30#include <qwt_legend_label.h>
50 qRegisterMetaType<std::map<std::string, VariantPtr>>(
"std::map<std::string, VariantPtr>");
52 widget->setMinimumHeight(150);
59 (void)
new QwtPlotPanner(
plotter->canvas());
62 QwtPlotMagnifier* magnifier =
new QwtPlotMagnifier(
plotter->canvas());
63 magnifier->setAxisEnabled(QwtPlot::xBottom,
false);
65 dynamic_cast<QwtPlotCanvas&
>(*
plotter->canvas())
66 .setPaintAttribute(QwtPlotCanvas::BackingStore,
69 QwtLegend* legend =
new QwtLegend;
70 legend->setDefaultItemMode(QwtLegendData::Mode::Checkable);
71 plotter->insertLegend(legend, QwtPlot::BottomLegend);
74 plotter->setAxisTitle(QwtPlot::xBottom,
"Time (in sec)");
75 plotter->enableAxis(QwtPlot::yLeft,
false);
77 plotter->enableAxis(QwtPlot::yRight,
true);
78 plotter->setAxisAutoScale(QwtPlot::yRight,
true);
85 SIGNAL(checked(
const QVariant&,
bool,
int)),
93 QWidget* barsWidget =
new QWidget();
95 barsWidget->setAccessibleName(
"barsWidget");
139 for (
auto& markerChannel :
markers)
141 for (
auto it = markerChannel.second.begin(); it != markerChannel.second.end();)
145 for (
auto elem : it->second)
147 elem.second->detach();
149 it = markerChannel.second.erase(it);
158 GraphDataMap::iterator it =
dataMap.begin();
160 auto addMarker = [
this](IceUtil::Time& age,
VariantPtr& var, std::string& datafieldId)
162 std::map<std::string, QwtPlotMarkerPtr>& markerSubMap =
markers[datafieldId][age];
164 std::string value = var->getString();
165 auto it2 = markerSubMap.find(value);
166 if (it2 != markerSubMap.end())
169 marker->setXValue(0.001 * age.toMilliSecondsDouble());
174 marker->setValue(0.001 * age.toMilliSecondsDouble(), 0);
175 marker->setLabel(QwtText(QString::fromStdString(value)));
176 marker->setLineStyle(QwtPlotMarker::VLine);
177 marker->setLabelAlignment(Qt::AlignBottom | Qt::AlignLeft);
179 for (
auto& markerSubMap :
markers)
181 if (markerSubMap.first == datafieldId)
187 marker->setLinePen(QColor(Qt::GlobalColor((i) % 5 + 13)));
189 markerSubMap[value] = marker;
193 for (; it !=
dataMap.end(); ++it)
196 QVector<QPointF> pointList;
198 auto datafieldId = it->first;
199 std::vector<TimeData>& dataVec = it->second;
201 pointList.reserve(dataVec.size());
208 for (
int i = dataVec.size() - 1; i >= 0; --i)
211 IceUtil::Time age = (
data.time - curTime);
217 if (var->getInitialized())
219 float xValue = 0.001 * age.toMilliSecondsDouble();
220 auto type = var->getType();
223 var->getFloat() != std::numeric_limits<float>::infinity())
225 yValue = (var->getFloat());
228 var->getDouble() != std::numeric_limits<double>::infinity())
230 yValue = (var->getDouble());
233 var->getInt() != std::numeric_limits<int>::infinity())
235 yValue = (var->getInt());
238 var->getLong() != std::numeric_limits<long>::infinity())
240 yValue =
static_cast<double>(var->getLong());
244 yValue = (var->getBool() ? 1 : -1);
248 addMarker(age, var, datafieldId);
255 pointList.push_back(QPointF(xValue, yValue));
262 <<
"uninitialized field: " << it->first;
276 QwtSeriesData<QPointF>* pointSeries =
new QwtPointSeriesData(pointList);
278 if (pointList.size() > 0 &&
curves.find(it->first) !=
curves.end() &&
281 QwtPlotCurve* curve =
curves[it->first];
282 curve->setData(pointSeries);
283 curve->setYAxis(QwtPlot::yRight);
284 QwtThermo* bar =
bars[it->first];
285 bar->setValue(pointList.first().y());
286 float range = curve->maxYValue() - curve->minYValue();
287 bar->setLowerBound(curve->minYValue() - 0.05 * range);
288 bar->setUpperBound((curve->maxYValue()) + range * 0.05);
302 item->setVisible(on);
303 QwtLegend* lgd = qobject_cast<QwtLegend*>(
plotter->legend());
305 QList<QWidget*> legendWidgets = lgd->legendWidgets(
plotter->itemToInfo(item));
307 if (legendWidgets.size() == 1)
309 QwtLegendLabel* legendLabel = qobject_cast<QwtLegendLabel*>(legendWidgets[0]);
313 legendLabel->setChecked(on);
322 ARMARX_WARNING <<
"found " << legendWidgets.size() <<
" items for the given curve";
332 plotter->setAxisAutoScale(QwtPlot::yRight, toggled);
359 std::map<std::string, VariantPtr>
362 using clock_t = std::chrono::high_resolution_clock;
363 const auto now = [] {
return clock_t::now(); };
364 const auto dt_ms = [](
auto t0,
auto t1) ->
float
365 {
return std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count() / 1e6f; };
371 std::map<std::string, DataFieldIdentifierBaseList> channelsSplittedByObserver;
372 for (QString
const& channel :
channels)
375 channelsSplittedByObserver[identifier->getObserverName()].push_back(identifier);
378 std::map<std::string, VariantPtr> newData;
379 const auto time_clear_start = now();
385 GraphDataMap::iterator itmap =
dataMap.begin();
387 for (; itmap !=
dataMap.end(); ++itmap)
389 std::vector<TimeData>& dataVec = itmap->second;
390 int stepSize = std::max<int>(1, dataVec.size() * 0.01);
391 int thresholdIndex = -1;
393 for (
unsigned int i = 0; i < dataVec.size(); i += stepSize)
399 if ((now - dataVec[i].time).toSecondsDouble() >
shownInterval * 2 ||
400 (thresholdIndex != -1 &&
411 if (thresholdIndex != -1)
413 unsigned int offset = std::min((
int)dataVec.size(), thresholdIndex);
416 if (offset > dataVec.size())
422 dataVec.erase(dataVec.begin(), dataVec.begin() + offset);
429 const auto time_clear_end = now();
433 std::map<std::string, DataFieldIdentifierBaseList>::iterator it =
434 channelsSplittedByObserver.begin();
435 const auto time_get_data_start = now();
436 float time_get_data_get_variants = 0;
437 float time_get_data_find_obs = 0;
438 float time_get_data_lock = 0;
439 float time_get_data_process = 0;
440 std::map<std::string, float> time_get_data_get_variants_per_obs;
443 for (; it != channelsSplittedByObserver.end(); ++it)
445 const std::string& observerName = it->first;
447 const auto time_get_data_find_obs_start = now();
453 time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
456 iceManager->getProxy<ObserverInterfacePrx>(observerName);
458 time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
461 const auto time_get_data_get_variants_start = now();
462 TimedVariantBaseList variants =
proxyMap[observerName]->getDataFields(it->second);
463 const auto time_get_data_get_variants_dt =
464 dt_ms(time_get_data_get_variants_start, now());
465 time_get_data_get_variants_per_obs[observerName] = time_get_data_get_variants_dt;
466 time_get_data_get_variants += time_get_data_get_variants_dt;
468 const auto time_get_data_lock_start = now();
470 time_get_data_lock += dt_ms(time_get_data_lock_start, now());
472 const auto time_get_data_process_start = now();
473 for (
unsigned int i = 0; i < variants.size(); ++i)
476 VariantPtr var = VariantPtr::dynamicCast(variants[i]);
478 DataFieldIdentifierPtr::dynamicCast(it->second[i])->getIdentifierStr();
479 if (!var->getInitialized())
484 auto type = var->getType();
488 dataMap[
id].rbegin()->
data->getString() != var->getString())
520 for (
const auto& e : dict)
527 std::string key =
id +
"." + e.first;
529 VariantPtr var = VariantPtr::dynamicCast(e.second);
530 auto type = var->getType();
549 time_get_data_process += dt_ms(time_get_data_process_start, now());
552 catch (Ice::NotRegisteredException& e)
555 <<
"Caught Ice::NotRegisteredException: " << e.what();
565 catch (armarx::UserException& e)
568 <<
"\nReason: " << e.reason;
574 const auto time_get_data_end = now();
577 const auto dt_get_data = dt_ms(time_get_data_start, time_get_data_end);
578 const auto dt_clear = dt_ms(time_clear_start, time_clear_end);
579 out <<
"timings PlotterController::getData"
580 <<
"\ndt_clear " << dt_clear <<
" ms"
581 <<
"\ndt_get_data " << dt_get_data <<
" ms"
582 <<
"\n time_get_data_find_obs " << time_get_data_find_obs <<
" ms"
583 <<
"\n time_get_data_get_variants " << time_get_data_get_variants <<
" ms";
584 for (
const auto& [k, v] : time_get_data_get_variants_per_obs)
586 out <<
"\n " << k <<
"\t" << v;
588 out <<
"\n time_get_data_lock " << time_get_data_lock <<
" ms"
589 <<
"\n time_get_data_process " << time_get_data_process <<
" ms";
598 if (samplingIntervalMs < 0)
605 std::map<std::string, TimedVariantBaseList> histories;
618 auto prx =
iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
622 auto id = identifier->getIdentifierStr();
623 auto historiesIt = histories.find(
id);
625 if (historiesIt == histories.end())
627 auto start = IceUtil::Time::now();
628 histories[id] = prx->getPartialDatafieldHistory(
629 identifier->channelName,
630 identifier->datafieldName,
631 (now - IceUtil::Time::seconds(
shownInterval)).toMicroSeconds(),
632 now.toMicroSeconds(),
635 << (IceUtil::Time::now() - start).toMilliSecondsDouble()
636 <<
" got " << histories[identifier->channelName].size()
638 historiesIt = histories.find(
id);
641 long lastTimestamp = 0;
643 VariantPtr var = VariantPtr::dynamicCast(prx->getDataField(identifier));
644 auto type = var->getType();
657 for (TimedVariantBasePtr& entry : historiesIt->second)
662 TimeData(IceUtil::Time::microSeconds(entry->getTimestamp()),
663 VariantPtr::dynamicCast(entry)));
664 lastTimestamp = entry->getTimestamp();
670 auto id = identifier->getIdentifierStr();
686 std::string key =
id +
"." + e.first;
687 ARMARX_VERBOSE << key <<
": " << *VariantPtr::dynamicCast(e.second);
688 QwtPlotCurve* curve =
createCurve(QString::fromStdString(key));
691 QwtThermo* bar =
createBar(QString::fromStdString(key));
695 for (
auto& entry : historiesIt->second)
700 for (
const auto& e : dict)
707 std::string key =
id +
"." + e.first;
709 VariantPtr var = VariantPtr::dynamicCast(e.second);
710 auto type = var->getType();
724 IceUtil::Time::microSeconds(entry->getTimestamp()),
761 QwtPlotItem* plotItem =
plotter->infoToItem(itemInfo);
775 QwtPlotCurve* curve =
new QwtPlotCurve(label);
776 curve->setRenderHint(QwtPlotItem::RenderAntialiased);
778 curve->setStyle(QwtPlotCurve::Lines);
780 curve->setPaintAttribute(QwtPlotCurve::ClipPolygons,
true);
794 QwtThermo* bar =
new QwtThermo(this->
widget);
795 bar->setAccessibleName(label);
796 bar->setFillBrush(QBrush(QColor(Qt::GlobalColor((
bars.size() + 7) % 15))));
798 "* { background-color: rgb(240, 240, 240); }");
800 QTextEdit* lab =
new QTextEdit(label, this->
widget);
801 lab->setStyleSheet(
"* { background-color: rgb(240, 240, 240); }");
802 lab->setLineWrapMode(QTextEdit::WidgetWidth);
803 lab->setTextInteractionFlags(
nullptr);
804 lab->setFrameStyle(0);
805 int linecount = lab->document()->blockCount();
806 lab->setMaximumHeight(70 * linecount);
807 lab->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
808 QVBoxLayout* layout =
new QVBoxLayout();
809 layout->addWidget(bar);
810 layout->addWidget(lab);
812 QWidget*
widget =
new QWidget(layout->widget());
813 widget->setLayout(layout);
826 std::vector<std::string>
830 std::vector<std::string> keys;
840 ObserverInterfacePrx observer =
841 iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
843 VariantPtr var = VariantPtr::dynamicCast(observer->getDataField(identifier));
857 if (e.first ==
"timestamp")
866 keys.push_back(identifier->getIdentifierStr() +
"." + e.first);
934 int containedItems =
barlayout->count() - 1;
937 int i = containedItems; i >= 0;
942 child->widget()->deleteLater();
1004 if (style ==
"Bar chart")
1011 QwtPlotCurve::CurveStyle st = QwtPlotCurve::Lines;
1012 if (style ==
"Curve (line, steps)")
1014 st = QwtPlotCurve::Steps;
1016 else if (style ==
"Curve (dots)")
1018 st = QwtPlotCurve::Dots;
1020 for (
const auto& [_, curve] :
curves)
1022 curve->setStyle(st);
1029 std::vector<Qt::GlobalColor>
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
#define ARMARX_STREAM_PRINTER
use this macro to write output code that is executed when printed and thus not executed if the debug ...
DataFieldIdentifier provide the basis to identify data field within a distributed ArmarX scenario.
The JSONObject class is used to represent and (de)serialize JSON objects.
static StringVariantBaseMap ConvertToBasicVariantMap(const JSONObjectPtr &serializer, const VariantBasePtr &variant)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
std::map< std::string, QwtThermo * > bars
bool getAutoScale() const
void setUpdateInterval(int value)
QStackedLayout * stackedLayout
std::map< std::string, VariantPtr > getData(const QStringList &channels)
void autoScale(bool toggled)
QPointer< QWidget > widget
void plottingPaused(bool toggled)
void newDataAvailable(long timestamp, const std::map< std::string, VariantPtr > &newData)
QStringList selectedDatafields
QwtPlotCurve * createCurve(const QString &label)
QStringList getSelectedDatafields() const
void setIceManager(const IceManagerPtr &value)
PlotterController(QObject *parent)
void setGraphStyle(const std::string &style)
QPointer< QwtPlot > plotter
std::recursive_mutex dataMutex
PeriodicTask< PlotterController >::pointer_type pollingTask
int getUpdateInterval() const
QwtThermo * createBar(const QString &label)
int getShownInterval() const
void setPollingInterval(int value)
void setShownInterval(int value)
void legendChecked(const QVariant &itemInfo, bool on)
Required for Qt5.
std::map< std::string, std::map< IceUtil::Time, std::map< std::string, QwtPlotMarkerPtr > > > markers
void setSelectedDatafields(const QStringList &value, int samplingIntervalMs=-1)
Changes the datafields that are plotted.
void setupCurves(int samplingIntervalMs=-1)
int getPollingInterval() const
void setAutoScale(bool value)
std::map< std::string, QwtPlotCurve * > curves
std::string getGraphStyle() const
std::vector< std::string > getSelectedDatafieldsKeys() const
std::vector< Qt::GlobalColor > curveColors
void showCurve(QwtPlotItem *item, bool on)
QWidget * getPlotterWidget()
~PlotterController() override
std::vector< Qt::GlobalColor > getCurveColors() const
void setCurveColors(const std::vector< Qt::GlobalColor > &value)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
#define ARMARX_CHECK_GREATER(lhs, rhs)
This macro evaluates whether lhs is greater (>) than rhs and if it turns out to be false it will thro...
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_LOG_S
This macro creates a new temporary instance which can then be used to log data using the << operator.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
const VariantTypeId String
bool IsBasicType(VariantTypeId id)
const VariantTypeId Double
const VariantTypeId Float
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::string GetHandledExceptionString()
QwtPlotMarker * QwtPlotMarkerPtr
IceInternal::Handle< Variant > VariantPtr
const LogSender::manipulator flush
IceUtil::Handle< IceManager > IceManagerPtr
IceManager smart pointer.
IceInternal::Handle< DataFieldIdentifier > DataFieldIdentifierPtr
Typedef of DataFieldIdentifierPtr as IceInternal::Handle<DataFieldIdentifier> for convenience.
bool isfinite(const std::vector< T, Ts... > &v)