30 #include <qwt_legend_label.h>
38 plotter(new QwtPlot())
53 qRegisterMetaType<std::map<std::string, VariantPtr>>(
"std::map<std::string, VariantPtr>");
55 widget->setMinimumHeight(150);
62 (void)
new QwtPlotPanner(
plotter->canvas());
65 QwtPlotMagnifier* magnifier =
new QwtPlotMagnifier(
plotter->canvas());
66 magnifier->setAxisEnabled(QwtPlot::xBottom,
false);
68 dynamic_cast<QwtPlotCanvas&
>(*
plotter->canvas()).setPaintAttribute(QwtPlotCanvas::BackingStore,
false);
70 QwtLegend* legend =
new QwtLegend;
71 legend->setDefaultItemMode(QwtLegendData::Mode::Checkable);
72 plotter->insertLegend(legend, QwtPlot::BottomLegend);
75 plotter->setAxisTitle(QwtPlot::xBottom,
"Time (in sec)");
76 plotter->enableAxis(QwtPlot::yLeft,
false);
78 plotter->enableAxis(QwtPlot::yRight,
true);
79 plotter->setAxisAutoScale(QwtPlot::yRight,
true);
85 connect(legend, SIGNAL(checked(
const QVariant&,
bool,
int)),
93 QWidget* barsWidget =
new QWidget();
95 barsWidget->setAccessibleName(
"barsWidget");
136 for (
auto& markerChannel :
markers)
138 for (
auto it = markerChannel.second.begin(); it != markerChannel.second.end();)
142 for (
auto elem : it->second)
144 elem.second->detach();
146 it = markerChannel.second.erase(it);
155 GraphDataMap::iterator it =
dataMap.begin();
159 std::map < std::string, QwtPlotMarkerPtr>& markerSubMap =
markers[datafieldId][age];
161 std::string
value = var->getString();
162 auto it2 = markerSubMap.find(
value);
163 if (it2 != markerSubMap.end())
166 marker->setXValue(0.001 * age.toMilliSecondsDouble());
171 marker->setValue(0.001 * age.toMilliSecondsDouble(), 0);
172 marker->setLabel(QwtText(QString::fromStdString(
value)));
173 marker->setLineStyle(QwtPlotMarker::VLine);
174 marker->setLabelAlignment(Qt::AlignBottom | Qt::AlignLeft);
176 for (
auto& markerSubMap :
markers)
178 if (markerSubMap.first == datafieldId)
184 marker->setLinePen(QColor(Qt::GlobalColor((i) % 5 + 13)));
186 markerSubMap[
value] = marker;
191 for (; it !=
dataMap.end(); ++it)
194 QVector<QPointF> pointList;
196 auto datafieldId = it->first;
197 std::vector<TimeData>& dataVec = it->second;
199 pointList.reserve(dataVec.size());
206 for (
int i = dataVec.size() - 1; i >= 0 ; --i)
215 if (var->getInitialized())
217 float xValue = 0.001 * age.toMilliSecondsDouble();
218 auto type = var->getType();
220 if (type ==
VariantType::Float && var->getFloat() != std::numeric_limits<float>::infinity())
222 yValue = (var->getFloat());
224 else if (type ==
VariantType::Double && var->getDouble() != std::numeric_limits<double>::infinity())
226 yValue = (var->getDouble());
228 else if (type ==
VariantType::Int && var->getInt() != std::numeric_limits<int>::infinity())
230 yValue = (var->getInt());
232 else if (type ==
VariantType::Long && var->getLong() != std::numeric_limits<long>::infinity())
234 yValue =
static_cast<double>(var->getLong());
238 yValue = (var->getBool() ? 1 : -1);
242 addMarker(age, var, datafieldId);
249 pointList.push_back(QPointF(xValue, yValue));
270 QwtSeriesData<QPointF>* pointSeries =
new QwtPointSeriesData(pointList);
272 if (pointList.size() > 0 &&
curves.find(it->first) !=
curves.end() &&
bars.find(it->first) !=
bars.end())
274 QwtPlotCurve* curve =
curves[it->first];
275 curve->setData(pointSeries);
276 curve->setYAxis(QwtPlot::yRight);
277 QwtThermo* bar =
bars[it->first];
278 bar->setValue(pointList.first().y());
279 float range = curve->maxYValue() - curve->minYValue();
280 bar->setLowerBound(curve->minYValue() - 0.05 * range);
281 bar->setUpperBound((curve->maxYValue()) + range * 0.05);
294 item->setVisible(on);
295 QwtLegend* lgd = qobject_cast<QwtLegend*>(
plotter->legend());
297 QList<QWidget*> legendWidgets =
298 lgd->legendWidgets(
plotter->itemToInfo(item));
300 if (legendWidgets.size() == 1)
302 QwtLegendLabel* legendLabel =
303 qobject_cast<QwtLegendLabel*>(legendWidgets[0]);
307 legendLabel->setChecked(on);
316 ARMARX_WARNING <<
"found " << legendWidgets.size() <<
" items for the given curve";
325 plotter->setAxisAutoScale(QwtPlot::yRight, toggled);
353 using clock_t = std::chrono::high_resolution_clock;
354 const auto now = [] {
return clock_t::now();};
355 const auto dt_ms = [](
auto t0,
auto t1) ->
float
357 return std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count() / 1e6f;
364 std::map< std::string, DataFieldIdentifierBaseList > channelsSplittedByObserver;
365 for (QString
const& channel : channels)
368 channelsSplittedByObserver[identifier->getObserverName()].push_back(identifier);
371 std::map<std::string, VariantPtr> newData;
372 const auto time_clear_start = now();
378 GraphDataMap::iterator itmap =
dataMap.begin();
380 for (; itmap !=
dataMap.end(); ++itmap)
382 std::vector<TimeData>& dataVec = itmap->second;
383 int stepSize = std::max<int>(1, dataVec.size() * 0.01);
384 int thresholdIndex = -1;
386 for (
unsigned int i = 0; i < dataVec.size(); i += stepSize)
392 if ((now - dataVec[i].time).toSecondsDouble() >
shownInterval * 2
393 || (thresholdIndex != -1 && (now - dataVec[i].time).toSecondsDouble() >
shownInterval)
404 if (thresholdIndex != -1)
406 unsigned int offset =
std::min((
int)dataVec.size(), thresholdIndex);
409 if (offset > dataVec.size())
415 dataVec.erase(dataVec.begin(), dataVec.begin() + offset);
422 const auto time_clear_end = now();
426 std::map<std::string, DataFieldIdentifierBaseList >::iterator it = channelsSplittedByObserver.begin();
427 const auto time_get_data_start = now();
428 float time_get_data_get_variants = 0;
429 float time_get_data_find_obs = 0;
430 float time_get_data_lock = 0;
431 float time_get_data_process = 0;
432 std::map<std::string, float> time_get_data_get_variants_per_obs;
435 for (; it != channelsSplittedByObserver.end(); ++it)
437 const std::string& observerName = it->first;
439 const auto time_get_data_find_obs_start = now();
445 time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
449 time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
452 const auto time_get_data_get_variants_start = now();
453 TimedVariantBaseList variants =
proxyMap[observerName]->getDataFields(it->second);
454 const auto time_get_data_get_variants_dt = dt_ms(time_get_data_get_variants_start, now());
455 time_get_data_get_variants_per_obs[observerName] = time_get_data_get_variants_dt;
456 time_get_data_get_variants += time_get_data_get_variants_dt;
458 const auto time_get_data_lock_start = now();
460 time_get_data_lock += dt_ms(time_get_data_lock_start, now());
462 const auto time_get_data_process_start = now();
463 for (
unsigned int i = 0; i < variants.size(); ++i)
466 VariantPtr var = VariantPtr::dynamicCast(variants[i]);
467 std::string
id = DataFieldIdentifierPtr::dynamicCast(it->second[i])->getIdentifierStr();
468 if (!var->getInitialized())
473 auto type = var->getType();
476 if (
dataMap[
id].size() == 0 ||
dataMap[
id].rbegin()->
data->getString() != var->getString())
508 for (
const auto& e : dict)
510 if (e.first ==
"timestamp")
514 std::string key =
id +
"." + e.first;
516 VariantPtr var = VariantPtr::dynamicCast(e.second);
517 auto type = var->getType();
536 time_get_data_process += dt_ms(time_get_data_process_start, now());
539 catch (Ice::NotRegisteredException& e)
551 catch (armarx::UserException& e)
559 const auto time_get_data_end = now();
562 const auto dt_get_data = dt_ms(time_get_data_start, time_get_data_end);
563 const auto dt_clear = dt_ms(time_clear_start, time_clear_end);
564 out <<
"timings PlotterController::getData"
565 <<
"\ndt_clear " << dt_clear <<
" ms"
566 <<
"\ndt_get_data " << dt_get_data <<
" ms"
567 <<
"\n time_get_data_find_obs " << time_get_data_find_obs <<
" ms"
568 <<
"\n time_get_data_get_variants " << time_get_data_get_variants <<
" ms";
569 for (
const auto& [k,
v] : time_get_data_get_variants_per_obs)
571 out <<
"\n " << k <<
"\t" <<
v;
573 out <<
"\n time_get_data_lock " << time_get_data_lock <<
" ms"
574 <<
"\n time_get_data_process " << time_get_data_process <<
" ms";
582 if (samplingIntervalMs < 0)
589 std::map<std::string, TimedVariantBaseList> histories;
600 auto prx =
iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
604 auto id = identifier->getIdentifierStr();
605 auto historiesIt = histories.find(
id);
607 if (historiesIt == histories.end())
609 auto start = IceUtil::Time::now();
610 histories[id] = prx->getPartialDatafieldHistory(identifier->channelName, identifier->datafieldName,
611 (now - IceUtil::Time::seconds(
shownInterval)).toMicroSeconds(), now.toMicroSeconds(), samplingIntervalMs);
612 ARMARX_DEBUG <<
"history data polling took : " << (IceUtil::Time::now() - start).toMilliSecondsDouble() <<
" got " << histories[identifier->channelName].size() <<
" entries";
613 historiesIt = histories.find(
id);
616 long lastTimestamp = 0;
618 VariantPtr var = VariantPtr::dynamicCast(prx->getDataField(identifier));
619 auto type = var->getType();
632 for (TimedVariantBasePtr& entry : historiesIt->second)
634 if (lastTimestamp + pollingInterval < entry->getTimestamp())
636 dataMap[id].push_back(
TimeData(IceUtil::Time::microSeconds(entry->getTimestamp()), VariantPtr::dynamicCast(entry)));
637 lastTimestamp = entry->getTimestamp();
643 auto id = identifier->getIdentifierStr();
649 if (e.first ==
"timestamp")
660 std::string key =
id +
"." + e.first;
661 ARMARX_VERBOSE << key <<
": " << *VariantPtr::dynamicCast(e.second);
662 QwtPlotCurve* curve =
createCurve(QString::fromStdString(key));
665 QwtThermo* bar =
createBar(QString::fromStdString(key));
669 for (
auto& entry : historiesIt->second)
671 if (lastTimestamp + pollingInterval < entry->getTimestamp())
674 for (
const auto& e : dict)
676 if (e.first ==
"timestamp")
680 std::string key =
id +
"." + e.first;
682 VariantPtr var = VariantPtr::dynamicCast(e.second);
683 auto type = var->getType();
696 dataMap[key].push_back(
TimeData(IceUtil::Time::microSeconds(entry->getTimestamp()), var));
730 QwtPlotItem* plotItem =
plotter->infoToItem(itemInfo);
743 QwtPlotCurve* curve =
new QwtPlotCurve(label);
744 curve->setRenderHint(QwtPlotItem::RenderAntialiased);
746 curve->setStyle(QwtPlotCurve::Lines);
748 curve->setPaintAttribute(QwtPlotCurve::ClipPolygons,
true);
761 QwtThermo* bar =
new QwtThermo(this->
widget);
762 bar->setAccessibleName(label);
763 bar->setFillBrush(QBrush(QColor(Qt::GlobalColor((
bars.size() + 7) % 15))));
764 bar->setStyleSheet(
"* { background-color: rgb(240, 240, 240); }");
766 QTextEdit* lab =
new QTextEdit(label, this->
widget);
767 lab->setStyleSheet(
"* { background-color: rgb(240, 240, 240); }");
768 lab->setLineWrapMode(QTextEdit::WidgetWidth);
769 lab->setTextInteractionFlags(
nullptr);
770 lab->setFrameStyle(0);
771 int linecount = lab->document()->blockCount();
772 lab->setMaximumHeight(70 * linecount);
773 lab->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
774 QVBoxLayout* layout =
new QVBoxLayout();
775 layout->addWidget(bar);
776 layout->addWidget(lab);
778 QWidget*
widget =
new QWidget(layout->widget());
779 widget->setLayout(layout);
796 std::vector<std::string> keys;
805 ObserverInterfacePrx observer =
iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
807 VariantPtr var = VariantPtr::dynamicCast(observer->getDataField(identifier));
821 if (e.first ==
"timestamp")
832 keys.push_back(identifier->getIdentifierStr() +
"." + e.first);
897 int containedItems =
barlayout->count() - 1;
899 for (
int i = containedItems; i >= 0 ; i--)
903 child->widget()->deleteLater();
959 if (style ==
"Bar chart")
966 QwtPlotCurve::CurveStyle st = QwtPlotCurve::Lines;
967 if (style ==
"Curve (line, steps)")
969 st = QwtPlotCurve::Steps;
971 else if (style ==
"Curve (dots)")
973 st = QwtPlotCurve::Dots;
975 for (
const auto& [_, curve] :
curves)