PlotterController.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package ArmarX
19  * @author Mirko Waechter( mirko.waechter at kit dot edu)
20  * @date 2016
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 #include "PlotterController.h"
26 
27 #include <chrono>
28 #include <cmath>
29 
30 #include <qwt_legend_label.h>
31 
33 
34 namespace armarx
35 {
36  PlotterController::PlotterController(QObject* parent) : QObject(parent), plotter(new QwtPlot())
37  {
38 
40  Qt::green,
41  Qt::blue,
42  Qt::cyan,
43  Qt::magenta,
44  Qt::darkRed,
45  Qt::darkGreen,
46  Qt::darkBlue,
47  Qt::darkCyan,
48  Qt::darkMagenta};
49 
50  qRegisterMetaType<std::map<std::string, VariantPtr>>("std::map<std::string, VariantPtr>");
51  widget = new QWidget();
52  widget->setMinimumHeight(150);
53  // widget->setMaximumWidth(600);
54  // widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding));
55  ////////////////
56  // Setup Plotter
57  ///////////////
58  // panning with the left mouse button
59  (void)new QwtPlotPanner(plotter->canvas());
60 
61  // zoom in/out with the wheel
62  QwtPlotMagnifier* magnifier = new QwtPlotMagnifier(plotter->canvas());
63  magnifier->setAxisEnabled(QwtPlot::xBottom, false);
64 
65  dynamic_cast<QwtPlotCanvas&>(*plotter->canvas())
66  .setPaintAttribute(QwtPlotCanvas::BackingStore,
67  false); //increases performance for incremental drawing
68 
69  QwtLegend* legend = new QwtLegend;
70  legend->setDefaultItemMode(QwtLegendData::Mode::Checkable);
71  plotter->insertLegend(legend, QwtPlot::BottomLegend);
72 
73 
74  plotter->setAxisTitle(QwtPlot::xBottom, "Time (in sec)");
75  plotter->enableAxis(QwtPlot::yLeft, false);
76 
77  plotter->enableAxis(QwtPlot::yRight, true);
78  plotter->setAxisAutoScale(QwtPlot::yRight, true);
79  // plotter->setAutoReplot();
80 
81 
82  // plotter->setCanvasBackground(* new QBrush(Qt::white));
83 
84  connect(legend,
85  SIGNAL(checked(const QVariant&, bool, int)),
86  SLOT(legendChecked(const QVariant&, bool)));
87 
88  connect(&timer, SIGNAL(timeout()), this, SLOT(updateGraph()));
89  stackedLayout = new QStackedLayout(widget);
90  stackedLayout->addWidget(plotter);
91 
92  barlayout = new QHBoxLayout;
93  QWidget* barsWidget = new QWidget();
94  barsWidget->setLayout(barlayout);
95  barsWidget->setAccessibleName("barsWidget");
96  stackedLayout->addWidget(barsWidget);
97  }
98 
100  {
101  ARMARX_DEBUG << "~PlotterController";
102  if (!widget.isNull())
103  {
104  widget->deleteLater();
105  }
106  timer.stop();
107  if (pollingTask)
108  {
109  pollingTask->stop();
110  }
111  }
112 
113  QWidget*
115  {
116  return widget;
117  }
118 
119  void
121  {
122  std::map<std::string, VariantPtr> newData = getData(selectedDatafields);
123 
124 
125  emit newDataAvailable(TimeUtil::GetTime().toMicroSeconds(), newData);
126  }
127 
128  void
130  {
131  if (this->__plottingPaused)
132  {
133  return;
134  }
135  std::lock_guard lock(dataMutex);
136 
137  IceUtil::Time curTime = TimeUtil::GetTime();
138  // erase old markers
139  for (auto& markerChannel : markers)
140  {
141  for (auto it = markerChannel.second.begin(); it != markerChannel.second.end();)
142  {
143  if ((curTime - it->first).toSecondsDouble() > shownInterval)
144  {
145  for (auto elem : it->second)
146  {
147  elem.second->detach();
148  }
149  it = markerChannel.second.erase(it);
150  }
151  else
152  {
153  it++;
154  }
155  }
156  }
157 
158  GraphDataMap::iterator it = dataMap.begin();
159 
160  auto addMarker = [this](IceUtil::Time& age, VariantPtr& var, std::string& datafieldId)
161  {
162  std::map<std::string, QwtPlotMarkerPtr>& markerSubMap = markers[datafieldId][age];
163 
164  std::string value = var->getString();
165  auto it2 = markerSubMap.find(value);
166  if (it2 != markerSubMap.end())
167  {
168  QwtPlotMarkerPtr marker = it2->second;
169  marker->setXValue(0.001 * age.toMilliSecondsDouble());
170  }
171  else
172  {
173  QwtPlotMarkerPtr marker(new QwtPlotMarker());
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);
178  int i = 0;
179  for (auto& markerSubMap : markers)
180  {
181  if (markerSubMap.first == datafieldId)
182  {
183  break;
184  }
185  i++;
186  }
187  marker->setLinePen(QColor(Qt::GlobalColor((i) % 5 + 13)));
188  marker->attach(plotter);
189  markerSubMap[value] = marker;
190  }
191  };
192 
193  for (; it != dataMap.end(); ++it)
194  {
195 
196  QVector<QPointF> pointList;
197  pointList.clear();
198  auto datafieldId = it->first;
199  std::vector<TimeData>& dataVec = it->second;
200  // int newSize = min(size,(int)dataVec.size());
201  pointList.reserve(dataVec.size());
202 
203 
204  try
205  {
206  int j = 0;
207 
208  for (int i = dataVec.size() - 1; i >= 0; --i)
209  {
210  TimeData& data = dataVec[i];
211  IceUtil::Time age = (data.time - curTime);
212 
213  if (age.toSecondsDouble() <= shownInterval /*&& age.toMicroSeconds() > 0*/)
214  {
215  VariantPtr var = VariantPtr::dynamicCast(data.data);
216 
217  if (var->getInitialized())
218  {
219  float xValue = 0.001 * age.toMilliSecondsDouble();
220  auto type = var->getType();
221  double yValue = 0;
222  if (type == VariantType::Float &&
223  var->getFloat() != std::numeric_limits<float>::infinity())
224  {
225  yValue = (var->getFloat());
226  }
227  else if (type == VariantType::Double &&
228  var->getDouble() != std::numeric_limits<double>::infinity())
229  {
230  yValue = (var->getDouble());
231  }
232  else if (type == VariantType::Int &&
233  var->getInt() != std::numeric_limits<int>::infinity())
234  {
235  yValue = (var->getInt());
236  }
237  else if (type == VariantType::Long &&
238  var->getLong() != std::numeric_limits<long>::infinity())
239  {
240  yValue = static_cast<double>(var->getLong());
241  }
242  else if (type == VariantType::Bool)
243  {
244  yValue = (var->getBool() ? 1 : -1);
245  }
246  else if (type == VariantType::String)
247  {
248  addMarker(age, var, datafieldId);
249  }
250  else
251  {
252  continue;
253  }
254 
255  pointList.push_back(QPointF(xValue, yValue));
256 
257  j++;
258  }
259  else
260  {
262  << "uninitialized field: " << it->first;
263  }
264  }
265  else
266  {
267  break; // data too old from now
268  }
269  }
270  }
271  catch (...)
272  {
274  }
275 
276  QwtSeriesData<QPointF>* pointSeries = new QwtPointSeriesData(pointList);
277 
278  if (pointList.size() > 0 && curves.find(it->first) != curves.end() &&
279  bars.find(it->first) != bars.end())
280  {
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);
289  }
290  }
291 
292  plotter->setAxisAutoScale(QwtPlot::yRight, autoScalePlot);
293 
294  // plotter->setAxisScale( QwtPlot::yLeft, -1, 1);
295 
296  plotter->replot();
297  }
298 
299  void
300  PlotterController::showCurve(QwtPlotItem* item, bool on)
301  {
302  item->setVisible(on);
303  QwtLegend* lgd = qobject_cast<QwtLegend*>(plotter->legend());
304 
305  QList<QWidget*> legendWidgets = lgd->legendWidgets(plotter->itemToInfo(item));
306 
307  if (legendWidgets.size() == 1)
308  {
309  QwtLegendLabel* legendLabel = qobject_cast<QwtLegendLabel*>(legendWidgets[0]);
310 
311  if (legendLabel)
312  {
313  legendLabel->setChecked(on);
314  }
315  else
316  {
317  ARMARX_WARNING << "legendLabel is no QwtLegendLabel";
318  }
319  }
320  else
321  {
322  ARMARX_WARNING << "found " << legendWidgets.size() << " items for the given curve";
323  }
324  plotter->replot();
325  }
326 
327  void
329  {
330  ARMARX_VERBOSE << "clicked autoscale" << flush;
331 
332  plotter->setAxisAutoScale(QwtPlot::yRight, toggled);
333  plotter->replot();
334  autoScalePlot = toggled;
335  }
336 
337  void
339  {
340  __plottingPaused = toggled;
341 
342  // if (pollingTask)
343  // {
344  // pollingTask->stop();
345  // }
346 
347  if (__plottingPaused)
348  {
349  timer.stop();
350  }
351  else
352  {
353  // pollingTask = new PeriodicTask<PlotterController>(this, &PlotterController::pollingExec, pollingInterval, false, "DataPollingTask", false);
354  // pollingTask->start();
355  timer.start(updateInterval);
356  }
357  }
358 
359  std::map<std::string, VariantPtr>
360  PlotterController::getData(const QStringList& channels)
361  {
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; };
366  if (iceManager->isShutdown())
367  {
368  return {};
369  }
370  //create Data field ids from channel names
371  std::map<std::string, DataFieldIdentifierBaseList> channelsSplittedByObserver;
372  for (QString const& channel : channels)
373  {
374  DataFieldIdentifierPtr identifier = new DataFieldIdentifier(channel.toStdString());
375  channelsSplittedByObserver[identifier->getObserverName()].push_back(identifier);
376  // ARMARX_INFO << identifier;
377  }
378  std::map<std::string, VariantPtr> newData;
379  const auto time_clear_start = now();
380  {
381  std::lock_guard lock(dataMutex);
382 
383  // first clear to old entries
384  auto now = TimeUtil::GetTime();
385  GraphDataMap::iterator itmap = dataMap.begin();
386 
387  for (; itmap != dataMap.end(); ++itmap)
388  {
389  std::vector<TimeData>& dataVec = itmap->second;
390  int stepSize = std::max<int>(1, dataVec.size() * 0.01);
391  int thresholdIndex = -1;
392 
393  for (unsigned int i = 0; i < dataVec.size(); i += stepSize)
394  {
395  // only delete if entries are older than 2*showninterval
396  // and delete then all entries that are older than showninterval.
397  // otherwise it would delete items on every call, which would be very slow
398 
399  if ((now - dataVec[i].time).toSecondsDouble() > shownInterval * 2 ||
400  (thresholdIndex != -1 &&
401  (now - dataVec[i].time).toSecondsDouble() > shownInterval))
402  {
403  thresholdIndex = i;
404  }
405  else
406  {
407  break;
408  }
409  }
410 
411  if (thresholdIndex != -1)
412  {
413  unsigned int offset = std::min((int)dataVec.size(), thresholdIndex);
414 
415  // ARMARX_IMPORTANT << "Erasing " << offset << " fields";
416  if (offset > dataVec.size())
417  {
418  dataVec.clear();
419  }
420  else
421  {
422  dataVec.erase(dataVec.begin(), dataVec.begin() + offset);
423  }
424  }
425 
426  // ARMARX_IMPORTANT << deactivateSpam(5) << "size: " << dataVec.size();
427  }
428  }
429  const auto time_clear_end = now();
430 
431  // now get new data
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;
441  try
442  {
443  for (; it != channelsSplittedByObserver.end(); ++it)
444  {
445  const std::string& observerName = it->first;
446 
447  const auto time_get_data_find_obs_start = now();
448  if (proxyMap.find(observerName) == proxyMap.end())
449  {
450  if (!iceManager)
451  {
452  continue;
453  time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
454  }
455  proxyMap[observerName] =
456  iceManager->getProxy<ObserverInterfacePrx>(observerName);
457  }
458  time_get_data_find_obs += dt_ms(time_get_data_find_obs_start, now());
459 
460  // QDateTime time(QDateTime::currentDateTime());
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;
467 
468  const auto time_get_data_lock_start = now();
469  std::lock_guard lock(dataMutex);
470  time_get_data_lock += dt_ms(time_get_data_lock_start, now());
471  // # ARMARX_IMPORTANT << "data from observer: " << observerName;
472  const auto time_get_data_process_start = now();
473  for (unsigned int i = 0; i < variants.size(); ++i)
474  {
475  // ARMARX_IMPORTANT << "Variant: " << VariantPtr::dynamicCast(variants[i]);
476  VariantPtr var = VariantPtr::dynamicCast(variants[i]);
477  std::string id =
478  DataFieldIdentifierPtr::dynamicCast(it->second[i])->getIdentifierStr();
479  if (!var->getInitialized())
480  {
481  //dataMap[id] = {};
482  continue;
483  }
484  auto type = var->getType();
485  if (type == VariantType::String)
486  {
487  if (dataMap[id].size() == 0 ||
488  dataMap[id].rbegin()->data->getString() != var->getString())
489  {
490  // only insert if changed
491  dataMap[id].push_back(TimeData(time, var));
492  newData[id] = var;
493  }
494  }
495  else if (type == VariantType::Float)
496  {
497  if (std::isfinite(var->getFloat()))
498  {
499  dataMap[id].push_back(TimeData(time, var));
500  }
501  newData[id] = var;
502  }
503  else if (type == VariantType::Double)
504  {
505  if (std::isfinite(var->getDouble()))
506  {
507  dataMap[id].push_back(TimeData(time, var));
508  }
509  newData[id] = var;
510  }
511  else if (VariantType::IsBasicType(type))
512  {
513  dataMap[id].push_back(TimeData(time, var));
514  newData[id] = var;
515  }
516  else
517  {
518  auto dict = JSONObject::ConvertToBasicVariantMap(json, var);
519 
520  for (const auto& e : dict)
521  {
522  if (e.first ==
523  "timestamp") // TimedVariants always contain a timestamp field which is irrelevant
524  {
525  continue;
526  }
527  std::string key = id + "." + e.first;
528  // ARMARX_INFO << key << ": " << *VariantPtr::dynamicCast(e.second);
529  VariantPtr var = VariantPtr::dynamicCast(e.second);
530  auto type = var->getType();
531  if (type == VariantType::String)
532  {
533  // complex contain additional strings often, which cannot be selected right now -> disable strings from complex types
534  // if (dataMap[id].size() == 0 || dataMap[id].rbegin()->data->getString() != var->getString())
535  // {
536  // // only insert if changed
537  // dataMap[id].push_back(TimeData(time, var));
538  // newData[key] = var;
539  // }
540  }
541  else
542  {
543  dataMap[key].push_back(TimeData(time, var));
544  newData[key] = var;
545  }
546  }
547  }
548  }
549  time_get_data_process += dt_ms(time_get_data_process_start, now());
550  }
551  }
552  catch (Ice::NotRegisteredException& e)
553  {
555  << "Caught Ice::NotRegisteredException: " << e.what();
556  }
558  {
559  ARMARX_WARNING << deactivateSpam(5) << "Caught InvalidDataFieldException: " << e.what();
560  }
562  {
563  ARMARX_WARNING << deactivateSpam(5) << "Caught InvalidChannelException: " << e.what();
564  }
565  catch (armarx::UserException& e)
566  {
567  ARMARX_WARNING << deactivateSpam(5) << "Caught UserException: " << e.what()
568  << "\nReason: " << e.reason;
569  }
570  catch (...)
571  {
573  }
574  const auto time_get_data_end = now();
576  {
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)
585  {
586  out << "\n " << k << "\t" << v;
587  }
588  out << "\n time_get_data_lock " << time_get_data_lock << " ms"
589  << "\n time_get_data_process " << time_get_data_process << " ms";
590  };
591  return newData;
592  }
593 
594  void
595  PlotterController::setupCurves(int samplingIntervalMs)
596  {
597  {
598  if (samplingIntervalMs < 0)
599  {
600  samplingIntervalMs = pollingInterval;
601  }
602  std::lock_guard lock(dataMutex);
603  clear();
604  auto now = TimeUtil::GetTime();
605  std::map<std::string, TimedVariantBaseList> histories;
606  markers.clear();
607  // for(auto marker : markers)
608  // marker->detach();
609  plotter->detachItems();
610  for (int i = 0; i < selectedDatafields.size(); i++)
611  {
612  try
613  {
614  ARMARX_VERBOSE << "Channel: " << selectedDatafields.at(i).toStdString()
615  << flush;
616  DataFieldIdentifierPtr identifier =
617  new DataFieldIdentifier(selectedDatafields.at(i).toStdString());
618  auto prx = iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
619 
620 
621  // get past data of that datafield
622  auto id = identifier->getIdentifierStr();
623  auto historiesIt = histories.find(id);
624 
625  if (historiesIt == histories.end())
626  {
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(),
633  samplingIntervalMs);
634  ARMARX_DEBUG << "history data polling took : "
635  << (IceUtil::Time::now() - start).toMilliSecondsDouble()
636  << " got " << histories[identifier->channelName].size()
637  << " entries";
638  historiesIt = histories.find(id);
639  }
640 
641  long lastTimestamp = 0;
642 
643  VariantPtr var = VariantPtr::dynamicCast(prx->getDataField(identifier));
644  auto type = var->getType();
645  if (type == VariantType::String)
646  {
647  // do nothing for now
648  }
649  else if (VariantType::IsBasicType(type))
650  {
651  QwtPlotCurve* curve = createCurve(selectedDatafields.at(i));
652  curves[selectedDatafields.at(i).toStdString()] = curve;
653 
654  QwtThermo* bar = createBar(selectedDatafields.at(i));
655  bars[selectedDatafields.at(i).toStdString()] = bar;
656 
657  for (TimedVariantBasePtr& entry : historiesIt->second)
658  {
659  if (lastTimestamp + pollingInterval < entry->getTimestamp())
660  {
661  dataMap[id].push_back(
662  TimeData(IceUtil::Time::microSeconds(entry->getTimestamp()),
663  VariantPtr::dynamicCast(entry)));
664  lastTimestamp = entry->getTimestamp();
665  }
666  }
667  }
668  else
669  {
670  auto id = identifier->getIdentifierStr();
671  ARMARX_VERBOSE << id;
672  auto dict = JSONObject::ConvertToBasicVariantMap(json, var);
673 
674  for (auto e : dict)
675  {
676  if (e.first ==
677  "timestamp") // TimedVariants always contain a timestamp field which is irrelevant
678  {
679  continue;
680  }
681  VariantTypeId type = e.second->getType();
682 
683  if (type == VariantType::Double || type == VariantType::Float ||
684  type == VariantType::Int || type == VariantType::Long)
685  {
686  std::string key = id + "." + e.first;
687  ARMARX_VERBOSE << key << ": " << *VariantPtr::dynamicCast(e.second);
688  QwtPlotCurve* curve = createCurve(QString::fromStdString(key));
689  curves[key] = curve;
690 
691  QwtThermo* bar = createBar(QString::fromStdString(key));
692  bars[key] = bar;
693  }
694  }
695  for (auto& entry : historiesIt->second)
696  {
697  if (lastTimestamp + pollingInterval < entry->getTimestamp())
698  {
699  auto dict = JSONObject::ConvertToBasicVariantMap(json, entry);
700  for (const auto& e : dict)
701  {
702  if (e.first ==
703  "timestamp") // TimedVariants always contain a timestamp field which is irrelevant
704  {
705  continue;
706  }
707  std::string key = id + "." + e.first;
708  // ARMARX_INFO << key << ": " << *VariantPtr::dynamicCast(e.second);
709  VariantPtr var = VariantPtr::dynamicCast(e.second);
710  auto type = var->getType();
711  if (type == VariantType::String)
712  {
713  // complex contain additional strings often, which cannot be selected right now -> disable strings from complex types
714  // if (dataMap[id].size() == 0 || dataMap[id].rbegin()->data->getString() != var->getString())
715  // {
716  // // only insert if changed
717  // dataMap[id].push_back(TimeData(time, var));
718  // newData[key] = var;
719  // }
720  }
721  else
722  {
723  dataMap[key].push_back(TimeData(
724  IceUtil::Time::microSeconds(entry->getTimestamp()),
725  var));
726  }
727  }
728  }
729  }
730  }
731  }
732  catch (...)
733  {
735  }
736  }
737 
738  plotter->replot();
739  }
740  plotter->setAxisScale(QwtPlot::xBottom, shownInterval * -1, 0.f);
741 
742  timer.start(updateInterval);
743 
744  if (pollingTask)
745  {
746  pollingTask->stop();
747  }
748 
752  false,
753  "DataPollingTask",
754  false);
755  pollingTask->start();
756  }
757 
758  void
759  PlotterController::legendChecked(const QVariant& itemInfo, bool on)
760  {
761  QwtPlotItem* plotItem = plotter->infoToItem(itemInfo);
762  if (plotItem)
763  {
764  showCurve(plotItem, on);
765  }
766  else
767  {
768  ARMARX_WARNING << "nonexistent legend item toggled to " << on;
769  }
770  }
771 
772  QwtPlotCurve*
773  PlotterController::createCurve(const QString& label)
774  {
775  QwtPlotCurve* curve = new QwtPlotCurve(label);
776  curve->setRenderHint(QwtPlotItem::RenderAntialiased);
777  curve->setPen(QColor(curveColors.at(curves.size() % curveColors.size())));
778  curve->setStyle(QwtPlotCurve::Lines);
779 
780  curve->setPaintAttribute(QwtPlotCurve::ClipPolygons, true);
781 
782  curve->attach(plotter);
783  showCurve(curve, true);
784 
785  return curve;
786  }
787 
788  QwtThermo*
789  PlotterController::createBar(const QString& label)
790  {
791  //creates a widget containing a bar chart and a label
792  //with the fill color of chart same as its curve
793 
794  QwtThermo* bar = new QwtThermo(this->widget);
795  bar->setAccessibleName(label);
796  bar->setFillBrush(QBrush(QColor(Qt::GlobalColor((bars.size() + 7) % 15))));
797  bar->setStyleSheet(
798  "* { background-color: rgb(240, 240, 240); }"); //neccessary because white is a picked fill color
799 
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);
811 
812  QWidget* widget = new QWidget(layout->widget());
813  widget->setLayout(layout);
814  barlayout->addWidget(widget);
815 
816  return bar;
817  }
818 
819  QStringList
821  {
822  std::lock_guard lock(dataMutex);
823  return selectedDatafields;
824  }
825 
826  std::vector<std::string>
828  {
829 
830  std::vector<std::string> keys;
831 
832  std::lock_guard lock(dataMutex);
833 
834  for (int i = 0; i < selectedDatafields.size(); i++)
835  {
836  try
837  {
838  DataFieldIdentifierPtr identifier =
839  new DataFieldIdentifier(selectedDatafields.at(i).toStdString());
840  ObserverInterfacePrx observer =
841  iceManager->getProxy<ObserverInterfacePrx>(identifier->observerName);
842 
843  VariantPtr var = VariantPtr::dynamicCast(observer->getDataField(identifier));
844  VariantTypeId type = var->getType();
845  if (type == VariantType::String || VariantType::IsBasicType(type))
846  {
847  keys.push_back(selectedDatafields.at(i).toStdString());
848  }
849  else
850  {
851  // TODO auto load libraries see ObserverItemModel.cpp:108
852 
853  auto dict = JSONObject::ConvertToBasicVariantMap(json, var);
854  for (auto e : dict)
855  {
856  ARMARX_LOG_S << e.first;
857  if (e.first == "timestamp")
858  {
859  continue;
860  }
861  VariantTypeId type = e.second->getType();
862 
863  if (type == VariantType::Double || type == VariantType::Float ||
864  type == VariantType::Int || type == VariantType::Long)
865  {
866  keys.push_back(identifier->getIdentifierStr() + "." + e.first);
867  }
868  }
869  }
870  }
871  catch (...)
872  {
874  }
875  }
876  return keys;
877  }
878 
879  void
880  PlotterController::setSelectedDatafields(const QStringList& value, int samplingIntervalMs)
881  {
882  {
883  std::lock_guard lock(dataMutex);
884  if (selectedDatafields == value)
885  {
886  return;
887  }
889  }
890  setupCurves(samplingIntervalMs);
891  }
892 
893  int
895  {
896  return pollingInterval;
897  }
898 
899  void
901  {
903  if (pollingTask)
904  {
905  pollingTask->changeInterval(value);
906  }
907  }
908 
909  int
911  {
912  return updateInterval;
913  }
914 
915  void
917  {
919  timer.start(value);
920  }
921 
922  void
924  {
925  iceManager = value;
926  json = new JSONObject(iceManager->getCommunicator());
927  }
928 
929  void
931  {
932  //maybe comparing new and old selected list better than doing a new one every time?
933  QLayoutItem* child;
934  int containedItems = barlayout->count() - 1;
935 
936  for (
937  int i = containedItems; i >= 0;
938  i--) //must be done in this order due to internal implementation of layout item numbering
939  {
940  child = barlayout->itemAt(i);
941  barlayout->removeItem(child);
942  child->widget()->deleteLater();
943  }
944 
945  bars.clear();
946  }
947 
948  void
950  {
951  std::lock_guard g(dataMutex);
952  plotter->detachItems();
953  markers.clear();
954  curves.clear();
955  dataMap.clear();
956  clearBarList();
957  }
958 
959  void
961  {
962  std::lock_guard g(dataMutex);
963  dataMap.clear();
964  }
965 
966  int
968  {
969  return shownInterval;
970  }
971 
972  void
974  {
975  ARMARX_VERBOSE << "Setting shown interval to " << shownInterval;
977  plotter->setAxisScale(QwtPlot::xBottom, shownInterval * -1, 0.f);
978  }
979 
980  bool
982  {
983  return autoScalePlot;
984  }
985 
986  void
988  {
990  }
991 
992  std::string
994  {
995  return graphStyle;
996  }
997 
998  void
999  PlotterController::setGraphStyle(const std::string& style)
1000  {
1001  if (graphStyle != style)
1002  {
1003  graphStyle = style;
1004  if (style == "Bar chart")
1005  {
1006  stackedLayout->setCurrentIndex(1);
1007  }
1008  else
1009  {
1010  stackedLayout->setCurrentIndex(0);
1011  QwtPlotCurve::CurveStyle st = QwtPlotCurve::Lines;
1012  if (style == "Curve (line, steps)")
1013  {
1014  st = QwtPlotCurve::Steps;
1015  }
1016  else if (style == "Curve (dots)")
1017  {
1018  st = QwtPlotCurve::Dots;
1019  }
1020  for (const auto& [_, curve] : curves)
1021  {
1022  curve->setStyle(st);
1023  }
1024  plotter->replot();
1025  }
1026  }
1027  }
1028 
1029  std::vector<Qt::GlobalColor>
1031  {
1032  return curveColors;
1033  }
1034 
1035  void
1036  PlotterController::setCurveColors(const std::vector<Qt::GlobalColor>& value)
1037  {
1038  ARMARX_CHECK_GREATER(value.size(), 0);
1039  curveColors = value;
1040  }
1041 } // namespace armarx
armarx::PlotterController::setPollingInterval
void setPollingInterval(int value)
Definition: PlotterController.cpp:900
armarx::PlotterController::setIceManager
void setIceManager(const IceManagerPtr &value)
Definition: PlotterController.cpp:923
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::PlotterController::selectedDatafields
QStringList selectedDatafields
Definition: PlotterController.h:158
armarx::PlotterController::updateGraph
void updateGraph()
Definition: PlotterController.cpp:129
armarx::PlotterController::bars
std::map< std::string, QwtThermo * > bars
Definition: PlotterController.h:168
armarx::VariantType::Float
const VariantTypeId Float
Definition: Variant.h:919
armarx::PlotterController::proxyMap
ProxyMap proxyMap
Definition: PlotterController.h:165
armarx::PlotterController::widget
QPointer< QWidget > widget
Definition: PlotterController.h:156
armarx::PlotterController::dataMutex
std::recursive_mutex dataMutex
Definition: PlotterController.h:163
armarx::PlotterController::getPlotterWidget
QWidget * getPlotterWidget()
Definition: PlotterController.cpp:114
armarx::PlotterController::showCurve
void showCurve(QwtPlotItem *item, bool on)
Definition: PlotterController.cpp:300
armarx::PlotterController::setAutoScale
void setAutoScale(bool value)
Definition: PlotterController.cpp:987
armarx::JSONObject::ConvertToBasicVariantMap
static StringVariantBaseMap ConvertToBasicVariantMap(const JSONObjectPtr &serializer, const VariantBasePtr &variant)
Definition: JSONObject.cpp:561
armarx::PlotterController::pollingInterval
int pollingInterval
Definition: PlotterController.h:150
armarx::JSONObject
The JSONObject class is used to represent and (de)serialize JSON objects.
Definition: JSONObject.h:43
armarx::PlotterController::curveColors
std::vector< Qt::GlobalColor > curveColors
Definition: PlotterController.h:167
ARMARX_CHECK_GREATER
#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...
Definition: ExpressionException.h:116
armarx::PlotterController::timer
QTimer timer
Definition: PlotterController.h:162
armarx::PlotterController::newDataAvailable
void newDataAvailable(long timestamp, const std::map< std::string, VariantPtr > &newData)
armarx::PlotterController::updateInterval
int updateInterval
Definition: PlotterController.h:151
armarx::PlotterController::getPollingInterval
int getPollingInterval() const
Definition: PlotterController.cpp:894
armarx::PlotterController::createBar
QwtThermo * createBar(const QString &label)
Definition: PlotterController.cpp:789
armarx::VariantType::Bool
const VariantTypeId Bool
Definition: Variant.h:916
armarx::PlotterController::barlayout
QHBoxLayout * barlayout
Definition: PlotterController.h:173
armarx::PlotterController::json
JSONObjectPtr json
Definition: PlotterController.h:159
armarx::PlotterController::autoScale
void autoScale(bool toggled)
Definition: PlotterController.cpp:328
armarx::PlotterController::clearBarList
void clearBarList()
Definition: PlotterController.cpp:930
armarx::PlotterController::getAutoScale
bool getAutoScale() const
Definition: PlotterController.cpp:981
armarx::PlotterController::iceManager
IceManagerPtr iceManager
Definition: PlotterController.h:160
armarx::PlotterController::~PlotterController
~PlotterController() override
Definition: PlotterController.cpp:99
IceInternal::Handle< Variant >
std::isfinite
bool isfinite(const std::vector< T, Ts... > &v)
Definition: algorithm.h:366
armarx::VariantType::Double
const VariantTypeId Double
Definition: Variant.h:920
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:75
armarx::GetHandledExceptionString
std::string GetHandledExceptionString()
Definition: Exception.cpp:165
armarx::PlotterController::getSelectedDatafields
QStringList getSelectedDatafields() const
Definition: PlotterController.cpp:820
armarx::PlotterController::dataMap
GraphDataMap dataMap
Definition: PlotterController.h:164
armarx::PlotterController::__plottingPaused
bool __plottingPaused
Definition: PlotterController.h:155
armarx::QwtPlotMarkerPtr
QwtPlotMarker * QwtPlotMarkerPtr
Definition: PlotterController.h:60
cxxopts::value
std::shared_ptr< Value > value()
Definition: cxxopts.hpp:855
armarx::exceptions::local::InvalidDataFieldException
Definition: InvalidDataFieldException.h:33
armarx::PlotterController::curves
std::map< std::string, QwtPlotCurve * > curves
Definition: PlotterController.h:166
armarx::PlotterController::setupCurves
void setupCurves(int samplingIntervalMs=-1)
Definition: PlotterController.cpp:595
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
armarx::PlotterController::setUpdateInterval
void setUpdateInterval(int value)
Definition: PlotterController.cpp:916
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::PlotterController::stackedLayout
QStackedLayout * stackedLayout
Definition: PlotterController.h:172
armarx::VariantType::Long
const VariantTypeId Long
Definition: Variant.h:918
armarx::PlotterController::legendChecked
void legendChecked(const QVariant &itemInfo, bool on)
Required for Qt5.
Definition: PlotterController.cpp:759
PlotterController.h
armarx::PlotterController::plottingPaused
void plottingPaused(bool toggled)
Definition: PlotterController.cpp:338
armarx::PlotterController::getGraphStyle
std::string getGraphStyle() const
Definition: PlotterController.cpp:993
armarx::exceptions::local::InvalidChannelException
Definition: InvalidChannelException.h:33
armarx::PlotterController::clear
void clear()
Definition: PlotterController.cpp:949
armarx::VariantTypeId
Ice::Int VariantTypeId
Definition: Variant.h:43
armarx::PlotterController::clearHistory
void clearHistory()
Definition: PlotterController.cpp:960
armarx::VariantType::IsBasicType
bool IsBasicType(VariantTypeId id)
Definition: Variant.cpp:893
ARMARX_LOG_S
#define ARMARX_LOG_S
Definition: Logging.h:145
armarx::PlotterController::graphStyle
std::string graphStyle
Definition: PlotterController.h:153
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
armarx::PlotterController::pollingTask
PeriodicTask< PlotterController >::pointer_type pollingTask
Definition: PlotterController.h:161
armarx::red
QColor red()
Definition: StyleSheets.h:78
armarx::PlotterController::getShownInterval
int getShownInterval() const
Definition: PlotterController.cpp:967
armarx::TimeUtil::GetTime
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition: TimeUtil.cpp:42
armarx::PlotterController::createCurve
QwtPlotCurve * createCurve(const QString &label)
Definition: PlotterController.cpp:773
ExpressionException.h
armarx::PlotterController::pollingExec
void pollingExec()
Definition: PlotterController.cpp:120
armarx::PlotterController::PlotterController
PlotterController(QObject *parent)
Definition: PlotterController.cpp:36
armarx::PlotterController::getData
std::map< std::string, VariantPtr > getData(const QStringList &channels)
Definition: PlotterController.cpp:360
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
armarx::PlotterController::shownInterval
int shownInterval
Definition: PlotterController.h:152
armarx::PlotterController::setGraphStyle
void setGraphStyle(const std::string &style)
Definition: PlotterController.cpp:999
IceUtil::Handle< IceManager >
armarx::PlotterController::plotter
QPointer< QwtPlot > plotter
Definition: PlotterController.h:157
armarx::VariantType::Int
const VariantTypeId Int
Definition: Variant.h:917
armarx::PlotterController::getUpdateInterval
int getUpdateInterval() const
Definition: PlotterController.cpp:910
armarx::PlotterController::autoScalePlot
bool autoScalePlot
Definition: PlotterController.h:154
armarx::PlotterController::markers
std::map< std::string, std::map< IceUtil::Time, std::map< std::string, QwtPlotMarkerPtr > > > markers
Definition: PlotterController.h:170
armarx::PlotterController::getCurveColors
std::vector< Qt::GlobalColor > getCurveColors() const
Definition: PlotterController.cpp:1030
armarx::PeriodicTask
Definition: ArmarXManager.h:70
armarx::PlotterController::getSelectedDatafieldsKeys
std::vector< std::string > getSelectedDatafieldsKeys() const
Definition: PlotterController.cpp:827
min
T min(T t1, T t2)
Definition: gdiam.h:44
armarx::handleExceptions
void handleExceptions()
Definition: Exception.cpp:157
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::VariantType::String
const VariantTypeId String
Definition: Variant.h:921
armarx::PlotterController::setShownInterval
void setShownInterval(int value)
Definition: PlotterController.cpp:973
armarx::PlotterController::setCurveColors
void setCurveColors(const std::vector< Qt::GlobalColor > &value)
Definition: PlotterController.cpp:1036
armarx::TimeData
Definition: PlotterController.h:62
armarx::PlotterController::setSelectedDatafields
void setSelectedDatafields(const QStringList &value, int samplingIntervalMs=-1)
Changes the datafields that are plotted.
Definition: PlotterController.cpp:880
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::DataFieldIdentifier
DataFieldIdentifier provide the basis to identify data field within a distributed ArmarX scenario.
Definition: DataFieldIdentifier.h:48
armarx::green
QColor green()
Definition: StyleSheets.h:72
ARMARX_STREAM_PRINTER
#define ARMARX_STREAM_PRINTER
use this macro to write output code that is executed when printed and thus not executed if the debug ...
Definition: Logging.h:310