plotwidget.cpp
Go to the documentation of this file.
1 /*
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5  */
6 
7 #include <QAction>
8 #include <QActionGroup>
9 #include <QApplication>
10 #include <QDebug>
11 #include <QDrag>
12 #include <QDragEnterEvent>
13 #include <QDragMoveEvent>
14 #include <QFileDialog>
15 #include <QFileInfo>
16 #include <QMessageBox>
17 #include <QMenu>
18 #include <QMimeData>
19 #include <QPainter>
20 #include <QPushButton>
21 #include <QWheelEvent>
22 #include <QSettings>
23 #include <QSvgGenerator>
24 #include <QClipboard>
25 #include <iostream>
26 #include <limits>
27 #include <set>
28 #include <memory>
29 #include <QtXml/QDomElement>
30 #include "qwt_scale_widget.h"
31 #include "qwt_plot_canvas.h"
32 #include "qwt_plot_opengl_canvas.h"
33 #include "qwt_scale_engine.h"
34 #include "qwt_scale_map.h"
35 #include "qwt_plot_layout.h"
36 #include "qwt_scale_draw.h"
37 #include "qwt_text.h"
38 #include "plotwidget.h"
39 #include "qwt_plot_renderer.h"
40 #include "qwt_series_data.h"
41 #include "qwt_date_scale_draw.h"
42 #include "suggest_dialog.h"
44 #include "plotwidget_editor.h"
45 #include "plotwidget_transforms.h"
46 
47 #include "plotzoomer.h"
48 #include "plotmagnifier.h"
49 #include "plotlegend.h"
50 
51 #include "PlotJuggler/svg_util.h"
52 #include "point_series_xy.h"
53 #include "colormap_selector.h"
54 
55 #include "statistics_dialog.h"
56 
58 {
59  virtual QwtText label(double v) const
60  {
61  QDateTime dt = QDateTime::fromMSecsSinceEpoch((qint64)(v * 1000));
62  if (dt.date().year() == 1970 && dt.date().month() == 1 && dt.date().day() == 1)
63  {
64  return dt.toString("hh:mm:ss.z");
65  }
66  return dt.toString("hh:mm:ss.z\nyyyy MMM dd");
67  }
68 };
69 
70 const double MAX_DOUBLE = std::numeric_limits<double>::max() / 2;
71 
72 static bool if_xy_plot_failed_show_dialog = true;
73 
74 PlotWidget::PlotWidget(PlotDataMapRef& datamap, QWidget* parent)
75  : PlotWidgetBase(parent)
76  , _mapped_data(datamap)
77  , _tracker(nullptr)
78  , _use_date_time_scale(false)
79  , _dragging({ DragInfo::NONE, {}, nullptr })
80  , _time_offset(0.0)
81  , _transform_select_dialog(nullptr)
82  , _context_menu_enabled(true)
83 {
84  connect(this, &PlotWidget::curveListChanged, this,
85  [this]() { this->updateMaximumZoomArea(); });
86 
87  qwtPlot()->setAcceptDrops(true);
88 
89  //--------------------------
90  _tracker = (new CurveTracker(qwtPlot()));
91 
92  _grid = new QwtPlotGrid();
93  _grid->setPen(QPen(Qt::gray, 0.0, Qt::DotLine));
94 
95  connect(this, &PlotWidgetBase::viewResized, this, &PlotWidget::on_externallyResized);
96 
97  connect(this, &PlotWidgetBase::dragEnterSignal, this, &PlotWidget::onDragEnterEvent);
98  connect(this, &PlotWidgetBase::dragLeaveSignal, this, &PlotWidget::onDragLeaveEvent);
99 
100  connect(this, &PlotWidgetBase::dropSignal, this, &PlotWidget::onDropEvent);
101 
102  connect(this, &PlotWidgetBase::widgetResized, this, [this]() {
103  if (isXYPlot() && keepRatioXY())
104  {
105  rescaleEqualAxisScaling();
106  }
107  });
108 
109  //-------------------------
110 
111  buildActions();
112 
113  _custom_Y_limits.min = (-MAX_DOUBLE);
114  _custom_Y_limits.max = (MAX_DOUBLE);
115 
116  // QwtScaleWidget* bottomAxis = qwtPlot()->axisWidget( QwtPlot::xBottom );
117  // QwtScaleWidget* leftAxis = qwtPlot()->axisWidget( QwtPlot::yLeft );
118 
119  // bottomAxis->installEventFilter(this);
120  // leftAxis->installEventFilter(this);
121  // qwtPlot()->canvas()->installEventFilter(this);
122 }
123 
125 {
127  delete _action_split_vertical;
129  delete _action_zoomOutMaximum;
132  delete _action_saveToFile;
133  delete _action_copy;
134  delete _action_paste;
137 }
138 
140 {
141  _context_menu_enabled = enabled;
142 }
143 
145 {
146  QIcon iconDeleteList;
147 
148  _action_edit = new QAction("&Edit curves...", this);
149  connect(_action_edit, &QAction::triggered, this, [=]() {
150  auto editor_dialog = new PlotwidgetEditor(this, qwtPlot());
151  editor_dialog->exec();
152  editor_dialog->deleteLater();
153  });
154 
155  _action_formula = new QAction("&Apply filter to data...", this);
156  connect(_action_formula, &QAction::triggered, this, [=]() {
157  auto editor_dialog = new DialogTransformEditor(this);
158  int res = editor_dialog->exec();
159  editor_dialog->deleteLater();
160  if (res == QDialog::Accepted)
161  {
162  emit undoableChange();
163  }
164  });
165 
166  _action_split_horizontal = new QAction("&Split Horizontally", this);
167  connect(_action_split_horizontal, &QAction::triggered, this,
169 
170  _action_split_vertical = new QAction("&Split Vertically", this);
171  connect(_action_split_vertical, &QAction::triggered, this, &PlotWidget::splitVertical);
172 
173  _action_removeAllCurves = new QAction("&Remove ALL curves", this);
174  connect(_action_removeAllCurves, &QAction::triggered, this,
176  connect(_action_removeAllCurves, &QAction::triggered, this,
178 
179  _action_zoomOutMaximum = new QAction("&Zoom Out", this);
180  connect(_action_zoomOutMaximum, &QAction::triggered, this, [this]() {
181  zoomOut(true);
182  replot();
183  emit undoableChange();
184  });
185 
186  _action_zoomOutHorizontally = new QAction("&Zoom Out Horizontally", this);
187  connect(_action_zoomOutHorizontally, &QAction::triggered, this, [this]() {
189  replot();
190  emit undoableChange();
191  });
192 
193  _action_zoomOutVertically = new QAction("&Zoom Out Vertically", this);
194  connect(_action_zoomOutVertically, &QAction::triggered, this, [this]() {
196  replot();
197  emit undoableChange();
198  });
199 
200  QFont font;
201  font.setPointSize(10);
202 
203  _action_saveToFile = new QAction("&Save plot to file", this);
204  connect(_action_saveToFile, &QAction::triggered, this, &PlotWidget::on_savePlotToFile);
205 
206  _action_copy = new QAction("&Copy", this);
207  connect(_action_copy, &QAction::triggered, this, &PlotWidget::on_copyAction_triggered);
208 
209  _action_paste = new QAction("&Paste", this);
210  connect(_action_paste, &QAction::triggered, this,
212 
213  _action_image_to_clipboard = new QAction("&Copy image to clipboard", this);
214  connect(_action_image_to_clipboard, &QAction::triggered, this,
216 
217  _flip_x = new QAction("&Flip Horizontal Axis", this);
218  _flip_x->setCheckable(true);
219  connect(_flip_x, &QAction::changed, this, &PlotWidget::onFlipAxis);
220 
221  _flip_y = new QAction("&Flip Vertical Axis", this);
222  _flip_y->setCheckable(true);
223  connect(_flip_y, &QAction::changed, this, &PlotWidget::onFlipAxis);
224 
225  _action_data_statistics = new QAction("&Show data statistics", this);
226  connect(_action_data_statistics, &QAction::triggered, this,
228 }
229 
231 {
232  if (_context_menu_enabled == false)
233  {
234  return;
235  }
236 
237  QSettings settings;
238  QString theme = settings.value("StyleSheet::theme", "light").toString();
239 
240  _action_removeAllCurves->setIcon(LoadSvg(":/resources/svg/trash.svg", theme));
241  _action_edit->setIcon(LoadSvg(":/resources/svg/pencil-edit.svg", theme));
242  _action_formula->setIcon(LoadSvg(":/resources/svg/Fx.svg", theme));
243  _action_split_horizontal->setIcon(LoadSvg(":/resources/svg/add_column.svg", theme));
244  _action_split_vertical->setIcon(LoadSvg(":/resources/svg/add_row.svg", theme));
245  _action_zoomOutMaximum->setIcon(LoadSvg(":/resources/svg/zoom_max.svg", theme));
247  LoadSvg(":/resources/svg/zoom_horizontal.svg", theme));
248  _action_zoomOutVertically->setIcon(LoadSvg(":/resources/svg/zoom_vertical.svg", theme));
249  _action_copy->setIcon(LoadSvg(":/resources/svg/copy.svg", theme));
250  _action_paste->setIcon(LoadSvg(":/resources/svg/paste.svg", theme));
251  _action_saveToFile->setIcon(LoadSvg(":/resources/svg/save.svg", theme));
252  _action_image_to_clipboard->setIcon(LoadSvg(":/resources/svg/plot_image.svg", theme));
253 
254  QMenu menu(qwtPlot());
255 
256  menu.addAction(_action_edit);
257  menu.addAction(_action_formula);
258  menu.addSeparator();
259  menu.addAction(_action_split_horizontal);
260  menu.addAction(_action_split_vertical);
261  menu.addSeparator();
262  menu.addAction(_action_zoomOutMaximum);
263  menu.addAction(_action_zoomOutHorizontally);
264  menu.addAction(_action_zoomOutVertically);
265  menu.addSeparator();
266  menu.addAction(_action_removeAllCurves);
267  menu.addSeparator();
268  if (isXYPlot())
269  {
270  menu.addAction(_flip_x);
271  }
272  menu.addAction(_flip_y);
273  menu.addSeparator();
274  menu.addAction(_action_copy);
275  menu.addAction(_action_paste);
276  menu.addAction(_action_image_to_clipboard);
277  menu.addAction(_action_saveToFile);
278  menu.addAction(_action_data_statistics);
279 
280  // check the clipboard
281  QClipboard* clipboard = QGuiApplication::clipboard();
282  QString clipboard_text = clipboard->text();
283  QDomDocument doc;
284  bool valid_clipbaord = (!clipboard_text.isEmpty() && // not empty
285  doc.setContent(clipboard_text) && // valid xml
286  doc.firstChildElement().tagName() == "PlotWidgetClipBoard");
287 
288  _action_paste->setEnabled(valid_clipbaord);
289 
290  _action_removeAllCurves->setEnabled(!curveList().empty());
291  _action_formula->setEnabled(!curveList().empty() && !isXYPlot());
292 
293  menu.exec(qwtPlot()->canvas()->mapToGlobal(pos));
294 }
295 
296 PlotWidget::CurveInfo* PlotWidget::addCurveXY(std::string name_x, std::string name_y,
297  QString curve_name)
298 {
299  std::string name = curve_name.toStdString();
300 
301  while (name.empty())
302  {
303  SuggestDialog dialog(name_x, name_y, qwtPlot());
304  auto ret = dialog.exec();
305 
306  curve_name = dialog.suggestedName();
307  name = curve_name.toStdString();
308  name_x = dialog.nameX().toStdString();
309  name_y = dialog.nameY().toStdString();
310 
311  if (ret != QDialog::Accepted)
312  {
313  return nullptr;
314  }
315 
316  auto curve_it = curveFromTitle(curve_name);
317 
318  if (name.empty() || curve_it)
319  {
320  int ret = QMessageBox::warning(qwtPlot(), "Missing name",
321  "The name of the curve is missing or exist already. "
322  "Try again or abort.",
323  QMessageBox::Abort | QMessageBox::Retry,
324  QMessageBox::NoButton);
325  if (ret == QMessageBox::Abort || ret == QMessageBox::NoButton)
326  {
327  return nullptr;
328  }
329  name.clear();
330  }
331  }
332 
333  auto it = _mapped_data.numeric.find(name_x);
334  if (it == _mapped_data.numeric.end())
335  {
336  throw std::runtime_error("Creation of XY plot failed");
337  }
338  PlotData& data_x = it->second;
339 
340  it = _mapped_data.numeric.find(name_y);
341  if (it == _mapped_data.numeric.end())
342  {
343  throw std::runtime_error("Creation of XY plot failed");
344  }
345  PlotData& data_y = it->second;
346 
347  auto curve_it = curveFromTitle(curve_name);
348  if (curve_it)
349  {
350  return nullptr;
351  }
352 
353  const auto qname = QString::fromStdString(name);
354  auto curve = new QwtPlotCurve(qname);
355 
356  try
357  {
358  auto plot_qwt = createCurveXY(&data_x, &data_y);
359 
360  curve->setPaintAttribute(QwtPlotCurve::ClipPolygons, true);
361  curve->setPaintAttribute(QwtPlotCurve::FilterPointsAggressive, true);
362  curve->setData(plot_qwt);
363  }
364  catch (std::exception& ex)
365  {
366  QMessageBox::warning(qwtPlot(), "Exception!", ex.what());
367  return nullptr;
368  }
369 
370  QColor color = getColorHint(nullptr);
371  curve->setPen(color);
372  setStyle(curve, curveStyle());
373 
374  curve->setRenderHint(QwtPlotItem::RenderAntialiased, true);
375 
376  curve->attach(qwtPlot());
377 
378  auto marker = new QwtPlotMarker;
379  marker->attach(qwtPlot());
380  marker->setVisible(isXYPlot());
381  QwtSymbol* sym = new QwtSymbol(QwtSymbol::Ellipse, color, QPen(Qt::black), QSize(8, 8));
382  marker->setSymbol(sym);
383 
384  CurveInfo curve_info;
385  curve_info.curve = curve;
386  curve_info.marker = marker;
387  curve_info.src_name = name;
388  curveList().push_back(curve_info);
389 
390  return &(curveList().back());
391 }
392 
393 PlotWidgetBase::CurveInfo* PlotWidget::addCurve(const std::string& name, QColor color)
394 {
395  PlotWidgetBase::CurveInfo* info = nullptr;
396 
397  auto it1 = _mapped_data.numeric.find(name);
398  if (it1 != _mapped_data.numeric.end())
399  {
400  info = PlotWidgetBase::addCurve(name, it1->second, color);
401  }
402 
403  auto it2 = _mapped_data.scatter_xy.find(name);
404  if (it2 != _mapped_data.scatter_xy.end())
405  {
406  info = PlotWidgetBase::addCurve(name, it2->second, color);
407  }
408 
409  if (info && info->curve)
410  {
411  if (auto timeseries = dynamic_cast<QwtTimeseries*>(info->curve->data()))
412  {
413  timeseries->setTimeOffset(_time_offset);
414  }
415  }
416  return info;
417 }
418 
419 void PlotWidget::removeCurve(const QString& title)
420 {
421  PlotWidgetBase::removeCurve(title);
422  _tracker->redraw();
423 }
424 
425 void PlotWidget::onDataSourceRemoved(const std::string& src_name)
426 {
427  bool deleted = false;
428 
429  for (auto it = curveList().begin(); it != curveList().end();)
430  {
431  PointSeriesXY* curve_xy = dynamic_cast<PointSeriesXY*>(it->curve->data());
432  bool remove_curve_xy = curve_xy && (curve_xy->dataX()->plotName() == src_name ||
433  curve_xy->dataY()->plotName() == src_name);
434 
435  if (it->src_name == src_name || remove_curve_xy)
436  {
437  deleted = true;
438  it->curve->detach();
439  it->marker->detach();
440  it = curveList().erase(it);
441  }
442  else
443  {
444  it++;
445  }
446  }
447 
448  if (deleted)
449  {
450  _tracker->redraw();
451  emit curveListChanged();
452  }
453  if (_background_item &&
454  _background_item->dataName() == QString::fromStdString(src_name))
455  {
456  _background_item->detach();
457  _background_item.reset();
458  }
459 }
460 
462 {
463  PlotWidgetBase::removeAllCurves();
464  setModeXY(false);
465  _tracker->redraw();
466  _flip_x->setChecked(false);
467  _flip_y->setChecked(false);
468 }
469 
470 void PlotWidget::onDragEnterEvent(QDragEnterEvent* event)
471 {
472  const QMimeData* mimeData = event->mimeData();
473  QStringList mimeFormats = mimeData->formats();
474 
476  _dragging.curves.clear();
477  _dragging.source = event->source();
478 
479  auto& format = mimeFormats.first();
480  QByteArray encoded = mimeData->data(format);
481  QDataStream stream(&encoded, QIODevice::ReadOnly);
482 
483  while (!stream.atEnd())
484  {
485  QString curve_name;
486  stream >> curve_name;
487  auto name = curve_name.toStdString();
488  if (!curve_name.isEmpty())
489  {
490  _dragging.curves.push_back(curve_name);
491  }
492  if (_mapped_data.numeric.count(name) == 0 && _mapped_data.scatter_xy.count(name) == 0)
493  {
494  event->ignore();
495  return;
496  }
497  }
498 
499  if (_dragging.curves.empty())
500  {
501  event->ignore();
502  return;
503  }
504 
505  if (format == "curveslist/add_curve")
506  {
508  event->acceptProposedAction();
509  }
510 
511  if (format == "curveslist/new_XY_axis")
512  {
513  if (_dragging.curves.size() != 2)
514  {
515  qDebug() << "FATAL: Dragging " << _dragging.curves.size() << " curves";
516  return;
517  }
518  if (curveList().empty() || isXYPlot())
519  {
521  event->acceptProposedAction();
522  }
523  }
524 }
525 
526 void PlotWidget::onDragLeaveEvent(QDragLeaveEvent* event)
527 {
529  _dragging.curves.clear();
530 }
531 
532 void PlotWidget::onDropEvent(QDropEvent*)
533 {
534  bool curves_changed = false;
535 
536  bool noCurves = curveList().empty();
537 
539  {
540  size_t scatter_count = 0;
541  for (const auto& curve_name : _dragging.curves)
542  {
543  scatter_count += _mapped_data.scatter_xy.count(curve_name.toStdString());
544  }
545  bool scatter_curves = (scatter_count == _dragging.curves.size());
546  if (scatter_count > 0 && !scatter_curves)
547  {
549  _dragging.curves.clear();
550  QMessageBox::warning(qwtPlot(), "Warning",
551  "You can not drag XY (scatter) data and timeseries into the "
552  "same plot");
553  return;
554  }
555 
556  // if there aren't other curves, you can change the mode
557  if (curveList().empty())
558  {
559  setModeXY(scatter_curves);
560  }
561 
562  if (isXYPlot() && !scatter_curves)
563  {
564  QMessageBox::warning(qwtPlot(), "Warning",
565  tr("This is a [XY plot], you can not drop a timeseries here.\n"
566  "To convert this widget into a [timeseries plot], "
567  "you must first remove all its curves."));
568  }
569  if (!isXYPlot() && scatter_curves)
570  {
571  QMessageBox::warning(qwtPlot(), "Warning",
572  tr("This is a [timeseries plot], you can not "
573  "drop XY scatter data here.\n"
574  "To convert this widget into a [XY plot], "
575  "you must first remove all its curves."));
576  }
577 
578  if (isXYPlot() != scatter_curves)
579  {
581  _dragging.curves.clear();
582  return;
583  }
584 
585  for (const auto& curve_name : _dragging.curves)
586  {
587  bool added = addCurve(curve_name.toStdString()) != nullptr;
588  curves_changed = curves_changed || added;
589  }
590  }
591  else if (_dragging.mode == DragInfo::NEW_XY && _dragging.curves.size() == 2)
592  {
593  if (!curveList().empty() && !isXYPlot())
594  {
596  _dragging.curves.clear();
597  QMessageBox::warning(qwtPlot(), "Warning",
598  tr("This is a [timeseries plot], you can not "
599  "drop XY scatter data here.\n"
600  "To convert this widget into a [XY plot], "
601  "you must first remove all its curves."));
602  return;
603  }
604 
605  setModeXY(true);
606  addCurveXY(_dragging.curves[0].toStdString(), _dragging.curves[1].toStdString());
607 
608  curves_changed = true;
609  }
610 
611  if (curves_changed)
612  {
613  emit curvesDropped();
614  emit curveListChanged();
615 
616  QSettings settings;
617  bool autozoom_curve_added =
618  settings.value("Preferences::autozoom_curve_added", true).toBool();
619  if (autozoom_curve_added || noCurves)
620  {
621  zoomOut(autozoom_curve_added);
622  }
623  else
624  {
625  replot();
626  }
627  }
629  _dragging.curves.clear();
630 }
631 
632 void PlotWidget::on_panned(int, int)
633 {
635 }
636 
637 QDomElement PlotWidget::xmlSaveState(QDomDocument& doc) const
638 {
639  QDomElement plot_el = doc.createElement("plot");
640 
641  QDomElement range_el = doc.createElement("range");
642  QRectF rect = currentBoundingRect();
643  range_el.setAttribute("bottom", QString::number(rect.bottom(), 'f', 6));
644  range_el.setAttribute("top", QString::number(rect.top(), 'f', 6));
645  range_el.setAttribute("left", QString::number(rect.left(), 'f', 6));
646  range_el.setAttribute("right", QString::number(rect.right(), 'f', 6));
647  plot_el.appendChild(range_el);
648 
649  QDomElement limitY_el = doc.createElement("limitY");
651  {
652  limitY_el.setAttribute("min", QString::number(_custom_Y_limits.min));
653  }
655  {
656  limitY_el.setAttribute("max", QString::number(_custom_Y_limits.max));
657  }
658  plot_el.appendChild(limitY_el);
659 
660  if (curveStyle() == PlotWidgetBase::LINES)
661  {
662  plot_el.setAttribute("style", "Lines");
663  }
664  else if (curveStyle() == PlotWidgetBase::LINES_AND_DOTS)
665  {
666  plot_el.setAttribute("style", "LinesAndDots");
667  }
668  else if (curveStyle() == PlotWidgetBase::DOTS)
669  {
670  plot_el.setAttribute("style", "Dots");
671  }
672  else if (curveStyle() == PlotWidgetBase::STICKS)
673  {
674  plot_el.setAttribute("style", "Sticks");
675  }
676  else if (curveStyle() == PlotWidgetBase::STEPS)
677  {
678  plot_el.setAttribute("style", "Steps");
679  }
680  else if (curveStyle() == PlotWidgetBase::STEPSINV)
681  {
682  plot_el.setAttribute("style", "StepsInv");
683  }
684 
685  for (auto& it : curveList())
686  {
687  auto& name = it.src_name;
688  QwtPlotCurve* curve = it.curve;
689  QDomElement curve_el = doc.createElement("curve");
690  curve_el.setAttribute("name", QString::fromStdString(name));
691  curve_el.setAttribute("color", curve->pen().color().name());
692 
693  plot_el.appendChild(curve_el);
694 
695  if (isXYPlot())
696  {
697  if (auto xy = dynamic_cast<PointSeriesXY*>(curve->data()))
698  {
699  curve_el.setAttribute("curve_x", QString::fromStdString(xy->dataX()->plotName()));
700  curve_el.setAttribute("curve_y", QString::fromStdString(xy->dataY()->plotName()));
701  }
702  }
703  else
704  {
705  auto ts = dynamic_cast<TransformedTimeseries*>(curve->data());
706  if (ts && ts->transform())
707  {
708  QDomElement transform_el = doc.createElement("transform");
709  transform_el.setAttribute("name", ts->transformName());
710  transform_el.setAttribute("alias", ts->alias());
711  ts->transform()->xmlSaveState(doc, transform_el);
712  curve_el.appendChild(transform_el);
713  }
714  }
715  }
716 
717  plot_el.setAttribute("mode", isXYPlot() ? "XYPlot" : "TimeSeries");
718 
719  plot_el.setAttribute("flip_x", isXYPlot() && _flip_x->isChecked() ? "true" : "false");
720  plot_el.setAttribute("flip_y", _flip_y->isChecked() ? "true" : "false");
721 
722  if (_background_item)
723  {
724  plot_el.setAttribute("background_data", _background_item->dataName());
725  plot_el.setAttribute("background_colormap", _background_item->colormapName());
726  }
727 
728  return plot_el;
729 }
730 
731 bool PlotWidget::xmlLoadState(QDomElement& plot_widget, bool autozoom)
732 {
733  std::set<std::string> added_curve_names;
734 
735  QString mode = plot_widget.attribute("mode");
736  setModeXY(mode == "XYPlot");
737 
738  _flip_x->setChecked(plot_widget.attribute("flip_x") == "true");
739  _flip_y->setChecked(plot_widget.attribute("flip_y") == "true");
740 
741  QDomElement limitY_el = plot_widget.firstChildElement("limitY");
742 
745 
746  if (!limitY_el.isNull())
747  {
748  if (limitY_el.hasAttribute("min"))
749  {
750  _custom_Y_limits.min = limitY_el.attribute("min").toDouble();
751  }
752  if (limitY_el.hasAttribute("max"))
753  {
754  _custom_Y_limits.max = limitY_el.attribute("max").toDouble();
755  }
756  }
757 
758  static bool warning_message_shown = false;
759 
760  // removeAllCurves simplified
761  for (auto& it : curveList())
762  {
763  it.curve->detach();
764  it.marker->detach();
765  }
766  curveList().clear();
767 
768  // insert curves
769  QStringList missing_curves;
770  for (QDomElement curve_element = plot_widget.firstChildElement("curve");
771  !curve_element.isNull(); curve_element = curve_element.nextSiblingElement("curve"))
772  {
773  bool is_merged_xy =
774  curve_element.hasAttribute("curve_x") && curve_element.hasAttribute("curve_y");
775  bool is_timeseries = !isXYPlot();
776  bool is_scatter_xy = !is_timeseries && !is_merged_xy;
777 
778  QString curve_name = curve_element.attribute("name");
779  std::string curve_name_std = curve_name.toStdString();
780  QColor color(curve_element.attribute("color"));
781 
782  //-----------------
783  if (is_timeseries || is_scatter_xy)
784  {
785  if ((is_timeseries && _mapped_data.numeric.count(curve_name_std) == 0) ||
786  (!is_timeseries && _mapped_data.scatter_xy.count(curve_name_std) == 0))
787  {
788  missing_curves.append(curve_name);
789  }
790  else
791  {
792  auto curve_info = addCurve(curve_name_std, color);
793  if (!curve_info)
794  {
795  continue;
796  }
797  auto& curve = curve_info->curve;
798  curve->setPen(color, 1.3);
799  added_curve_names.insert(curve_name_std);
800 
801  auto ts = dynamic_cast<TransformedTimeseries*>(curve->data());
802  QDomElement transform_el = curve_element.firstChildElement("transform");
803  if (ts && transform_el.isNull() == false)
804  {
805  ts->setTransform(transform_el.attribute("name"));
806  ts->transform()->xmlLoadState(transform_el);
807  ts->updateCache(true);
808  auto alias = transform_el.attribute("alias");
809  ts->setAlias(alias);
810  curve->setTitle(alias);
811  }
812  }
813  }
814  //-----------------
815  if (is_merged_xy)
816  {
817  std::string curve_x = curve_element.attribute("curve_x").toStdString();
818  std::string curve_y = curve_element.attribute("curve_y").toStdString();
819  if (_mapped_data.numeric.find(curve_x) == _mapped_data.numeric.end() ||
820  _mapped_data.numeric.find(curve_y) == _mapped_data.numeric.end())
821  {
822  missing_curves.append(curve_name);
823  }
824  else
825  {
826  auto curve_it = addCurveXY(curve_x, curve_y, curve_name);
827  if (!curve_it)
828  {
829  continue;
830  }
831  curve_it->curve->setPen(color, 1.3);
832  curve_it->marker->setSymbol(
833  new QwtSymbol(QwtSymbol::Ellipse, color, QPen(Qt::black), QSize(8, 8)));
834  added_curve_names.insert(curve_name_std);
835  }
836  }
837  }
838 
839  if (missing_curves.size() > 0 && !warning_message_shown)
840  {
841  QMessageBox::warning(qwtPlot(), "Warning",
842  tr("Can't find one or more curves.\n"
843  "This message will be shown only once.\n%1")
844  .arg(missing_curves.join(",\n")));
845  warning_message_shown = true;
846  }
847 
848  emit curveListChanged();
849 
850  //-----------------------------------------
851 
852  QDomElement rectangle = plot_widget.firstChildElement("range");
853 
854  if (!rectangle.isNull() && autozoom)
855  {
856  QRectF rect;
857  rect.setBottom(rectangle.attribute("bottom").toDouble());
858  rect.setTop(rectangle.attribute("top").toDouble());
859  rect.setLeft(rectangle.attribute("left").toDouble());
860  rect.setRight(rectangle.attribute("right").toDouble());
861  this->setZoomRectangle(rect, false);
862  }
863 
864  if (plot_widget.hasAttribute("style"))
865  {
866  QString style = plot_widget.attribute("style");
867  if (style == "Lines")
868  {
869  changeCurvesStyle(PlotWidgetBase::LINES);
870  }
871  else if (style == "LinesAndDots")
872  {
873  changeCurvesStyle(PlotWidgetBase::LINES_AND_DOTS);
874  }
875  else if (style == "Dots")
876  {
877  changeCurvesStyle(PlotWidgetBase::DOTS);
878  }
879  else if (style == "Sticks")
880  {
881  changeCurvesStyle(PlotWidgetBase::STICKS);
882  }
883  else if (style == "Steps")
884  {
885  changeCurvesStyle(PlotWidgetBase::STEPS);
886  }
887  else if (style == "StepsInv")
888  {
889  changeCurvesStyle(PlotWidgetBase::STEPSINV);
890  }
891  }
892 
893  QString bg_data = plot_widget.attribute("background_data");
894  QString bg_colormap = plot_widget.attribute("background_colormap");
895 
896  if (!bg_data.isEmpty() && !bg_colormap.isEmpty())
897  {
898  auto plot_it = datamap().numeric.find(bg_data.toStdString());
899  if (plot_it == datamap().numeric.end())
900  {
901  QMessageBox::warning(qwtPlot(), "Warning",
902  tr("Can't restore the background color.\n"
903  "Series [%1] not found.")
904  .arg(bg_data));
905  }
906  else
907  {
908  auto color_it = ColorMapLibrary().find(bg_colormap);
909  if (color_it == ColorMapLibrary().end())
910  {
911  QMessageBox::warning(qwtPlot(), "Warning",
912  tr("Can't restore the background color.\n"
913  "ColorMap [%1] not found.")
914  .arg(bg_colormap));
915  }
916  else
917  {
918  // everything fine.
920  std::make_unique<BackgroundColorItem>(plot_it->second, bg_colormap);
921  _background_item->setTimeOffset(&_time_offset);
922  _background_item->attach(qwtPlot());
923  }
924  }
925  }
926 
927  if (autozoom)
928  {
930  }
931  replot();
932  return true;
933 }
934 
936 {
937  QRectF canvas_rect = qwtPlot()->canvas()->contentsRect();
938 
939  auto max_rect = maxZoomRect();
940  const double canvas_ratio = std::abs(canvas_rect.width() / canvas_rect.height());
941  const double max_ratio = std::abs(max_rect.width() / max_rect.height());
942 
943  QRectF rect = max_rect;
944 
945  if (max_ratio < canvas_ratio)
946  {
947  double new_width = (-max_rect.height() * canvas_ratio);
948  rect.setWidth(new_width);
949  }
950  else
951  {
952  double new_height = (-max_rect.width() / canvas_ratio);
953  rect.setHeight(new_height);
954  }
955 
956  rect.moveCenter(max_rect.center());
957 
958  setAxisScale(QwtPlot::yLeft, rect.bottom(), rect.top());
959  setAxisScale(QwtPlot::xBottom, rect.left(), rect.right());
960  qwtPlot()->updateAxes();
961  replot();
962 }
963 
964 void PlotWidget::setZoomRectangle(QRectF rect, bool emit_signal)
965 {
966  if (isXYPlot() && keepRatioXY())
967  {
969  }
970  else
971  {
972  setAxisScale(QwtPlot::yLeft, rect.bottom(), rect.top());
973  setAxisScale(QwtPlot::xBottom, rect.left(), rect.right());
974  qwtPlot()->updateAxes();
975  }
976 
977  if (emit_signal)
978  {
979  if (isXYPlot())
980  {
981  emit undoableChange();
982  }
983  else
984  {
985  emit rectChanged(this, rect);
986  }
987  }
989 }
990 
992 {
993  // TODO: this needs MUCH more testing
994 
995  int visible = 0;
996 
997  for (auto& it : curveList())
998  {
999  if (it.curve->isVisible())
1000  {
1001  visible++;
1002  }
1003 
1004  const auto& curve_name = it.src_name;
1005 
1006  auto data_it = _mapped_data.numeric.find(curve_name);
1007  if (data_it != _mapped_data.numeric.end())
1008  {
1009  if (auto ts = dynamic_cast<TransformedTimeseries*>(it.curve->data()))
1010  {
1011  ts->updateCache(true);
1012  }
1013  }
1014  }
1015 
1016  if (curveList().size() == 0 || visible == 0)
1017  {
1018  setDefaultRangeX();
1019  }
1020 }
1021 
1022 void PlotWidget::activateLegend(bool activate)
1023 {
1024  legend()->setVisible(activate);
1025 }
1026 
1027 void PlotWidget::activateGrid(bool activate)
1028 {
1029  _grid->enableX(activate);
1030  _grid->enableXMin(activate);
1031  _grid->enableY(activate);
1032  _grid->enableYMin(activate);
1033  _grid->attach(qwtPlot());
1034 }
1035 
1037 {
1038  _tracker->setParameter(val);
1039 }
1040 
1042 {
1044 }
1045 
1047 {
1048  return _tracker->isEnabled();
1049 }
1050 
1051 void PlotWidget::setTrackerPosition(double abs_time)
1052 {
1053  if (isXYPlot())
1054  {
1055  for (auto& it : curveList())
1056  {
1057  if (auto series = dynamic_cast<QwtTimeseries*>(it.curve->data()))
1058  {
1059  auto pointXY = series->sampleFromTime(abs_time);
1060  if (pointXY)
1061  {
1062  it.marker->setValue(pointXY.value());
1063  }
1064  }
1065  }
1066  }
1067  else
1068  {
1069  double relative_time = abs_time - _time_offset;
1070  _tracker->setPosition(QPointF(relative_time, 0.0));
1071  }
1072 }
1073 
1075 {
1076  auto prev_offset = _time_offset;
1077  _time_offset = offset;
1078 
1079  if (fabs(prev_offset - offset) > std::numeric_limits<double>::epsilon())
1080  {
1081  for (auto& it : curveList())
1082  {
1083  if (auto series = dynamic_cast<QwtTimeseries*>(it.curve->data()))
1084  {
1085  series->setTimeOffset(_time_offset);
1086  }
1087  }
1088  if (!isXYPlot() && !curveList().empty())
1089  {
1090  QRectF rect = currentBoundingRect();
1091  double delta = prev_offset - offset;
1092  rect.moveLeft(rect.left() + delta);
1093  setZoomRectangle(rect, false);
1094  }
1095  }
1097 }
1098 
1100 {
1102  bool is_timescale =
1103  dynamic_cast<TimeScaleDraw*>(qwtPlot()->axisScaleDraw(QwtPlot::xBottom)) != nullptr;
1104 
1105  if (enable && !isXYPlot())
1106  {
1107  if (!is_timescale)
1108  {
1110  }
1111  }
1112  else
1113  {
1114  if (is_timescale)
1115  {
1117  }
1118  }
1119 }
1120 
1121 // TODO report failure for empty dataset
1123 {
1124  auto [bottom, top] = PlotWidgetBase::getVisualizationRangeY(range_X);
1125 
1126  const bool lower_limit = _custom_Y_limits.min > -MAX_DOUBLE;
1127  const bool upper_limit = _custom_Y_limits.max < MAX_DOUBLE;
1128 
1129  if (lower_limit)
1130  {
1131  bottom = _custom_Y_limits.min;
1132  if (top < bottom)
1133  {
1134  top = bottom;
1135  }
1136  }
1137 
1138  if (upper_limit)
1139  {
1141  if (top < bottom)
1142  {
1143  bottom = top;
1144  }
1145  }
1146 
1147  return Range({ bottom, top });
1148 }
1149 
1150 void PlotWidget::updateCurves(bool reset_older_data)
1151 {
1152  for (auto& it : curveList())
1153  {
1154  auto series = dynamic_cast<QwtSeriesWrapper*>(it.curve->data());
1155  series->updateCache(reset_older_data);
1156  }
1158 
1159  updateStatistics(true);
1160 }
1161 
1162 void PlotWidget::updateStatistics(bool forceUpdate)
1163 {
1164  if (_statistics_dialog)
1165  {
1166  if (_statistics_dialog->calcVisibleRange() || forceUpdate)
1167  {
1168  auto rect = currentBoundingRect();
1169  _statistics_dialog->update({ rect.left(), rect.right() });
1170  }
1171  }
1172 }
1173 
1174 void PlotWidget::on_changeCurveColor(const QString& curve_name, QColor new_color)
1175 {
1176  for (auto& it : curveList())
1177  {
1178  if (it.curve->title() == curve_name)
1179  {
1180  auto& curve = it.curve;
1181  if (curve->pen().color() != new_color)
1182  {
1183  curve->setPen(new_color, 1.3);
1184  }
1185  replot();
1186  break;
1187  }
1188  }
1189 }
1190 
1192 {
1193  if (isXYPlot())
1194  {
1196  }
1197  else
1198  {
1199  QRectF canvas_rect = qwtPlot()->canvas()->contentsRect();
1200  const QwtScaleMap xMap = qwtPlot()->canvasMap(QwtPlot::xBottom);
1201  const QwtScaleMap yMap = qwtPlot()->canvasMap(QwtPlot::yLeft);
1202  canvas_rect = canvas_rect.normalized();
1203  double x1 = xMap.invTransform(canvas_rect.left());
1204  double x2 = xMap.invTransform(canvas_rect.right());
1205  double y1 = yMap.invTransform(canvas_rect.bottom());
1206  double y2 = yMap.invTransform(canvas_rect.top());
1207  // flip will be done inside the function setAxisScale()
1208  setAxisScale(QwtPlot::yLeft, y1, y2);
1209  setAxisScale(QwtPlot::xBottom, x1, x2);
1210  qwtPlot()->updateAxes();
1211  replot();
1212  }
1213  emit undoableChange();
1214 }
1215 
1217 {
1218  QString prev_colormap;
1219  if (name.isEmpty())
1220  {
1221  if (_background_item)
1222  {
1223  name = _background_item->dataName();
1224  prev_colormap = _background_item->colormapName();
1225  }
1226  else
1227  {
1228  return;
1229  }
1230  }
1231 
1232  auto plot_it = datamap().numeric.find(name.toStdString());
1233  if (plot_it == datamap().numeric.end())
1234  {
1235  if (_background_item)
1236  {
1237  _background_item->detach();
1238  _background_item.reset();
1239  replot();
1240  }
1241  return;
1242  }
1243 
1244  ColormapSelectorDialog dialog(name, prev_colormap, this);
1245  auto ret = dialog.exec();
1246  if (ret == QDialog::Accepted)
1247  {
1248  if (_background_item)
1249  {
1250  _background_item->detach();
1251  _background_item.reset();
1252  }
1253 
1254  QString colormap = dialog.selectedColorMap();
1255  if (!colormap.isEmpty() && ColorMapLibrary().count(colormap) != 0)
1256  {
1257  _background_item = std::make_unique<BackgroundColorItem>(plot_it->second, colormap);
1258  _background_item->setTimeOffset(&_time_offset);
1259  _background_item->attach(qwtPlot());
1260  }
1261  replot();
1262  }
1263 }
1264 
1266 {
1267  _statistics_window_title = title;
1268 
1269  if (_statistics_dialog)
1270  {
1272  }
1273 }
1274 
1276 {
1277  if (!_statistics_dialog)
1278  {
1280  }
1281 
1283 
1284  auto rect = currentBoundingRect();
1285  _statistics_dialog->update({ rect.left(), rect.right() });
1286  _statistics_dialog->show();
1287  _statistics_dialog->raise();
1288  _statistics_dialog->activateWindow();
1289 
1290  _statistics_dialog->setAttribute(Qt::WA_DeleteOnClose);
1291 
1292  auto setToNull = [this]() { _statistics_dialog = nullptr; };
1293 
1295  [this](PlotWidget*, QRectF rect) {
1296  _statistics_dialog->update({ rect.left(), rect.right() });
1297  });
1298 
1299  connect(_statistics_dialog, &QDialog::rejected, this, setToNull);
1300 
1301  connect(this, &PlotWidgetBase::curveListChanged, this,
1302  [this]() { updateStatistics(); });
1303 }
1304 
1305 void PlotWidget::on_externallyResized(const QRectF& rect)
1306 {
1307  QRectF current_rect = currentBoundingRect();
1308  if (current_rect == rect)
1309  {
1310  return;
1311  }
1312 
1313  if (!isXYPlot() && isZoomLinkEnabled())
1314  {
1315  emit rectChanged(this, rect);
1316  }
1317 }
1318 
1319 void PlotWidget::zoomOut(bool emit_signal)
1320 {
1321  if (curveList().size() == 0)
1322  {
1323  QRectF rect(0, 1, 1, -1);
1324  this->setZoomRectangle(rect, false);
1325  return;
1326  }
1328 
1329  setZoomRectangle(maxZoomRect(), emit_signal);
1330  replot();
1331 }
1332 
1334 {
1336  QRectF act = currentBoundingRect();
1337  auto rangeX = getVisualizationRangeX();
1338 
1339  act.setLeft(rangeX.min);
1340  act.setRight(rangeX.max);
1341  setZoomRectangle(act, emit_signal);
1342 }
1343 
1345 {
1347  QRectF rect = currentBoundingRect();
1348  auto rangeY = getVisualizationRangeY({ rect.left(), rect.right() });
1349 
1350  rect.setBottom(rangeY.min);
1351  rect.setTop(rangeY.max);
1352  this->setZoomRectangle(rect, emit_signal);
1353 }
1354 
1356 {
1357  if (enable == isXYPlot())
1358  {
1359  return;
1360  }
1361  PlotWidgetBase::setModeXY(enable);
1362 
1364 
1365  if (enable)
1366  {
1367  QFont font_footer;
1368  font_footer.setPointSize(10);
1369  QwtText text("XY Plot");
1370  text.setFont(font_footer);
1371  qwtPlot()->setFooter(text);
1372  }
1373  else
1374  {
1375  qwtPlot()->setFooter("");
1376  }
1377 
1378  zoomOut(true);
1380  replot();
1381 }
1382 
1384 {
1385  QSettings settings;
1386  QByteArray xml_text =
1387  settings.value("AddCustomPlotDialog.savedXML", QByteArray()).toByteArray();
1388  if (!xml_text.isEmpty())
1389  {
1390  _snippets = GetSnippetsFromXML(xml_text);
1391  }
1392 }
1393 
1395 {
1396  QString fileName;
1397 
1398  QFileDialog saveDialog(qwtPlot());
1399  saveDialog.setAcceptMode(QFileDialog::AcceptSave);
1400 
1401  QStringList filters;
1402  filters << "png (*.png)"
1403  << "jpg (*.jpg *.jpeg)"
1404  << "svg (*.svg)";
1405 
1406  saveDialog.setNameFilters(filters);
1407  saveDialog.exec();
1408 
1409  if (saveDialog.result() == QDialog::Accepted && !saveDialog.selectedFiles().empty())
1410  {
1411  fileName = saveDialog.selectedFiles().first();
1412 
1413  if (fileName.isEmpty())
1414  {
1415  return;
1416  }
1417 
1418  bool is_svg = false;
1419  QFileInfo fileinfo(fileName);
1420  if (fileinfo.suffix().isEmpty())
1421  {
1422  auto filter = saveDialog.selectedNameFilter();
1423  if (filter == filters[0])
1424  {
1425  fileName.append(".png");
1426  }
1427  else if (filter == filters[1])
1428  {
1429  fileName.append(".jpg");
1430  }
1431  else if (filter == filters[2])
1432  {
1433  fileName.append(".svg");
1434  is_svg = true;
1435  }
1436  }
1437 
1438  bool tracker_enabled = _tracker->isEnabled();
1439  if (tracker_enabled)
1440  {
1441  this->enableTracker(false);
1442  replot();
1443  }
1444 
1445  QRect documentRect(0, 0, 1200, 900);
1446  QwtPlotRenderer rend;
1447 
1448  if (is_svg)
1449  {
1450  QSvgGenerator generator;
1451  generator.setFileName(fileName);
1452  generator.setResolution(80);
1453  generator.setViewBox(documentRect);
1454  QPainter painter(&generator);
1455  rend.render(qwtPlot(), &painter, documentRect);
1456  }
1457  else
1458  {
1459  QPixmap pixmap(1200, 900);
1460  QPainter painter(&pixmap);
1461  rend.render(qwtPlot(), &painter, documentRect);
1462  pixmap.save(fileName);
1463  }
1464 
1465  if (tracker_enabled)
1466  {
1467  this->enableTracker(true);
1468  replot();
1469  }
1470  }
1471 }
1472 
1474 {
1475  _custom_Y_limits = range;
1477  replot();
1478 }
1479 
1481 {
1482  return _custom_Y_limits;
1483 }
1484 
1486 {
1487  bool tracker_enabled = _tracker->isEnabled();
1488  if (tracker_enabled)
1489  {
1490  this->enableTracker(false);
1491  replot();
1492  }
1493 
1494  auto documentRect = qwtPlot()->canvas()->rect();
1495  qDebug() << documentRect;
1496 
1497  QwtPlotRenderer rend;
1498  QPixmap pixmap(documentRect.width(), documentRect.height());
1499  QPainter painter(&pixmap);
1500  rend.render(qwtPlot(), &painter, documentRect);
1501 
1502  QClipboard* clipboard = QGuiApplication::clipboard();
1503  clipboard->setPixmap(pixmap);
1504 
1505  if (tracker_enabled)
1506  {
1507  this->enableTracker(true);
1508  replot();
1509  }
1510 }
1511 
1513 {
1514  QDomDocument doc;
1515  auto root = doc.createElement("PlotWidgetClipBoard");
1516  auto el = xmlSaveState(doc);
1517  doc.appendChild(root);
1518  root.appendChild(el);
1519 
1520  QClipboard* clipboard = QGuiApplication::clipboard();
1521  clipboard->setText(doc.toString());
1522 }
1523 
1525 {
1526  QClipboard* clipboard = QGuiApplication::clipboard();
1527  QString clipboard_text = clipboard->text();
1528 
1529  QDomDocument doc;
1530  bool valid = doc.setContent(clipboard_text);
1531  if (!valid)
1532  {
1533  return;
1534  }
1535  auto root = doc.firstChildElement();
1536  if (root.tagName() != "PlotWidgetClipBoard")
1537  {
1538  return;
1539  }
1540  else
1541  {
1542  auto el = root.firstChildElement();
1543  xmlLoadState(el);
1544  emit undoableChange();
1545  }
1546 }
1547 
1548 bool PlotWidget::eventFilter(QObject* obj, QEvent* event)
1549 {
1550  if (PlotWidgetBase::eventFilter(obj, event))
1551  {
1552  return true;
1553  }
1554 
1555  if (event->type() == QEvent::Destroy)
1556  {
1557  return false;
1558  }
1559 
1560  if (obj == qwtPlot()->canvas())
1561  {
1562  return canvasEventFilter(event);
1563  }
1564  return false;
1565 }
1566 
1568 {
1569  QSettings settings;
1570  QString theme = settings.value("Preferences::theme", "light").toString();
1571  auto pixmap = LoadSvg(":/resources/svg/move_view.svg", theme);
1572  QApplication::setOverrideCursor(QCursor(pixmap.scaled(24, 24)));
1573 }
1574 
1575 void PlotWidget::setAxisScale(QwtAxisId axisId, double min, double max)
1576 {
1577  if (min > max)
1578  {
1579  std::swap(min, max);
1580  }
1581  if (axisId == QwtPlot::xBottom && _flip_x->isChecked())
1582  {
1583  qwtPlot()->setAxisScale(QwtPlot::xBottom, max, min);
1584  }
1585  else if (axisId == QwtPlot::yLeft && _flip_y->isChecked())
1586  {
1587  qwtPlot()->setAxisScale(QwtPlot::yLeft, max, min);
1588  }
1589  else
1590  {
1591  qwtPlot()->setAxisScale(axisId, min, max);
1592  }
1593 }
1594 
1596 {
1597  // for (const auto& it : curveList())
1598  // {
1599  // auto series = dynamic_cast<QwtSeriesWrapper*>(it.curve->data());
1600  // if (series->plotData()->attribute(PJ::DISABLE_LINKED_ZOOM).toBool())
1601  // {
1602  // return false;
1603  // }
1604  // }
1605  return true;
1606 }
1607 
1609 {
1610  switch (event->type())
1611  {
1612  case QEvent::MouseButtonPress: {
1613  if (_dragging.mode != DragInfo::NONE)
1614  {
1615  return true; // don't pass to canvas().
1616  }
1617 
1618  QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
1619 
1620  if (mouse_event->button() == Qt::LeftButton)
1621  {
1622  const QPoint press_point = mouse_event->pos();
1623  if (mouse_event->modifiers() == Qt::ShiftModifier) // time tracker
1624  {
1625  QPointF pointF(qwtPlot()->invTransform(QwtPlot::xBottom, press_point.x()),
1626  qwtPlot()->invTransform(QwtPlot::yLeft, press_point.y()));
1627  emit trackerMoved(pointF);
1628  return true; // don't pass to canvas().
1629  }
1630  else if (mouse_event->modifiers() == Qt::ControlModifier) // panner
1631  {
1633  }
1634  return false; // send to canvas()
1635  }
1636  else if (mouse_event->buttons() == Qt::MiddleButton &&
1637  mouse_event->modifiers() == Qt::NoModifier)
1638  {
1640  return false;
1641  }
1642  else if (mouse_event->button() == Qt::RightButton)
1643  {
1644  if (mouse_event->modifiers() == Qt::NoModifier) // show menu
1645  {
1646  canvasContextMenuTriggered(mouse_event->pos());
1647  return true; // don't pass to canvas().
1648  }
1649  }
1650  }
1651  break;
1652  //---------------------------------
1653  case QEvent::MouseMove: {
1654  if (_dragging.mode != DragInfo::NONE)
1655  {
1656  return true; // don't pass to canvas().
1657  }
1658 
1659  QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
1660 
1661  if (mouse_event->buttons() == Qt::LeftButton &&
1662  mouse_event->modifiers() == Qt::ShiftModifier)
1663  {
1664  const QPoint point = mouse_event->pos();
1665  QPointF pointF(qwtPlot()->invTransform(QwtPlot::xBottom, point.x()),
1666  qwtPlot()->invTransform(QwtPlot::yLeft, point.y()));
1667  emit trackerMoved(pointF);
1668  return true;
1669  }
1670  }
1671  break;
1672 
1673  case QEvent::Leave: {
1675  _dragging.curves.clear();
1676  }
1677  break;
1678  case QEvent::MouseButtonRelease: {
1679  if (_dragging.mode == DragInfo::NONE)
1680  {
1681  QApplication::restoreOverrideCursor();
1682  return false;
1683  }
1684  }
1685  break;
1686 
1687  } // end switch
1688 
1689  return false;
1690 }
1691 
1693 {
1694  if (!curveList().empty())
1695  {
1696  double min = std::numeric_limits<double>::max();
1697  double max = std::numeric_limits<double>::lowest();
1698  for (auto& it : _mapped_data.numeric)
1699  {
1700  const PlotData& data = it.second;
1701  if (data.size() > 0)
1702  {
1703  double A = data.front().x;
1704  double B = data.back().x;
1705  min = std::min(A, min);
1706  max = std::max(B, max);
1707  }
1708  }
1710  }
1711  else
1712  {
1713  setAxisScale(QwtPlot::xBottom, 0.0, 1.0);
1714  }
1715 }
1716 
1718  const PlotData* data_y)
1719 {
1720  PointSeriesXY* output = nullptr;
1721 
1722  try
1723  {
1724  output = new PointSeriesXY(data_x, data_y);
1725  }
1726  catch (std::runtime_error& ex)
1727  {
1729  {
1730  QMessageBox msgBox(qwtPlot());
1731  msgBox.setWindowTitle("Warnings");
1732  msgBox.setText(tr("The creation of the XY plot failed with the following "
1733  "message:\n %1")
1734  .arg(ex.what()));
1735  msgBox.addButton("Continue", QMessageBox::AcceptRole);
1736  msgBox.exec();
1737  }
1738  throw std::runtime_error("Creation of XY plot failed");
1739  }
1740 
1741  output->setTimeOffset(_time_offset);
1742  return output;
1743 }
1744 
1746  const QString& transform_ID)
1747 {
1749  output->setTransform(transform_ID);
1750  output->setTimeOffset(_time_offset);
1751  output->updateCache(true);
1752  return output;
1753 }
PlotWidget::_action_zoomOutVertically
QAction * _action_zoomOutVertically
Definition: plotwidget.h:175
PlotWidget::_action_zoomOutMaximum
QAction * _action_zoomOutMaximum
Definition: plotwidget.h:173
StatisticsDialog::calcVisibleRange
bool calcVisibleRange()
Definition: statistics_dialog.cpp:34
PlotWidget::canvasEventFilter
bool canvasEventFilter(QEvent *event)
Definition: plotwidget.cpp:1608
color
color
Definition: color.h:16
PJ::PlotWidgetBase::CurveInfo::marker
QwtPlotMarker * marker
Definition: plotwidget_base.h:44
PlotWidget::_action_image_to_clipboard
QAction * _action_image_to_clipboard
Definition: plotwidget.h:179
TimeScaleDraw
Definition: plotwidget.cpp:57
PlotWidget::on_zoomOutVertical_triggered
void on_zoomOutVertical_triggered(bool emit_signal=true)
Definition: plotwidget.cpp:1344
PlotWidget::_action_copy
QAction * _action_copy
Definition: plotwidget.h:177
QwtScaleDraw
A class for drawing scales.
Definition: qwt_scale_draw.h:35
PJ::PlotWidgetBase::curveList
const std::list< CurveInfo > & curveList() const
Definition: plotwidget_base.cpp:480
PlotWidget::createCurveXY
QwtSeriesWrapper * createCurveXY(const PlotData *data_x, const PlotData *data_y)
Definition: plotwidget.cpp:1717
sol::stack::top
int top(lua_State *L)
Definition: sol.hpp:11684
PlotWidget::_action_split_vertical
QAction * _action_split_vertical
Definition: plotwidget.h:170
PJ::TimeseriesBase
Definition: timeseries.h:16
plotwidget.h
QwtScaleMap::invTransform
double invTransform(double p) const
Definition: qwt_scale_map.h:154
suggest_dialog.h
LoadSvg
const QPixmap & LoadSvg(QString filename, QString style_name="light")
Definition: svg_util.h:26
PlotWidget::removeAllCurves
void removeAllCurves() override
Definition: plotwidget.cpp:461
QwtSeriesWrapper
Definition: timeseries_qwt.h:17
PlotWidget::configureTracker
void configureTracker(CurveTracker::Parameter val)
Definition: plotwidget.cpp:1036
QwtSeriesWrapper::updateCache
virtual void updateCache(bool reset_old_data)
Definition: timeseries_qwt.h:39
PlotwidgetEditor
Definition: plotwidget_editor.h:48
PJ::PlotWidgetBase::CurveInfo::src_name
std::string src_name
Definition: plotwidget_base.h:42
QwtPlotCurve::FilterPointsAggressive
@ FilterPointsAggressive
Definition: qwt_plot_curve.h:233
PlotWidget::_grid
QwtPlotGrid * _grid
Definition: plotwidget.h:185
PlotWidget::rescaleEqualAxisScaling
void rescaleEqualAxisScaling()
Definition: plotwidget.cpp:935
PJ::PlotWidgetBase::CurveInfo
Definition: plotwidget_base.h:40
PlotWidget::onDropEvent
void onDropEvent(QDropEvent *event)
Definition: plotwidget.cpp:532
PlotWidget::on_copyToClipboard
void on_copyToClipboard()
Definition: plotwidget.cpp:1485
GetSnippetsFromXML
SnippetsMap GetSnippetsFromXML(const QString &xml_text)
Definition: custom_function.cpp:132
qwt_plot_renderer.h
PlotWidget::curveListChanged
void curveListChanged()
PlotWidget::DragInfo::mode
enum PlotWidget::DragInfo::@33 mode
TransformedTimeseries::transform
TransformFunction::Ptr transform()
Definition: timeseries_qwt.cpp:77
PlotWidget::customAxisLimit
Range customAxisLimit() const
Definition: plotwidget.cpp:1480
PlotWidget::eventFilter
bool eventFilter(QObject *obj, QEvent *event) override
Definition: plotwidget.cpp:1548
PlotWidget::on_zoomOutHorizontal_triggered
void on_zoomOutHorizontal_triggered(bool emit_signal=true)
Definition: plotwidget.cpp:1333
QwtPlotGrid
A class which draws a coordinate grid.
Definition: qwt_plot_grid.h:33
QwtPlotGrid::enableXMin
void enableXMin(bool)
Enable or disable minor vertical grid lines.
Definition: qwt_plot_grid.cpp:108
arg
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1875
QwtPlotGrid::enableX
void enableX(bool)
Enable or disable vertical grid lines.
Definition: qwt_plot_grid.cpp:76
PlotWidget::setContextMenuEnabled
void setContextMenuEnabled(bool enabled)
Definition: plotwidget.cpp:139
SuggestDialog::nameX
QString nameX() const
Definition: suggest_dialog.cpp:32
QwtPlot::setAxisScale
void setAxisScale(QwtAxisId, double min, double max, double stepSize=0)
Disable autoscaling and specify a fixed scale for a selected axis.
Definition: qwt_plot_axis.cpp:477
PlotWidget::~PlotWidget
virtual ~PlotWidget() override
Definition: plotwidget.cpp:124
TransformedTimeseries
Definition: timeseries_qwt.h:74
PlotWidget::setModeXY
void setModeXY(bool enable) override
Definition: plotwidget.cpp:1355
PJ::PlotWidgetBase::curveStyle
CurveStyle curveStyle() const
Definition: plotwidget_base.cpp:499
PlotWidget::buildActions
void buildActions()
Definition: plotwidget.cpp:144
PlotWidget::_action_paste
QAction * _action_paste
Definition: plotwidget.h:178
PlotWidget::splitHorizontal
void splitHorizontal()
PlotWidget::setDefaultRangeX
void setDefaultRangeX()
Definition: plotwidget.cpp:1692
PlotWidget::setTrackerPosition
void setTrackerPosition(double abs_time)
Definition: plotwidget.cpp:1051
PlotWidget::_action_saveToFile
QAction * _action_saveToFile
Definition: plotwidget.h:176
PlotWidget::on_changeTimeOffset
void on_changeTimeOffset(double offset)
Definition: plotwidget.cpp:1074
PlotWidget::onDataSourceRemoved
void onDataSourceRemoved(const std::string &src_name)
Definition: plotwidget.cpp:425
StatisticsDialog::setTitle
void setTitle(QString title)
Definition: statistics_dialog.cpp:110
PlotWidget::onBackgroundColorRequest
void onBackgroundColorRequest(QString name)
Definition: plotwidget.cpp:1216
QwtPlotGrid::enableYMin
void enableYMin(bool)
Enable or disable minor horizontal grid lines.
Definition: qwt_plot_grid.cpp:124
PlotWidget::updateAvailableTransformers
void updateAvailableTransformers()
Definition: plotwidget.cpp:1383
QwtPlotGrid::enableY
void enableY(bool)
Enable or disable horizontal grid lines.
Definition: qwt_plot_grid.cpp:92
PlotWidget::activateGrid
void activateGrid(bool activate)
Definition: plotwidget.cpp:1027
PlotWidget
Definition: plotwidget.h:38
TimeScaleDraw::label
virtual QwtText label(double v) const
Convert a value into its representing label.
Definition: plotwidget.cpp:59
PJ::PlotDataMapRef::numeric
TimeseriesMap numeric
Numerical timeseries.
Definition: plotdata.h:39
PlotWidget::on_copyAction_triggered
void on_copyAction_triggered()
Definition: plotwidget.cpp:1512
PlotWidget::DragInfo::CURVES
@ CURVES
Definition: plotwidget.h:200
PlotWidget::_statistics_dialog
StatisticsDialog * _statistics_dialog
Definition: plotwidget.h:193
PlotWidget::_action_zoomOutHorizontally
QAction * _action_zoomOutHorizontally
Definition: plotwidget.h:174
PJ::PlotWidgetBase::keepRatioXY
bool keepRatioXY() const
Definition: plotwidget_base.cpp:504
PJ::PlotWidgetBase::getVisualizationRangeX
virtual PJ::Range getVisualizationRangeX() const
Definition: plotwidget_base.cpp:189
PJ::PlotWidgetBase::replot
void replot()
Definition: plotwidget_base.cpp:780
nonstd::span_lite::size
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.hpp:1554
MAX_DOUBLE
const double MAX_DOUBLE
Definition: plotwidget.cpp:70
QwtPlotCurve::ClipPolygons
@ ClipPolygons
Definition: qwt_plot_curve.h:185
CurveTracker::isEnabled
bool isEnabled() const
Definition: customtracker.cpp:74
detail::count
constexpr auto count() -> size_t
Definition: core.h:1222
PlotWidget::_action_split_horizontal
QAction * _action_split_horizontal
Definition: plotwidget.h:169
ColormapSelectorDialog
Definition: colormap_selector.h:17
PointSeriesXY
Definition: point_series_xy.h:12
PlotWidget::setZoomRectangle
void setZoomRectangle(QRectF rect, bool emit_signal)
Definition: plotwidget.cpp:964
PlotWidget::updateCurves
void updateCurves(bool reset_older_data)
Definition: plotwidget.cpp:1150
PlotWidget::addCurve
CurveInfo * addCurve(const std::string &name, QColor color=Qt::transparent)
Definition: plotwidget.cpp:393
custom_function.h
QwtPlot::setAxisScaleDraw
void setAxisScaleDraw(QwtAxisId, QwtScaleDraw *)
Set a scale draw.
Definition: qwt_plot_axis.cpp:536
PlotWidget::isZoomLinkEnabled
bool isZoomLinkEnabled() const
Definition: plotwidget.cpp:1595
CurveTracker::redraw
void redraw()
Definition: customtracker.h:45
PJ::PlotWidgetBase::setStyle
static void setStyle(QwtPlotCurve *curve, CurveStyle style)
Definition: plotwidget_base.cpp:698
qwt_scale_map.h
PlotWidget::on_changeCurveColor
void on_changeCurveColor(const QString &curve_name, QColor new_color)
Definition: plotwidget.cpp:1174
PlotWidget::datamap
PlotDataMapRef & datamap()
Definition: plotwidget.h:64
QwtText
A class representing a text.
Definition: qwt_text.h:51
qwt_date_scale_draw.h
output
static const char * output
Definition: luac.c:38
QwtSymbol
A class for drawing symbols.
Definition: qwt_symbol.h:31
PJ::PlotWidgetBase::curveFromTitle
CurveInfo * curveFromTitle(const QString &title)
Definition: plotwidget_base.cpp:737
CurveTracker::setEnabled
void setEnabled(bool enable)
Definition: customtracker.cpp:62
SuggestDialog
Definition: suggest_dialog.h:17
PlotWidget::onDragLeaveEvent
void onDragLeaveEvent(QDragLeaveEvent *event)
Definition: plotwidget.cpp:526
PlotWidget::enableTracker
void enableTracker(bool enable)
Definition: plotwidget.cpp:1041
QwtPlotRenderer
Renderer for exporting a plot to a document, a printer or anything else, that is supported by QPainte...
Definition: qwt_plot_renderer.h:39
PlotWidget::_tracker
CurveTracker * _tracker
Definition: plotwidget.h:184
PlotWidget::on_savePlotToFile
void on_savePlotToFile()
Definition: plotwidget.cpp:1394
StatisticsDialog
Definition: statistics_dialog.h:28
PJ::Range::max
double max
Definition: plotdatabase.h:27
PlotWidget::on_panned
void on_panned(int dx, int dy)
Definition: plotwidget.cpp:632
PJ::PlotDataMapRef::scatter_xy
ScatterXYMap scatter_xy
Definition: plotdata.h:36
PlotWidget::canvasContextMenuTriggered
void canvasContextMenuTriggered(const QPoint &pos)
Definition: plotwidget.cpp:230
PlotWidget::addCurveXY
CurveInfo * addCurveXY(std::string name_x, std::string name_y, QString curve_name="")
Definition: plotwidget.cpp:296
qwt_scale_draw.h
std::swap
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
qwt_plot_opengl_canvas.h
PlotWidget::updateStatistics
void updateStatistics(bool forceUpdate=false)
Definition: plotwidget.cpp:1162
CurveTracker
Definition: customtracker.h:18
plotwidget_transforms.h
PlotWidget::DragInfo::NONE
@ NONE
Definition: plotwidget.h:199
PlotWidget::_action_removeAllCurves
QAction * _action_removeAllCurves
Definition: plotwidget.h:166
plotlegend.h
PlotWidget::onShowDataStatistics
void onShowDataStatistics()
Definition: plotwidget.cpp:1275
QwtSymbol::Ellipse
@ Ellipse
Ellipse or circle.
Definition: qwt_symbol.h:44
PlotWidget::DragInfo::source
QObject * source
Definition: plotwidget.h:204
sol::meta::enable
std::enable_if_t< all< Args... >::value, enable_t > enable
Definition: sol.hpp:2244
statistics_dialog.h
PlotWidget::xmlLoadState
bool xmlLoadState(QDomElement &element, bool autozoom=true)
Definition: plotwidget.cpp:731
colormap_selector.h
PlotWidget::onDragEnterEvent
void onDragEnterEvent(QDragEnterEvent *event)
Definition: plotwidget.cpp:470
QwtPlotCurve::pen
const QPen & pen() const
Definition: qwt_plot_curve.cpp:330
PlotWidget::_dragging
DragInfo _dragging
Definition: plotwidget.h:207
QwtSeriesStore::data
QwtSeriesData< T > * data()
Definition: qwt_series_store.h:146
QwtPlot::axisScaleDraw
const QwtScaleDraw * axisScaleDraw(QwtAxisId) const
Return the scale draw of a specified axis.
Definition: qwt_plot_axis.cpp:298
QwtAxisId
int QwtAxisId
Axis identifier.
Definition: qwt_axis_id.h:26
PlotWidget::PlotWidget
PlotWidget(PlotDataMapRef &datamap, QWidget *parent)
Definition: plotwidget.cpp:74
PlotWidget::onFlipAxis
void onFlipAxis()
Definition: plotwidget.cpp:1191
QwtScaleMap
A scale map.
Definition: qwt_scale_map.h:26
PJ::Range
Definition: plotdatabase.h:24
PlotWidget::on_changeDateTimeScale
void on_changeDateTimeScale(bool enable)
Definition: plotwidget.cpp:1099
format
auto format(const text_style &ts, const S &format_str, const Args &... args) -> std::basic_string< Char >
Definition: color.h:543
CurveTracker::setPosition
void setPosition(const QPointF &pos)
Definition: customtracker.cpp:79
PlotWidget::_mapped_data
PlotDataMapRef & _mapped_data
Definition: plotwidget.h:86
QwtPlot::yLeft
@ yLeft
Definition: qwt_plot.h:240
PlotWidget::on_externallyResized
void on_externallyResized(const QRectF &new_rect)
Definition: plotwidget.cpp:1305
PJ::PlotWidgetBase::qwtPlot
QwtPlot * qwtPlot()
Definition: plotwidget_base.cpp:165
PlotWidget::undoableChange
void undoableChange()
ColorMapLibrary
std::map< QString, ColorMap::Ptr > & ColorMapLibrary()
Definition: color_map.cpp:48
PlotWidget::_statistics_window_title
QString _statistics_window_title
Definition: plotwidget.h:187
PlotWidget::_snippets
SnippetsMap _snippets
Definition: plotwidget.h:226
PlotWidget::getVisualizationRangeY
Range getVisualizationRangeY(Range range_X) const override
Definition: plotwidget.cpp:1122
PlotWidget::_use_date_time_scale
bool _use_date_time_scale
Definition: plotwidget.h:191
QwtTimeseries
Definition: timeseries_qwt.h:44
PlotWidget::setAxisScale
void setAxisScale(QwtAxisId axisId, double min, double max)
Definition: plotwidget.cpp:1575
PointSeriesXY::dataY
const PlotData * dataY() const
Definition: point_series_xy.h:37
PlotWidget::rectChanged
void rectChanged(PlotWidget *self, QRectF rect)
SuggestDialog::suggestedName
QString suggestedName() const
Definition: suggest_dialog.cpp:42
qwt_scale_engine.h
CurveTracker::setParameter
void setParameter(Parameter par)
Definition: customtracker.cpp:51
PlotWidget::_flip_y
QAction * _flip_y
Definition: plotwidget.h:182
PlotWidget::on_pasteAction_triggered
void on_pasteAction_triggered()
Definition: plotwidget.cpp:1524
if_xy_plot_failed_show_dialog
static bool if_xy_plot_failed_show_dialog
Definition: plotwidget.cpp:72
PlotWidgetBase
PlotWidget::_action_data_statistics
QAction * _action_data_statistics
Definition: plotwidget.h:171
PlotWidget::_time_offset
double _time_offset
Definition: plotwidget.h:220
PJ::PlotWidgetBase::CurveInfo::curve
QwtPlotCurve * curve
Definition: plotwidget_base.h:43
PJ::PlotWidgetBase::legend
PlotLegend * legend()
Definition: plotwidget_base.cpp:804
PlotWidget::DragInfo::NEW_XY
@ NEW_XY
Definition: plotwidget.h:201
PlotWidget::activateLegend
void activateLegend(bool activate)
Definition: plotwidget.cpp:1022
PlotWidget::_flip_x
QAction * _flip_x
Definition: plotwidget.h:181
PlotWidget::createTimeSeries
QwtSeriesWrapper * createTimeSeries(const PlotData *data, const QString &transform_ID={}) override
Definition: plotwidget.cpp:1745
PointSeriesXY::dataX
const PlotData * dataX() const
Definition: point_series_xy.h:33
plotzoomer.h
qwt_plot_canvas.h
PlotWidget::_background_item
std::unique_ptr< BackgroundColorItem > _background_item
Definition: plotwidget.h:189
PlotWidget::DragInfo::curves
std::vector< QString > curves
Definition: plotwidget.h:203
QwtPlotRenderer::render
virtual void render(QwtPlot *, QPainter *, const QRectF &plotRect) const
Definition: qwt_plot_renderer.cpp:482
PJ::PlotWidgetBase::maxZoomRect
QRectF maxZoomRect() const
Definition: plotwidget_base.cpp:299
PlotWidget::xmlSaveState
QDomElement xmlSaveState(QDomDocument &doc) const
Definition: plotwidget.cpp:637
B
#define B(name, bit)
PlotWidget::isTrackerEnabled
bool isTrackerEnabled() const
Definition: plotwidget.cpp:1046
mqtt_test.data
dictionary data
Definition: mqtt_test.py:22
qwt_scale_widget.h
PlotWidget::_action_formula
QAction * _action_formula
Definition: plotwidget.h:168
plotwidget_editor.h
plotmagnifier.h
PlotWidget::reloadPlotData
void reloadPlotData()
Definition: plotwidget.cpp:991
SuggestDialog::nameY
QString nameY() const
Definition: suggest_dialog.cpp:37
TransformedTimeseries::setTransform
void setTransform(QString transform_ID)
Definition: timeseries_qwt.cpp:82
QwtPlotMarker
A class for drawing markers.
Definition: qwt_plot_marker.h:45
QwtPlot::canvas
QWidget * canvas()
Definition: qwt_plot.cpp:463
PJ::PlotDataMapRef
Definition: plotdata.h:34
QwtPlot::xBottom
@ xBottom
Definition: qwt_plot.h:242
PJ::PlotWidgetBase::isXYPlot
bool isXYPlot() const
Definition: plotwidget_base.cpp:289
QwtPlotItem::setVisible
virtual void setVisible(bool)
Definition: qwt_plot_item.cpp:457
PJ::PlotWidgetBase::updateMaximumZoomArea
void updateMaximumZoomArea()
Definition: plotwidget_base.cpp:818
QwtPlot::setFooter
void setFooter(const QString &)
Definition: qwt_plot.cpp:372
PlotWidget::setStatisticsTitle
void setStatisticsTitle(QString title)
Definition: plotwidget.cpp:1265
CurveTracker::Parameter
Parameter
Definition: customtracker.h:28
QwtPlotItem::attach
void attach(QwtPlot *plot)
Attach the item to a plot.
Definition: qwt_plot_item.cpp:98
PlotWidget::zoomOut
void zoomOut(bool emit_signal)
Definition: plotwidget.cpp:1319
qwt_text.h
PlotWidget::_action_edit
QAction * _action_edit
Definition: plotwidget.h:167
PlotWidget::curvesDropped
void curvesDropped()
QwtPlot::canvasMap
virtual QwtScaleMap canvasMap(QwtAxisId) const
Definition: qwt_plot.cpp:800
QwtPlotItem::RenderAntialiased
@ RenderAntialiased
Enable antialiasing.
Definition: qwt_plot_item.h:206
StatisticsDialog::update
void update(Range range)
Definition: statistics_dialog.cpp:39
PJ::PlotWidgetBase::changeCurvesStyle
void changeCurvesStyle(CurveStyle style)
Definition: plotwidget_base.cpp:727
PlotWidget::splitVertical
void splitVertical()
PlotWidget::trackerMoved
void trackerMoved(QPointF pos)
PJ::PlotWidgetBase::getColorHint
QColor getColorHint(PlotDataXY *data)
Definition: plotwidget_base.cpp:627
ColormapSelectorDialog::selectedColorMap
QString selectedColorMap() const
Definition: colormap_selector.cpp:51
PlotWidget::overrideCursonMove
void overrideCursonMove()
Definition: plotwidget.cpp:1567
PlotWidget::removeCurve
void removeCurve(const QString &title) override
Definition: plotwidget.cpp:419
PlotWidget::_custom_Y_limits
Range _custom_Y_limits
Definition: plotwidget.h:222
mqtt_test.ret
ret
Definition: mqtt_test.py:30
PJ::Range::min
double min
Definition: plotdatabase.h:26
point_series_xy.h
nullptr
#define nullptr
Definition: backward.hpp:386
QwtPlotCurve
A plot item, that represents a series of points.
Definition: qwt_plot_curve.h:56
svg_util.h
qwt_plot_layout.h
qwt_series_data.h
PlotWidget::setCustomAxisLimits
void setCustomAxisLimits(Range range)
Definition: plotwidget.cpp:1473
PJ::PlotWidgetBase::currentBoundingRect
QRectF currentBoundingRect() const
Definition: plotwidget_base.cpp:294
PlotWidget::_context_menu_enabled
bool _context_menu_enabled
Definition: plotwidget.h:228
DialogTransformEditor
Definition: plotwidget_transforms.h:18
QwtPlot::updateAxes
void updateAxes()
Rebuild the axes scales.
Definition: qwt_plot_axis.cpp:670
PJ::PlotDataBase::plotName
const std::string & plotName() const
Definition: plotdatabase.h:168


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:45