All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
HistogramChart.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2010-2013 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file HistogramChart.cpp
22 
23  \brief A class to represent a histogram chart.
24 */
25 
26 //Terralib
27 #include "../../../dataaccess/dataset/ObjectId.h"
28 #include "../../../dataaccess/dataset/ObjectIdSet.h"
29 #include "../../../qt/widgets/se/Utils.h"
30 #include "../../../se/Stroke.h"
31 #include "Enums.h"
32 #include "Histogram.h"
33 #include "HistogramChart.h"
34 #include "HistogramStyle.h"
35 #include "StringScaleDraw.h"
36 
37 
38 //QT
39 #include <qbrush.h>
40 #include <qpen.h>
41 
42 //QWT
43 #include <qwt_column_symbol.h>
44 #include <qwt_plot.h>
45 
46 //STL
47 #include <limits>
48 
50  QwtPlotHistogram(),
51  m_histogram(histogram),
52  m_histogramStyle(style)
53 {
54 
55  //Vector that will be populated by the histogram's data
56  QVector<QwtIntervalSample> samples;
57 
58  if(!m_histogramStyle)
59  {
61  QPen barPen;
62  QBrush barBrush;
63 
66  barBrush.setStyle(Qt::SolidPattern);
67 
68  setPen(barPen);
69  setBrush(barBrush);
70  }
71 
72  if((histogram->getType() >= te::dt::INT16_TYPE && histogram->getType() <= te::dt::UINT64_TYPE) ||
73  histogram->getType() == te::dt::FLOAT_TYPE || histogram->getType() == te::dt::DOUBLE_TYPE ||
74  histogram->getType() == te::dt::NUMERIC_TYPE)
75  {
76  std::map<double, unsigned int> values;
77  values = histogram->getValues();
78 
79  std::map<double, unsigned int>::const_iterator it;
80  it = values.begin();
81 
82  std::map<int, unsigned int> vmap;
83 
84  int i = 0;
85 
86  double ini = histogram->getMinValue();
87 
88  double vx = ini + histogram->getInterval();
89 
90  while(vx <= values.rbegin()->first)
91  {
92  vmap[i] = 0;
93  if(fabs(vx) < 0.000000000001)
94  vx = 0.;
95  while(it != values.end())
96  {
97  if(it->first >= ini && it->first < vx)
98  vmap[i] += it->second;
99  else
100  break;
101  ++it;
102  }
103 
104  QwtInterval qinterval(ini, vx);
105  qinterval.setBorderFlags(QwtInterval::ExcludeMaximum);
106  samples.push_back(QwtIntervalSample(vmap[i], qinterval));
107 
108  ini = vx;
109  vx += histogram->getInterval();
110  ++i;
111  }
112 
113  setData(new QwtIntervalSeriesData(samples));
114  }
115 
116  else if (histogram->getType() == te::dt::DATETIME_TYPE || histogram->getType() == te::dt::STRING_TYPE)
117  {
118  std::map<std::string, unsigned int> values;
119  values = histogram->getStringValues();
120 
121  std::map<std::string, unsigned int>::iterator it;
122  it = values.begin();
123 
125  QVector<QwtIntervalSample> samples(values.size());
126  double LabelInterval = 0.0;
127 
128  while (it != values.end())
129  {
130  QwtInterval qwtInterval(LabelInterval, LabelInterval+1);
131  qwtInterval.setBorderFlags(QwtInterval::ExcludeMaximum);
132  samples[LabelInterval] = QwtIntervalSample(it->second, qwtInterval);
133  LabelInterval++;
134  it++;
135  }
136 
137  setData(new QwtIntervalSeriesData(samples));
138  }
139  else
140  {
141  std::map<double, unsigned int> values;
142  std::map<double, unsigned int>::const_iterator it;
143  values = histogram->getValues();
144  it = values.begin();
145  double interval = 0.0;
146 
147  while (it != values.end())
148  {
149  QwtInterval qwtInterval(interval, interval+1);
150  samples.push_back(QwtIntervalSample(it->second, qwtInterval));
151  interval++;
152  it++;
153  }
154 
155  QPen blankPen = QPen(Qt::transparent);
156  setPen(blankPen);
157 
158  te::se::Stroke* blankStroke = new te::se::Stroke();
159  blankStroke->setOpacity(QString::number(0, 'g', 2).toStdString());
160  m_histogramStyle->setStroke(blankStroke);
161 
162  setData(new QwtIntervalSeriesData(samples));
163  }
164 
165  m_selection = new QwtPlotHistogram();
166  m_selection->setStyle(QwtPlotHistogram::Columns);
167 
168  //The default selection color is green
169  m_selection->setBrush(QColor("#00FF00"));
170  m_selection->attach(plot());
171 
172 }
173 
175 {
176  delete m_histogram;
177  delete m_histogramStyle;
178  delete m_selection;
179  if(m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
180  delete m_histogramScaleDraw;
181 }
182 
184 {
186 }
187 
189 {
190  return m_histogramScaleDraw;
191 }
192 
194 {
195  delete m_histogramScaleDraw;
196  m_histogramScaleDraw = newScaleDraw;
197 }
198 
200 {
201  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
202  {
203  plot->setAxisScaleDraw(QwtPlot::xBottom, m_histogramScaleDraw);
204  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
205  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelRotation(-60);
206  }
207 
208  QwtPlotHistogram::attach(plot);
209 }
210 
212 {
213  return m_histogram;
214 }
215 
217 {
218  delete m_histogram;
219  m_histogram = newHistogram;
220 }
221 
223 {
224  return m_histogramStyle->clone();
225 }
226 
228 {
229  delete m_histogramStyle;
230  m_histogramStyle = newStyle;
231 
232  //The pen and brush that will be used
233  QPen barPen;
234  QBrush barBrush;
235 
236  //Configuring the pen and brush based on the current style
237  te::qt::widgets::Config(barPen, m_histogramStyle->getStroke());
238  te::qt::widgets::Config(barBrush, m_histogramStyle->getFill());
239  barBrush.setStyle(Qt::SolidPattern);
240 
241  //Updating the chart's pen and brush.
242  setPen(barPen);
243  setBrush(barBrush);
244 }
245 
247 {
248  //Removing the previous selection, if there was any.
249  m_selection->detach();
250 
251  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator itObjSet;
252  QwtSeriesData<QwtIntervalSample>* values = data();
253 
254  //Acquiring all selected intervals:
255 
256  if((m_histogram->getType() >= te::dt::INT16_TYPE && m_histogram->getType() <= te::dt::UINT64_TYPE) ||
257  m_histogram->getType() == te::dt::FLOAT_TYPE || m_histogram->getType() == te::dt::DOUBLE_TYPE ||
258  m_histogram->getType() == te::dt::NUMERIC_TYPE)
259  {
260 
261  std::map<double, unsigned int> highlightedIntervals;
262 
263  //Acquiring the slected intervals
264  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
265  {
266  double interval = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)))->getValue();
267  highlightedIntervals.insert(std::make_pair(interval, 0));
268  }
269 
270  //Acquiring the selected values' frequency
271  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
272  {
273  double interval = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)))->getValue();
274  ++highlightedIntervals.at(interval);
275  }
276 
277  QVector<QwtIntervalSample> highlightedSamples(highlightedIntervals.size());
278 
279  //Acquiring all selected samples:
280  for(size_t i = 0; i < values->size(); ++i)
281  {
282  for (std::map<double, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
283  {
284  //Comparing with the minimum value. Our histogram is created based on the exclude maximum policy.
285  if(values->sample(i).interval.minValue() == it->first)
286  {
287  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
288  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
289  }
290  }
291  }
292  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
293  }
294 
295  else if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
296  {
297 
298  //A vector that will contain the selected strings
299  std::map<std::string, unsigned int> highlightedIntervals;
300 
301  //Acquiring the slected intervals
302  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
303  {
304  std::string interval = m_histogram->find((*itObjSet))->toString();
305  highlightedIntervals.insert(std::make_pair(interval,0));
306  }
307 
308  //Acquiring the selected values' frequency
309  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
310  {
311  std::string interval = m_histogram->find((*itObjSet))->toString();
312  ++highlightedIntervals.at(interval);
313  }
314 
315 
316  //A vector containing that will be populated with the samples that match the selected strings
317  QVector<QwtIntervalSample> highlightedSamples(highlightedIntervals.size());
318 
319  //Acquiring all selected samples:
320  for(size_t i = 0; i < values->size(); ++i)
321  {
322  for (std::map<std::string, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
323  {
324  //Comparing label by label.
325  if(m_histogramScaleDraw->label(i).text().toStdString() == it->first)
326  {
327  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
328  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
329  }
330  }
331  }
332  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
333  }
334 
335  m_selection->attach(plot());
336  plot()->replot();
337 }
338 
340 {
341  QwtSeriesData<QwtIntervalSample>* values = data();
342 
343  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
344  {
345  std::auto_ptr<te::dt::String> data(new te::dt::String(""));
346  for(size_t i = 0; i < values->size(); ++i)
347  {
348  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
349  data.reset(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
350  }
351 
352  return m_histogram->find(data.get());
353  }
354  else
355  {
356  std::auto_ptr<te::dt::Double> data(new te::dt::Double(std::numeric_limits<double>::max()));
357 
358  for(size_t i = 0; i < values->size(); ++i)
359  {
360  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
361  data.reset(new te::dt::Double(values->sample(i).interval.minValue()));
362  }
363 
364  return m_histogram->find(data.get());
365  }
366 }
367 
369 {
370  QwtSeriesData<QwtIntervalSample>* values = data();
371  std::vector<te::dt::AbstractData*> selected;
372 
373  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
374  {
375  for(size_t i = 0; i < values->size(); ++i)
376  {
377  int min = values->sample(i).interval.minValue();
378  int max = values->sample(i).interval.maxValue();
379  int frequency = values->sample(i).value;
380 
381  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
382  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && frequency > rect.y())
383  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
384 
385  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
386  else if(min < rect.x() && max > rect.x() && frequency > rect.y())
387  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
388  }
389  }
390 
391  else
392  {
393  for(size_t i = 0; i < values->size(); ++i)
394  {
395 
396  int min = values->sample(i).interval.minValue();
397  int max = values->sample(i).interval.maxValue();
398  int frequency = values->sample(i).value;
399 
400  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
401  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && frequency > rect.y())
402  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
403 
404  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
405  else if(min < rect.x() && max > rect.x() && frequency > rect.y())
406  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
407  }
408  }
409 
410  return m_histogram->find(selected);
411 }
412 
414 {
415  m_selection->setBrush(selColor);
416 }
StringScaleDraw * m_histogramScaleDraw
Scale draw that defines how a label will be displayed on this chart.
te::se::Fill * getFill()
Returns a pointer to the histogram bar's fill.
HistogramChart(Histogram *data, te::qt::widgets::HistogramStyle *style=0)
Constructor.
void attach(QwtPlot *plot)
It atttaches a QwtPlot to this Cahrt.
virtual int rtti() const
Returns the chart's type.
void setHistogramStyle(te::qt::widgets::HistogramStyle *newStyle)
It sets the chart's style.
A class to represent a Histogram.
Definition: Histogram.h:56
A class to represent a set of labels to be used on a histogram's chart.
te::se::Stroke * getStroke()
Returns a pointer to the histogram bar's stroke.
void setScaleDraw(StringScaleDraw *newScaleDraw)
It sets the chart's scale draw.
virtual std::string toString() const
It returns the data value in a string representation.
Definition: SimpleData.h:126
void setHistogram(te::qt::widgets::Histogram *newHistogram)
It sets the chart's histogram.
A class used to define the style of a histogram's chart.
A class to represent a histogram.
TEQTWIDGETSEXPORT void Config(QPen &pen, const te::se::Stroke *stroke)
It configs the given pen based on Symbology Enconding Stroke element.
Definition: Utils.cpp:52
void setOpacity(const std::string &opacity)
Definition: Stroke.cpp:93
HistogramStyle * clone()
Returns a pointer to a clone of this HistogramStyle.
te::qt::widgets::HistogramStyle * m_histogramStyle
The histogram's style as displayed by this widget.
te::qt::widgets::HistogramStyle * getHistogramStyle()
Returns a clone of the pointer to the histogram's style.
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:53
QwtPlotHistogram * m_selection
The PlotItems to be highlighted when a selection occurs;.
te::qt::widgets::Histogram * getHistogram()
It returns the chart's histogram.
std::map< std::string, unsigned int > getStringValues()
It returns the map containing the histogram String values. The key is a unique string that represents...
Definition: Histogram.cpp:74
A class to represent a histogram chart.
double & getMinValue()
It returns the histogram's minimum value. Will be invalid if the histogram was created based on strin...
Definition: Histogram.cpp:83
void highlight(const te::da::ObjectIdSet *oids)
Highlights the objects identified by oids.
void setSelectionColor(QColor selColor)
color used to hgihlight selected objects on this chart.
std::map< double, unsigned int > getValues()
It returns the map containing the histogram values. The key is the minimum values of the histogram's ...
Definition: Histogram.cpp:63
std::set< ObjectId *, te::common::LessCmp< ObjectId * > >::const_iterator end() const
Returns an iterator for the object ids in container.
A Stroke specifies the appearance of a linear geometry.
Definition: Stroke.h:67
std::set< std::string > & getStringInterval()
It returns the histogram's string set of intervals. Will be invalid if the histogram was created base...
Definition: Histogram.cpp:103
A template for atomic data types (integers, floats, strings and others).
Definition: SimpleData.h:59
double & getInterval()
It returns the histogram's interval. Will be invalid if the histogram was created based on string int...
Definition: Histogram.cpp:93
int & getType()
It returns the histogram's type.
Definition: Histogram.cpp:53
std::set< ObjectId *, te::common::LessCmp< ObjectId * > >::const_iterator begin() const
Returns an iterator for the object ids in container.
StringScaleDraw * getScaleDraw()
It returns the chart's scale draw.
void setStroke(te::se::Stroke *newStroke)
It sets the histogram bar's stroke.