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