Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
QmitkPlotWidget.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 <iostream>
14 #include <qlayout.h>
15 
16 #include <qwt_interval_symbol.h>
17 #include <qwt_point_data.h>
18 
19 #include "QmitkPlotWidget.h"
20 
21 QmitkPlotWidget::QmitkPlotWidget(QWidget *parent, const char *title, const char *, Qt::WindowFlags f)
22  : QWidget(parent, f)
23 {
24  auto boxLayout = new QVBoxLayout(this);
25  m_Plot = new QwtPlot(QwtText(title), this);
26  m_Plot->setCanvasBackground(Qt::white);
27  boxLayout->addWidget(m_Plot);
28 }
29 
31 {
32  this->Clear();
33  delete m_Plot;
34 }
35 
37 {
38  return m_Plot;
39 }
40 
41 void QmitkPlotWidget::SetLegend(QwtLegend *legend, QwtPlot::LegendPosition pos, double ratio)
42 {
43  m_Plot->insertLegend(legend, pos, ratio);
44 }
45 
46 void QmitkPlotWidget::SetLegendAttribute(unsigned int curveId, const QwtPlotCurve::LegendAttribute &attribute)
47 {
48  std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute(attribute);
49 }
50 
51 unsigned int QmitkPlotWidget::InsertCurve(const char *title, QColor color)
52 {
53  QwtText qwt_title = QwtText(title);
54  qwt_title.setColor(color);
55  qwt_title.setPaintAttribute(QwtText::PaintUsingTextColor);
56 
57  QwtPlotCurve *curve = new QwtPlotCurve(qwt_title);
58  QwtPlotIntervalCurve *xErrors = new QwtPlotIntervalCurve();
59  QwtPlotIntervalCurve *yErrors = new QwtPlotIntervalCurve();
60 
61  auto tuple = std::make_tuple(curve, xErrors, yErrors);
62  m_PlotCurveVector.push_back(tuple);
63 
64  std::get<0>(m_PlotCurveVector.back())->attach(m_Plot);
65  std::get<1>(m_PlotCurveVector.back())->attach(m_Plot);
66  std::get<2>(m_PlotCurveVector.back())->attach(m_Plot);
67 
68  // error curves should not show up on the legend
69  std::get<1>(m_PlotCurveVector.back())->setItemAttribute(QwtPlotItem::Legend, false);
70  std::get<2>(m_PlotCurveVector.back())->setItemAttribute(QwtPlotItem::Legend, false);
71 
72  return static_cast<unsigned int>(m_PlotCurveVector.size() - 1);
73 }
74 
75 void QmitkPlotWidget::SetPlotTitle(const QwtText &qwt_title)
76 {
77  this->m_Plot->setTitle(qwt_title);
78 }
79 
80 void QmitkPlotWidget::SetPlotTitle(const char *title)
81 {
82  QwtText qwt_title_text(title);
83  this->SetPlotTitle(qwt_title_text);
84 }
85 
86 void QmitkPlotWidget::SetAxisTitle(int axis, const char *title)
87 {
88  m_Plot->setAxisTitle(axis, title);
89 }
90 
91 bool QmitkPlotWidget::SetCurveData(unsigned int curveId,
92  const QmitkPlotWidget::DataVector &xValues,
93  const QmitkPlotWidget::DataVector &yValues)
94 {
95  if (xValues.size() != yValues.size())
96  {
97  std::cerr << "Sizes of data arrays don't match." << std::endl;
98  return false;
99  }
100  double *rawDataX = ConvertToRawArray(xValues);
101  double *rawDataY = ConvertToRawArray(yValues);
102  std::get<0>(m_PlotCurveVector[curveId])
103  ->setSamples(new QwtPointArrayData(rawDataX, rawDataY, static_cast<int>(xValues.size())));
104  delete[] rawDataX;
105  delete[] rawDataY;
106  return true;
107 }
108 
109 bool QmitkPlotWidget::SetCurveData(unsigned int curveId,
110  const DataVector &xValues,
111  const DataVector &yValues,
112  const DataVector &yLowerError,
113  const DataVector &yUpperError)
114 {
115  bool success = true;
116  success = success && this->SetCurveData(curveId, xValues, yValues);
117  success = success && this->AddErrorIntervalCurve(curveId, yLowerError, yUpperError, false);
118 
119  return success;
120 }
121 
122 bool QmitkPlotWidget::SetCurveData(unsigned int curveId,
123  const DataVector &xValues,
124  const DataVector &yValues,
125  const DataVector &xLowerError,
126  const DataVector &xUpperError,
127  const DataVector &yLowerError,
128  const DataVector &yUpperError)
129 {
130  bool success = true;
131  success = success && this->SetCurveData(curveId, xValues, yValues);
132  success = success && this->AddErrorIntervalCurve(curveId, xLowerError, xUpperError, true);
133  success = success && this->AddErrorIntervalCurve(curveId, yLowerError, yUpperError, false);
134 
135  return success;
136 }
137 
138 bool QmitkPlotWidget::SetCurveData(unsigned int curveId, const XYDataVector &data)
139 {
140  double *rawDataX = ConvertToRawArray(data, 0);
141  double *rawDataY = ConvertToRawArray(data, 1);
142  std::get<0>(m_PlotCurveVector[curveId])
143  ->setData(new QwtPointArrayData(rawDataX, rawDataY, static_cast<int>(data.size())));
144  delete[] rawDataX;
145  delete[] rawDataY;
146  return true;
147 }
148 
149 void QmitkPlotWidget::SetCurvePen(unsigned int curveId, const QPen &pen)
150 {
151  std::get<0>(m_PlotCurveVector[curveId])->setPen(pen);
152  std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute(QwtPlotCurve::LegendShowLine);
153 }
154 
155 void QmitkPlotWidget::SetCurveBrush(unsigned int curveId, const QBrush &brush)
156 {
157  std::get<0>(m_PlotCurveVector[curveId])->setBrush(brush);
158  std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute(QwtPlotCurve::LegendShowBrush);
159 }
160 
161 void QmitkPlotWidget::SetCurveTitle(unsigned int, const char *title)
162 {
163  m_Plot->setTitle(title);
164 }
165 
166 void QmitkPlotWidget::SetCurveStyle(unsigned int curveId, const QwtPlotCurve::CurveStyle style)
167 {
168  std::get<0>(m_PlotCurveVector[curveId])->setStyle(style);
169 }
170 
171 void QmitkPlotWidget::SetCurveSymbol(unsigned int curveId, QwtSymbol *symbol)
172 {
173  std::get<0>(m_PlotCurveVector[curveId])->setSymbol(symbol);
174  std::get<0>(m_PlotCurveVector[curveId])->setLegendAttribute(QwtPlotCurve::LegendShowSymbol);
175 }
176 
177 void QmitkPlotWidget::SetCurveAntialiasingOn(unsigned int curveId)
178 {
179  std::get<0>(m_PlotCurveVector[curveId])->setRenderHint(QwtPlotItem::RenderAntialiased);
180 }
181 
183 {
184  std::get<0>(m_PlotCurveVector[curveId])->setRenderHint(QwtPlotItem::RenderAntialiased, false);
185 }
186 
187 void QmitkPlotWidget::SetErrorPen(unsigned int curveId, const QPen &pen)
188 {
189  std::get<1>(m_PlotCurveVector[curveId])->setPen(pen);
190  QwtIntervalSymbol *errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
191  errorBar->setPen(pen);
192  std::get<1>(m_PlotCurveVector[curveId])->setSymbol(errorBar);
193  std::get<2>(m_PlotCurveVector[curveId])->setPen(pen);
194  errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
195  errorBar->setPen(pen);
196  std::get<2>(m_PlotCurveVector[curveId])->setSymbol(errorBar);
197 }
198 
199 void QmitkPlotWidget::SetErrorStyleSymbols(unsigned int curveId, bool drawSmybols)
200 {
201  if (drawSmybols)
202  {
203  std::get<1>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::NoCurve);
204  QwtIntervalSymbol *errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
205  errorBar->setPen(std::get<1>(m_PlotCurveVector[curveId])->pen());
206  std::get<1>(m_PlotCurveVector[curveId])->setSymbol(errorBar);
207  std::get<2>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::NoCurve);
208  errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
209  errorBar->setPen(std::get<2>(m_PlotCurveVector[curveId])->pen());
210  std::get<2>(m_PlotCurveVector[curveId])->setSymbol(errorBar);
211  }
212  else
213  {
214  std::get<1>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::Tube);
215  std::get<1>(m_PlotCurveVector[curveId])->setSymbol(nullptr);
216  std::get<2>(m_PlotCurveVector[curveId])->setStyle(QwtPlotIntervalCurve::Tube);
217  std::get<2>(m_PlotCurveVector[curveId])->setSymbol(nullptr);
218  }
219 }
220 
222 {
223  m_Plot->replot();
224 }
225 
227 {
228  m_Plot->detachItems();
229  m_PlotCurveVector.clear();
230  m_PlotCurveVector.resize(0);
231 }
232 
234 {
235  auto raw = new double[values.size()];
236  for (unsigned int i = 0; i < values.size(); ++i)
237  raw[i] = values[i];
238  return raw;
239 }
240 
241 double *QmitkPlotWidget::ConvertToRawArray(const QmitkPlotWidget::XYDataVector &values, unsigned int component)
242 {
243  auto raw = new double[values.size()];
244  for (unsigned int i = 0; i < values.size(); ++i)
245  {
246  switch (component)
247  {
248  case (0):
249  raw[i] = values[i].first;
250  break;
251  case (1):
252  raw[i] = values[i].second;
253  break;
254  default:
255  std::cout << "Component must be either 0 or 1." << std::endl;
256  }
257  }
258  return raw;
259 }
260 
261 bool QmitkPlotWidget::AddErrorIntervalCurve(unsigned int curveId,
262  const DataVector &lessError,
263  const DataVector &moreError,
264  bool isXError)
265 {
266  const QwtSeriesData<QPointF> *curveSeriesData = std::get<0>(this->m_PlotCurveVector[curveId])->data();
267 
268  size_t size = curveSeriesData->size();
269 
270  if (size != lessError.size() || size != moreError.size())
271  {
272  std::cerr << "Sizes of data arrays don't match." << std::endl;
273  return false;
274  }
275 
276  QVector<QwtIntervalSample> samples;
277  QwtIntervalSample *sample;
278  QwtPlotIntervalCurve *curve;
279 
280  if (isXError)
281  {
282  curve = std::get<1>(m_PlotCurveVector[curveId]);
283  }
284  else
285  {
286  curve = std::get<2>(m_PlotCurveVector[curveId]);
287  }
288 
289  for (unsigned int index = 0; index < size; ++index)
290  {
291  qreal xValue = curveSeriesData->sample(index).x();
292  qreal yValue = curveSeriesData->sample(index).y();
293  if (isXError)
294  {
295  sample = new QwtIntervalSample(xValue, xValue - lessError[index], xValue + moreError[index]);
296  }
297  else
298  {
299  sample = new QwtIntervalSample(xValue, yValue - lessError[index], yValue + moreError[index]);
300  }
301  samples.push_back(*sample);
302  }
303 
304  curve->setSamples(samples);
305  curve->setStyle(QwtPlotIntervalCurve::NoCurve);
306 
307  QwtIntervalSymbol *errorBar = new QwtIntervalSymbol(QwtIntervalSymbol::Bar);
308  errorBar->setPen(QPen(Qt::black));
309  curve->setSymbol(errorBar);
310 
311  if (isXError)
312  {
313  curve->setOrientation(Qt::Horizontal);
314  }
315  else
316  {
317  curve->setOrientation(Qt::Vertical);
318  }
319 
320  return true;
321 }
void SetPlotTitle(const QwtText &qwt_title)
std::vector< ScalarType > DataVector
std::vector< std::pair< double, double > > XYDataVector
void SetCurveAntialiasingOff(unsigned int curveId)
std::vector< std::tuple< QwtPlotCurve *, QwtPlotIntervalCurve *, QwtPlotIntervalCurve * > > m_PlotCurveVector
QwtPlot * GetPlot()
void SetCurveSymbol(unsigned int curveId, QwtSymbol *symbol)
void SetCurveStyle(unsigned int curveId, const QwtPlotCurve::CurveStyle style)
~QmitkPlotWidget() override
void SetCurveAntialiasingOn(unsigned int curveId)
void SetCurvePen(unsigned int curveId, const QPen &pen)
unsigned int InsertCurve(const char *title, QColor color=QColor(Qt::black))
void SetCurveTitle(unsigned int curveId, const char *title)
bool SetCurveData(unsigned int curveId, const DataVector &xValues, const DataVector &yValues)
QmitkPlotWidget(QWidget *parent=nullptr, const char *title=nullptr, const char *name=nullptr, Qt::WindowFlags f=nullptr)
void SetCurveBrush(unsigned int curveId, const QBrush &brush)
double * ConvertToRawArray(const DataVector &values)
bool AddErrorIntervalCurve(unsigned int curveId, const DataVector &lessError, const DataVector &moreError, bool isXError)
void SetAxisTitle(int axis, const char *title)
void SetLegendAttribute(unsigned int curveId, const QwtPlotCurve::LegendAttribute &attribute)
void SetLegend(QwtLegend *legend, QwtPlot::LegendPosition pos=QwtPlot::RightLegend, double ratio=-1)
void SetErrorStyleSymbols(unsigned int curveId, bool drawSmybols)
void SetErrorPen(unsigned int curveId, const QPen &pen)