Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkChartWidget.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include <regex>
14 
15 #include <QGridLayout>
16 #include <QWebChannel>
17 #include <QWebEngineSettings>
18 #include <QWebEngineView>
19 #include <QmitkChartWidget.h>
20 
21 #include "mitkExceptionMacro.h"
22 #include <QmitkChartData.h>
23 #include <QmitkChartxyData.h>
24 
25 class CustomPage : public QWebEnginePage
26 {
27 public:
28  CustomPage(QObject *parent = nullptr) : QWebEnginePage(parent) {}
29  virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/,
30  const QString &message,
31  int lineNumber,
32  const QString & /*sourceID*/) override
33  {
34  MITK_INFO << "JS > " << lineNumber << ": " << message.toStdString();
35  }
36 };
37 
38 class QmitkChartWidget::Impl final
39 {
40 public:
41  explicit Impl(QWidget *parent);
42  ~Impl();
43 
44  Impl(const Impl &) = delete;
45  Impl &operator=(const Impl &) = delete;
46 
47  void AddData1D(const std::vector<double> &data1D, const std::string &label, QmitkChartWidget::ChartType chartType);
48  void AddData2D(const std::vector< std::pair<double, double> > &data2D,
49  const std::string &label,
50  QmitkChartWidget::ChartType chartType);
51 
52  void AddChartExampleData(const std::vector< std::pair<double, double> >& data2D,
53  const std::string& label,
54  const std::string& type,
55  const std::string& color,
56  const std::string& style,
57  const std::string& pieLabelsData = 0);
58 
59  void UpdateData1D(const std::vector<double> &data1D, const std::string &label);
60  void UpdateData2D(const std::vector< std::pair<double, double> > &data2D, const std::string &label);
61  void UpdateChartExampleData(const std::vector< std::pair<double, double> >& data2D,
62  const std::string& label,
63  const std::string& type,
64  const std::string& color,
65  const std::string& lineStyle,
66  const std::string& pieLabelsData = 0);
67 
68  void RemoveData(const std::string &label);
69 
70  void UpdateLabel(const std::string &existingLabel, const std::string &newLabel);
71 
72  QmitkChartxyData* GetDataElementByLabel(const std::string& label) const;
73 
74  void ClearData();
75 
76  void SetColor(const std::string &label, const std::string &colorName);
77 
78  void SetLineStyle(const std::string &label, LineStyle style);
79 
80  void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol);
81 
82  void SetYAxisScale(AxisScale scale);
83 
84  void SetXAxisLabel(const std::string &label);
85 
86  void SetYAxisLabel(const std::string &label);
87 
88  void SetPieLabels(const std::vector<std::string> &pieLabels, const std::string &label);
89 
90  void SetTitle(const std::string &title);
91 
92  void SetXErrorBars(const std::string &label,
93  const std::vector<double> &errorPlus,
94  const std::vector<double> &errorMinus = std::vector<double>());
95  void SetYErrorBars(const std::string &label,
96  const std::vector<double> &errorPlus,
97  const std::vector<double> &errorMinus = std::vector<double>());
98  std::string GetThemeName() const;
99  void SetThemeName(ColorTheme style);
100 
101  void SetLegendPosition(LegendPosition position);
102 
103  void Show(bool showSubChart);
104 
105  void SetShowLegend(bool show);
106  void SetShowErrorBars(bool show);
107 
108  void SetStackedData(bool stacked);
109 
110  void SetShowDataPoints(bool showDataPoints = false);
111 
112  void SetShowSubchart(bool showSubChart);
113 
114  void SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType);
115 
116  void SetMinMaxValueXView(double minValueX, double maxValueX);
117  void SetMinMaxValueYView(double minValueY, double maxValueY);
118 
119  QList<QVariant> ConvertErrorVectorToQList(const std::vector<double> &error);
120  QList<QVariant> ConvertVectorToQList(const std::vector<std::string> &vec);
121 
122  std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const;
123 
124  void ClearJavaScriptChart();
125  void InitializeJavaScriptChart();
126  void CallJavaScriptFuntion(const QString &command);
127 
128  QSize sizeHint() const;
129 
130  void GetImageUrl();
131 
132 private:
133  using ChartxyDataVector = std::vector<std::unique_ptr<QmitkChartxyData>>;
134  std::string GetUniqueLabelName(const QList<QVariant> &labelList, const std::string &label) const;
135  QList<QVariant> GetDataLabels(const ChartxyDataVector &c3xyData) const;
136 
137  QWebChannel *m_WebChannel;
138  QWebEngineView *m_WebEngineView;
139 
140  QmitkChartData m_C3Data;
141  ChartxyDataVector m_C3xyData;
142  std::map<QmitkChartWidget::ChartType, std::string> m_ChartTypeToName;
143  std::map<QmitkChartWidget::ChartColor, std::string> m_ChartColorToName;
144  std::map<QmitkChartWidget::ColorTheme, std::string> m_ColorThemeToName;
145  std::map<QmitkChartWidget::LegendPosition, std::string> m_LegendPositionToName;
146  std::map<QmitkChartWidget::LineStyle, std::string> m_LineStyleToName;
147  std::map<QmitkChartWidget::MarkerSymbol, std::string> m_MarkerSymbolToName;
148  std::map<QmitkChartWidget::AxisScale, std::string> m_AxisScaleToName;
149 };
150 
151 QmitkChartWidget::Impl::Impl(QWidget *parent)
152  : m_WebChannel(new QWebChannel(parent)), m_WebEngineView(new QWebEngineView(parent))
153 {
154  // disable context menu for QWebEngineView
155  m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu);
156 
157  m_WebEngineView->setPage(new CustomPage());
158 
159  // Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated.
160 
161  m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html")));
162  m_WebEngineView->page()->setWebChannel(m_WebChannel);
163 
164  m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
165 
166  connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool)));
167  auto layout = new QGridLayout(parent);
168  layout->setMargin(0);
169  layout->addWidget(m_WebEngineView);
170  m_ChartTypeToName.emplace(ChartType::bar, "bar");
171  m_ChartTypeToName.emplace(ChartType::line, "line");
172  m_ChartTypeToName.emplace(ChartType::spline, "spline");
173  m_ChartTypeToName.emplace(ChartType::pie, "pie");
174  m_ChartTypeToName.emplace(ChartType::area, "area");
175  m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline");
176  m_ChartTypeToName.emplace(ChartType::scatter, "scatter");
177 
178  m_ChartColorToName.emplace(ChartColor::red, "red");
179  m_ChartColorToName.emplace(ChartColor::orange, "orange");
180  m_ChartColorToName.emplace(ChartColor::yellow, "yellow");
181  m_ChartColorToName.emplace(ChartColor::green, "green");
182  m_ChartColorToName.emplace(ChartColor::blue, "blue");
183  m_ChartColorToName.emplace(ChartColor::purple, "purple");
184  m_ChartColorToName.emplace(ChartColor::brown, "brown");
185  m_ChartColorToName.emplace(ChartColor::magenta, "magenta");
186  m_ChartColorToName.emplace(ChartColor::tan, "tan");
187  m_ChartColorToName.emplace(ChartColor::cyan, "cyan");
188  m_ChartColorToName.emplace(ChartColor::olive, "olive");
189  m_ChartColorToName.emplace(ChartColor::maroon, "maroon");
190  m_ChartColorToName.emplace(ChartColor::navy, "navy");
191  m_ChartColorToName.emplace(ChartColor::aquamarine, "aquamarine");
192  m_ChartColorToName.emplace(ChartColor::turqouise, "turqouise");
193  m_ChartColorToName.emplace(ChartColor::silver, "silver");
194  m_ChartColorToName.emplace(ChartColor::lime, "lime");
195  m_ChartColorToName.emplace(ChartColor::teal, "teal");
196  m_ChartColorToName.emplace(ChartColor::indigo, "indigo");
197  m_ChartColorToName.emplace(ChartColor::violet, "violet");
198  m_ChartColorToName.emplace(ChartColor::pink, "pink");
199  m_ChartColorToName.emplace(ChartColor::black, "black");
200  m_ChartColorToName.emplace(ChartColor::white, "white");
201  m_ChartColorToName.emplace(ChartColor::grey, "grey");
202 
203  m_LegendPositionToName.emplace(LegendPosition::bottomMiddle, "bottomMiddle");
204  m_LegendPositionToName.emplace(LegendPosition::bottomRight, "bottomRight");
205  m_LegendPositionToName.emplace(LegendPosition::topRight, "topRight");
206  m_LegendPositionToName.emplace(LegendPosition::topLeft, "topLeft");
207  m_LegendPositionToName.emplace(LegendPosition::middleRight, "middleRight");
208 
209  m_LineStyleToName.emplace(LineStyle::solid, "solid");
210  m_LineStyleToName.emplace(LineStyle::dashed, "dashed");
211 
212  m_MarkerSymbolToName.emplace(MarkerSymbol::circle, "circle");
213  m_MarkerSymbolToName.emplace(MarkerSymbol::cross, "cross");
214  m_MarkerSymbolToName.emplace(MarkerSymbol::diamond, "diamond");
215  m_MarkerSymbolToName.emplace(MarkerSymbol::pentagon, "pentagon");
216  m_MarkerSymbolToName.emplace(MarkerSymbol::square, "square");
217  m_MarkerSymbolToName.emplace(MarkerSymbol::star, "star");
218  m_MarkerSymbolToName.emplace(MarkerSymbol::x, "x");
219 
220  m_MarkerSymbolToName.emplace(MarkerSymbol::diamond_tall, "diamond-tall");
221  m_MarkerSymbolToName.emplace(MarkerSymbol::star_diamond, "star-diamond");
222  m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_up, "star-triangle-up");
223  m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_down, "star-triangle-down");
224  m_MarkerSymbolToName.emplace(MarkerSymbol::asterisk, "asterisk");
225  m_MarkerSymbolToName.emplace(MarkerSymbol::cross_thin, "cross-thin");
226  m_MarkerSymbolToName.emplace(MarkerSymbol::x_thin, "x-thin");
227 
228  m_AxisScaleToName.emplace(AxisScale::linear, "");
229  m_AxisScaleToName.emplace(AxisScale::log, "log");
230 
231  m_ColorThemeToName.emplace(ColorTheme::lightstyle, "light");
232  m_ColorThemeToName.emplace(ColorTheme::darkstyle, "dark");
233 }
234 
235 QmitkChartWidget::Impl::~Impl() {}
236 
237 std::string QmitkChartWidget::Impl::GetThemeName() const
238 {
239  return m_C3Data.GetThemeName().toString().toStdString();
240 }
241 
242 std::string CheckForCorrectHex(const std::string &colorName)
243 {
244  std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})");
245  std::smatch match;
246 
247  if (!colorName.empty() && colorName.at(0) != '#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx))
248  {
249  return "#" + colorName;
250  }
251  else
252  {
253  return colorName;
254  }
255 }
256 
257 void QmitkChartWidget::Impl::GetImageUrl()
258 {
259  m_C3Data.EmitSignalImageUrl();
260 }
261 
262 void QmitkChartWidget::Impl::AddData1D(const std::vector<double> &data1D,
263  const std::string &label,
265 {
266  std::vector< std::pair<double, double> > transformedData2D;
267  unsigned int count = 0;
268  // transform the 1D data to 2D data
269  for (const auto &ele : data1D)
270  {
271  transformedData2D.emplace_back(count, ele);
272  count++;
273  }
274 
275  AddData2D(transformedData2D, label, type);
276 }
277 
278 void QmitkChartWidget::Impl::AddData2D(const std::vector< std::pair<double, double> > &data2D,
279  const std::string &label,
281 {
282  const std::string chartTypeName(m_ChartTypeToName.at(type));
283 
284  auto definedLabels = GetDataLabels(m_C3xyData);
285  auto uniqueLabel = GetUniqueLabelName(definedLabels, label);
286 
287  unsigned int sizeOfC3xyData = static_cast<unsigned int>(m_C3xyData.size());
288  m_C3xyData.push_back(std::make_unique<QmitkChartxyData>(data2D,
289  QVariant(QString::fromStdString(uniqueLabel)),
290  QVariant(QString::fromStdString(chartTypeName)),
291  QVariant(sizeOfC3xyData)));
292 }
293 
294 void QmitkChartWidget::Impl::AddChartExampleData(const std::vector< std::pair<double, double> >& data2D,
295  const std::string& label,
296  const std::string& type,
297  const std::string& color,
298  const std::string& lineStyle,
299  const std::string& pieLabelsData)
300 {
301  auto definedLabels = GetDataLabels(m_C3xyData);
302  auto uniqueLabel = GetUniqueLabelName(definedLabels, label);
303  if (type == "scatter")
304  {
305  SetShowDataPoints(true);
306  MITK_INFO << "Enabling data points for all because of scatter plot";
307  }
308  unsigned int sizeOfC3xyData = static_cast<unsigned int>(m_C3xyData.size());
309 
310  std::unique_ptr<QmitkChartxyData> chartData =
311  std::make_unique<QmitkChartxyData>(
312  data2D,
313  QVariant(QString::fromStdString(uniqueLabel)),
314  QVariant(QString::fromStdString(type)),
315  QVariant(sizeOfC3xyData));
316 
317  chartData->SetColor(QVariant(QString::fromStdString(color)));
318  chartData->SetLineStyle(QVariant(QString::fromStdString(lineStyle)));
319 
320  if (pieLabelsData != "")
321  {
322  std::string pieLabelsDataWorkingString = pieLabelsData;
323 
324  QList<QVariant> pieLabelsDataList;
325  while (pieLabelsDataWorkingString.size() != 0)
326  {
327  QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";")));
328  pieLabelsDataList.push_back(oneElement);
329 
330  if (pieLabelsDataWorkingString.find(";") != std::string::npos)
331  {
332  pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1);
333  }
334  else
335  {
336  pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end());
337  }
338  }
339 
340  chartData->SetPieLabels(pieLabelsDataList);
341  }
342 
343  m_C3xyData.push_back(std::move(chartData));
344 }
345 
346 void QmitkChartWidget::Impl::UpdateData1D(const std::vector<double> &data1D, const std::string &label)
347 {
348  std::vector< std::pair<double, double> > transformedData2D;
349  unsigned int count = 0;
350  // transform the 1D data to 2D data
351  for (const auto &ele : data1D)
352  {
353  transformedData2D.emplace_back( count, ele );
354  count++;
355  }
356 
357  UpdateData2D(transformedData2D, label);
358 }
359 
360 void QmitkChartWidget::Impl::UpdateData2D(const std::vector< std::pair<double, double> > &data2D, const std::string &label)
361 {
362  auto element = GetDataElementByLabel(label);
363  if (element)
364  element->SetData(data2D);
365 }
366 
367 void QmitkChartWidget::Impl::UpdateChartExampleData(const std::vector< std::pair<double, double> >& data2D,
368  const std::string& label,
369  const std::string& type,
370  const std::string& color,
371  const std::string& lineStyle,
372  const std::string& pieLabelsData)
373 {
374  UpdateData2D(data2D, label);
375 
376  auto element = GetDataElementByLabel(label);
377  if (element)
378  {
379  element->SetChartType(QString::fromStdString(type));
380  element->SetColor(QString::fromStdString(color));
381  element->SetLineStyle(QString::fromStdString(lineStyle));
382 
383  if (pieLabelsData != "")
384  {
385  std::string pieLabelsDataWorkingString = pieLabelsData;
386 
387  QList<QVariant> pieLabelsDataList;
388  while (pieLabelsDataWorkingString.size() != 0)
389  {
390  QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";")));
391  pieLabelsDataList.push_back(oneElement);
392 
393  if (pieLabelsDataWorkingString.find(";") != std::string::npos)
394  {
395  pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1);
396  }
397  else
398  {
399  pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end());
400  }
401  }
402 
403  element->SetPieLabels(pieLabelsDataList);
404  }
405  }
406 }
407 
408 void QmitkChartWidget::Impl::RemoveData(const std::string &label)
409 {
410  for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter)
411  {
412  if ((*iter)->GetLabel().toString().toStdString() == label)
413  {
414  m_C3xyData.erase(iter);
415  return;
416  }
417  }
418 
419  throw std::invalid_argument("Cannot Remove Data because the label does not exist.");
420 }
421 
422 void QmitkChartWidget::Impl::ClearData()
423 {
424  for (auto &xyData : m_C3xyData)
425  {
426  m_WebChannel->deregisterObject(xyData.get());
427  }
428 
429  m_C3xyData.clear();
430 }
431 
432 void QmitkChartWidget::Impl::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) {
433  auto element = GetDataElementByLabel(existingLabel);
434  if (element)
435  {
436  auto definedLabels = GetDataLabels(m_C3xyData);
437  auto uniqueLabel = GetUniqueLabelName(definedLabels, newLabel);
438  element->SetLabel(QString::fromStdString(uniqueLabel));
439  }
440 }
441 
442 void QmitkChartWidget::Impl::SetColor(const std::string &label, const std::string &colorName)
443 {
444  auto element = GetDataElementByLabel(label);
445  if (element)
446  {
447  auto colorChecked = CheckForCorrectHex(colorName);
448  element->SetColor(QVariant(QString::fromStdString(colorChecked)));
449  }
450 }
451 
452 void QmitkChartWidget::Impl::SetLineStyle(const std::string &label, LineStyle style)
453 {
454  auto element = GetDataElementByLabel(label);
455  const std::string lineStyleName(m_LineStyleToName.at(style));
456  element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName)));
457 }
458 
459 void QmitkChartWidget::Impl::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol)
460 {
461  auto element = GetDataElementByLabel(label);
462  const std::string markerSymbolName(m_MarkerSymbolToName.at(symbol));
463  element->SetMarkerSymbol(QVariant(QString::fromStdString(markerSymbolName)));
464 }
465 
466 void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale)
467 {
468  const std::string axisScaleName(m_AxisScaleToName.at(scale));
469  m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName));
470 }
471 
472 QmitkChartxyData *QmitkChartWidget::Impl::GetDataElementByLabel(const std::string &label) const
473 {
474  for (const auto &qmitkChartxyData : m_C3xyData)
475  {
476  if (qmitkChartxyData->GetLabel().toString() == label.c_str())
477  {
478  return qmitkChartxyData.get();
479  }
480  }
481  return nullptr;
482 }
483 
484 QList<QVariant> QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector &c3xyData) const
485 {
486  QList<QVariant> dataLabels;
487  for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element)
488  {
489  dataLabels.push_back((*element)->GetLabel());
490  }
491  return dataLabels;
492 }
493 
494 void QmitkChartWidget::Impl::SetXAxisLabel(const std::string &label)
495 {
496  m_C3Data.SetXAxisLabel(QString::fromStdString(label));
497 }
498 
499 void QmitkChartWidget::Impl::SetYAxisLabel(const std::string &label)
500 {
501  m_C3Data.SetYAxisLabel(QString::fromStdString(label));
502 }
503 
504 void QmitkChartWidget::Impl::SetPieLabels(const std::vector<std::string> &pieLabels, const std::string &label)
505 {
506  auto element = GetDataElementByLabel(label);
507  if (element)
508  {
509  if (element->GetChartType() == QVariant("pie"))
510  {
511  auto dataY = element->GetYData();
512  element->SetPieLabels(ConvertVectorToQList(pieLabels));
513  if (static_cast<unsigned>(dataY.size()) != pieLabels.size())
514  {
515  MITK_INFO << "data has " << dataY.size() << " entries whereas pie labels have " << pieLabels.size()
516  << " entries. Unnamed pie labels automatically get a numerical label.";
517  }
518  }
519  else
520  {
521  MITK_INFO << "label" << label << "has chart type " << element->GetChartType().toString().toStdString() << ", but pie is required";
522  }
523  }
524 }
525 
526 void QmitkChartWidget::Impl::SetTitle(const std::string &title)
527 {
528  m_C3Data.SetTitle(QString::fromStdString(title));
529 }
530 
531 void QmitkChartWidget::Impl::SetThemeName(QmitkChartWidget::ColorTheme style)
532 {
533  const std::string themeName(m_ColorThemeToName.at(style));
534  m_C3Data.SetThemeName(QString::fromStdString(themeName));
535 }
536 
537 void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition)
538 {
539  const std::string legendPositionName(m_LegendPositionToName.at(legendPosition));
540  m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName));
541 }
542 
543 void QmitkChartWidget::Impl::Show(bool showSubChart)
544 {
545  if (m_C3xyData.empty())
546  {
547  MITK_WARN << "no data available for display in chart";
548  }
549 
550  else
551  {
552  m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie"));
553  }
554 
555  InitializeJavaScriptChart();
556 }
557 
558 void QmitkChartWidget::Impl::SetShowLegend(bool show)
559 {
560  m_C3Data.SetShowLegend(show);
561 }
562 
563 void QmitkChartWidget::Impl::SetStackedData(bool stacked)
564 {
565  m_C3Data.SetStackedData(stacked);
566 }
567 
568 void QmitkChartWidget::Impl::SetShowErrorBars(bool show)
569 {
570  m_C3Data.SetShowErrorBars(show);
571 }
572 
573 void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints)
574 {
575  if (showDataPoints == true)
576  {
577  m_C3Data.SetDataPointSize(6.5);
578  }
579  else
580  {
581  m_C3Data.SetDataPointSize(0);
582  }
583 }
584 
585 void QmitkChartWidget::Impl::SetShowSubchart(bool showSubChart) {
586  m_C3Data.SetShowSubchart(showSubChart);
587 }
588 
589 void QmitkChartWidget::Impl::SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType)
590 {
591  auto element = GetDataElementByLabel(label);
592  if (element)
593  {
594  if (chartType == ChartType::scatter)
595  {
596  SetShowDataPoints(true);
597  MITK_INFO << "Enabling data points for all because of scatter plot";
598  }
599  const std::string chartTypeName(m_ChartTypeToName.at(chartType));
600  element->SetChartType(QVariant(QString::fromStdString(chartTypeName)));
601  }
602 }
603 
604 void QmitkChartWidget::Impl::SetMinMaxValueXView(double minValueX, double maxValueX) {
605  m_C3Data.SetMinValueXView(minValueX);
606  m_C3Data.SetMaxValueXView(maxValueX);
607 }
608 
609 void QmitkChartWidget::Impl::SetMinMaxValueYView(double minValueY, double maxValueY) {
610  m_C3Data.SetMinValueYView(minValueY);
611  m_C3Data.SetMaxValueYView(maxValueY);
612 }
613 
614 QList<QVariant> QmitkChartWidget::Impl::ConvertErrorVectorToQList(const std::vector<double> &error)
615 {
616  QList<QVariant> errorConverted;
617  for (const auto &aValue : error)
618  {
619  errorConverted.append(aValue);
620  }
621 
622  return errorConverted;
623 }
624 
625 QList<QVariant> QmitkChartWidget::Impl::ConvertVectorToQList(const std::vector<std::string> &vec)
626 {
627  QList<QVariant> vecConverted;
628  for (const auto &aValue : vec)
629  {
630  vecConverted.append(QString::fromStdString(aValue));
631  }
632 
633  return vecConverted;
634 }
635 
636 void QmitkChartWidget::Impl::SetXErrorBars(const std::string &label,
637  const std::vector<double> &errorPlus,
638  const std::vector<double> &errorMinus)
639 {
640  auto element = GetDataElementByLabel(label);
641  if (element)
642  {
643  auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus);
644  auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus);
645 
646  element->SetXErrorDataPlus(errorConvertedPlus);
647  element->SetXErrorDataMinus(errorConvertedMinus);
648  }
649 }
650 
651 void QmitkChartWidget::Impl::SetYErrorBars(const std::string &label,
652  const std::vector<double> &errorPlus,
653  const std::vector<double> &errorMinus)
654 {
655  auto element = GetDataElementByLabel(label);
656  if (element)
657  {
658  auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus);
659  auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus);
660 
661  element->SetYErrorDataPlus(errorConvertedPlus);
662  element->SetYErrorDataMinus(errorConvertedMinus);
663  }
664 }
665 
666 std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const
667 {
668  return m_ChartTypeToName.at(chartType);
669 }
670 
671 QSize QmitkChartWidget::Impl::sizeHint() const
672 {
673  return QSize(400, 300);
674 }
675 
676 void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString &command)
677 {
678  m_WebEngineView->page()->runJavaScript(command);
679 }
680 
681 void QmitkChartWidget::Impl::ClearJavaScriptChart()
682 {
683  m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html")));
684 }
685 
686 void QmitkChartWidget::Impl::InitializeJavaScriptChart()
687 {
688  auto alreadyRegisteredObjects = m_WebChannel->registeredObjects();
689  auto alreadyRegisteredObjectsValues = alreadyRegisteredObjects.values();
690  // only register objects that have not been registered yet
691  if (alreadyRegisteredObjectsValues.indexOf(&m_C3Data) == -1)
692  {
693  m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data);
694  }
695 
696  unsigned count = 0;
697  for (auto &xyData : m_C3xyData)
698  {
699  // only register objects that have not been registered yet
700  if (alreadyRegisteredObjectsValues.indexOf(xyData.get()) == -1)
701  {
702  QString variableName = "xyData" + QString::number(count);
703  m_WebChannel->registerObject(variableName, xyData.get());
704  }
705  count++;
706  }
707 
708  m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/QmitkChartWidget.html")));
709 }
710 
711 std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList<QVariant> &labelList, const std::string &label) const
712 {
713  QString currentLabel = QString::fromStdString(label);
714  int counter = 0;
715  while (labelList.contains(currentLabel))
716  {
717  currentLabel = QString::fromStdString(label + std::to_string(counter));
718  counter++;
719  }
720  return currentLabel.toStdString();
721 }
722 
723 QmitkChartWidget::QmitkChartWidget(QWidget *parent) : QWidget(parent), m_Impl(new Impl(this))
724 {
726 }
727 
729 void QmitkChartWidget::SetColor(const std::string &label, const std::string &colorName)
730 {
731  m_Impl->SetColor(label, colorName);
732 }
733 
734 void QmitkChartWidget::SetLineStyle(const std::string &label, LineStyle style)
735 {
736  m_Impl->SetLineStyle(label, style);
737 }
738 
739 void QmitkChartWidget::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol)
740 {
741  m_Impl->SetMarkerSymbol(label, symbol);
742 }
743 
745 {
746  m_Impl->SetYAxisScale(scale);
747 }
748 
749 void QmitkChartWidget::AddData1D(const std::vector<double> &data1D, const std::string &label, ChartType type)
750 {
751  m_Impl->AddData1D(data1D, label, type);
752 }
753 
754 void QmitkChartWidget::AddData2D(const std::vector< std::pair<double, double> >& data2D, const std::string& label, ChartType type)
755 {
756  m_Impl->AddData2D(data2D, label, type);
757 }
758 
759 void QmitkChartWidget::AddChartExampleData(const std::vector< std::pair<double, double> >& data2D,
760  const std::string& label,
761  const std::string& type,
762  const std::string& color,
763  const std::string& lineStyle,
764  const std::string& pieLabelsData)
765 {
766  m_Impl->AddChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData);
767 }
768 
769 void QmitkChartWidget::UpdateData1D(const std::vector<double> &data1D, const std::string &label)
770 {
771  m_Impl->UpdateData1D(data1D, label);
772 }
773 
774 void QmitkChartWidget::UpdateData2D(const std::vector< std::pair<double, double> > &data2D, const std::string &label)
775 {
776  m_Impl->UpdateData2D(data2D, label);
777 }
778 
779 void QmitkChartWidget::UpdateChartExampleData(const std::vector< std::pair<double, double> >& data2D,
780  const std::string& label,
781  const std::string& type,
782  const std::string& color,
783  const std::string& lineStyle,
784  const std::string& pieLabelsData)
785 {
786  m_Impl->UpdateChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData);
787 }
788 
789 void QmitkChartWidget::RemoveData(const std::string &label)
790 {
791  m_Impl->RemoveData(label);
792 }
793 
794 void QmitkChartWidget::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) {
795  m_Impl->UpdateLabel(existingLabel, newLabel);
796 }
797 
799 {
800  return m_Impl->GetDataElementByLabel(label);
801 }
802 
803 void QmitkChartWidget::SetXAxisLabel(const std::string &label)
804 {
805  m_Impl->SetXAxisLabel(label);
806 }
807 
808 void QmitkChartWidget::SetYAxisLabel(const std::string &label)
809 {
810  m_Impl->SetYAxisLabel(label);
811 }
812 
813 void QmitkChartWidget::SetPieLabels(const std::vector<std::string> &pieLabels, const std::string &label)
814 {
815  m_Impl->SetPieLabels(pieLabels, label);
816 }
817 
818 void QmitkChartWidget::SetTitle(const std::string &title)
819 {
820  m_Impl->SetTitle(title);
821 }
822 
823 void QmitkChartWidget::SetShowDataPoints(bool showDataPoints)
824 {
825  m_Impl->SetShowDataPoints(showDataPoints);
826 }
827 
828 void QmitkChartWidget::SetChartType(const std::string &label, ChartType type)
829 {
830  m_Impl->SetChartType(label, type);
831 }
832 
833 void QmitkChartWidget::SetXErrorBars(const std::string &label,
834  const std::vector<double> &errorPlus,
835  const std::vector<double> &errorMinus)
836 {
837  m_Impl->SetXErrorBars(label, errorPlus, errorMinus);
838 }
839 
840 void QmitkChartWidget::SetYErrorBars(const std::string &label,
841  const std::vector<double> &errorPlus,
842  const std::vector<double> &errorMinus)
843 {
844  m_Impl->SetYErrorBars(label, errorPlus, errorMinus);
845 }
846 
848 {
849  m_Impl->SetLegendPosition(position);
850 }
851 
853 {
854  m_Impl->SetShowLegend(show);
855 }
856 
858 {
859  m_Impl->SetStackedData(stacked);
860 }
861 
862 void QmitkChartWidget::Show(bool showSubChart)
863 {
864  m_Impl->Show(showSubChart);
865 }
866 
868 {
869  m_Impl->ClearData();
870  m_Impl->ClearJavaScriptChart();
871 }
872 
873 void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful)
874 {
875  if (isLoadSuccessful)
876  {
877  emit PageSuccessfullyLoaded();
878  }
879 }
880 
882 {
883  auto themeName = m_Impl->GetThemeName();
884  QString command;
885  if (themeName == "dark")
886  {
887  command = QString("changeTheme('dark')");
888  }
889  else
890  {
891  command = QString("changeTheme('light')");
892  }
893 
894  m_Impl->CallJavaScriptFuntion(command);
895 }
896 
898 {
899  m_Impl->SetThemeName(themeEnabled);
900 }
901 
902 void QmitkChartWidget::SetShowSubchart(bool showSubChart)
903 {
904  m_Impl->SetShowSubchart(showSubChart);
905 }
906 
907 void QmitkChartWidget::SetShowErrorBars(bool showErrorBars)
908 {
909  m_Impl->SetShowErrorBars(showErrorBars);
910 }
911 
912 void QmitkChartWidget::SetMinMaxValueXView(double minValueX, double maxValueX)
913 {
914  m_Impl->SetMinMaxValueXView(minValueX, maxValueX);
915 }
916 
917 void QmitkChartWidget::SetMinMaxValueYView(double minValueY, double maxValueY)
918 {
919  m_Impl->SetMinMaxValueYView(minValueY, maxValueY);
920 }
921 
923 {
924  const QString command = QString("Reload()");
925  m_Impl->CallJavaScriptFuntion(command);
926 }
927 
929 {
930  return m_Impl->sizeHint();
931 }
932 
934 {
935  m_Impl->GetImageUrl();
936 }
void SetLineStyle(const std::string &label, LineStyle style)
Sets the line style of one data entry (identifier is previously assigned label)
void Reload()
Reloads the chart in the widget.
void SetShowSubchart(bool showSubChart)
Sets whether the subchart shall be shown.
static char * line
Definition: svm.cpp:2870
This class holds the relevant properties for the chart generation with C3 such as labels and diagram ...
void SetTitle(const std::string &title)
Sets a title for the chart.
#define MITK_INFO
Definition: mitkLogMacros.h:18
void AddData1D(const std::vector< double > &data1D, const std::string &label, ChartType chartType=ChartType::bar)
Adds 1D data to the widget.
QmitkChartxyData * GetDataElementByLabel(const std::string &label) const
double square(double a)
void SetLegendPosition(LegendPosition position)
Sets the legend position.
void AddChartExampleData(const std::vector< std::pair< double, double > > &data2D, const std::string &label, const std::string &type, const std::string &color, const std::string &style, const std::string &pieLabelsData=0)
ChartType
enum of diagram types.
ColorTheme
enum of chart style (modifies background and line color).
QSize sizeHint() const override
void UpdateData1D(const std::vector< double > &data1D, const std::string &label)
Updates data of an existing label.
void SetColor(const std::string &label, const std::string &colorName)
Sets the color of one data entry (identifier is previously assigned label)
void SetXErrorBars(const std::string &label, const std::vector< double > &errorPlus, const std::vector< double > &errorMinus=std::vector< double >())
Sets error bars for data in x direction.
void UpdateChartExampleData(const std::vector< std::pair< double, double > > &data2D, const std::string &label, const std::string &type, const std::string &color, const std::string &lineStyle, const std::string &pieLabelsData=0)
Adds 2D data to the widget. Call repeatedly for displaying multiple charts.
void SetChartType(const std::string &label, ChartType type)
Sets the chart type for a data entry.
void SetMinMaxValueXView(double minValueX, double maxValueX)
Sets the min and max x values of the chart.
QmitkChartWidget(QWidget *parent=nullptr)
void UpdateLabel(const std::string &existingLabel, const std::string &newLabel)
Q_INVOKABLE void SetPieLabels(const QList< QVariant > &pieLabels)
void Show(bool showSubChart=false)
Displays the chart in the widget.
#define MITK_WARN
Definition: mitkLogMacros.h:19
void SetShowDataPoints(bool showDataPoints)
Either displays the dataPoints or not.
void Clear()
Clears all data inside and resets the widget.
void SetTheme(ColorTheme themeEnabled)
Sets the theme of the widget.
std::string CheckForCorrectHex(const std::string &colorName)
void SetYAxisLabel(const std::string &label)
void SetPieLabels(const std::vector< std::string > &pieLabels, const std::string &label)
Sets labels for pie chart data.
void AddData2D(const std::vector< std::pair< double, double > > &data2D, const std::string &label, ChartType chartType=ChartType::bar)
Q_INVOKABLE void SetLineStyle(const QVariant &lineStyle)
void OnLoadFinished(bool isLoadSuccessful)
void UpdateData2D(const std::vector< std::pair< double, double > > &data2D, const std::string &label)
void SetMinMaxValueYView(double minValueY, double maxValueY)
Sets the min and max y values of the chart.
void SetYErrorBars(const std::string &label, const std::vector< double > &errorPlus, const std::vector< double > &errorMinus=std::vector< double >())
Sets error bars for data in y direction.
void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol)
Sets the marker style of one data entry (identifier is previously assigned label) ...
void RemoveData(const std::string &label)
Removes data from the widget, works for 1D and 2D Data.
void SetStackedData(bool stacked)
LegendPosition
enum of legend position. See https://plot.ly/javascript/legend/
void SetShowLegend(bool show)
void SetXAxisLabel(const std::string &label)
void SetYAxisScale(AxisScale scale)
Sets the axis scale to either linear (default) or logarithmic.
void PageSuccessfullyLoaded()
~QmitkChartWidget() override
void SetShowErrorBars(bool showErrorBars)
Sets whether the error bars shall be shown.
Q_INVOKABLE void SetColor(const QVariant &color)