HistogramChart.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 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 "../../../dataaccess/utils/Utils.h"
30 #include "../../../qt/widgets/se/Utils.h"
31 #include "../../../se/Stroke.h"
32 #include "Enums.h"
33 #include "Histogram.h"
34 #include "HistogramChart.h"
35 #include "HistogramStyle.h"
36 #include "StringScaleDraw.h"
37 #include "Utils.h"
38 
39 
40 //QT
41 #include <qbrush.h>
42 #include <qpen.h>
43 
44 //QWT
45 #include <qwt_column_symbol.h>
46 #include <qwt_plot.h>
47 
48 //STL
49 #include <limits>
50 
52  QwtPlotHistogram(),
53  m_histogram(histogram),
54  m_histogramStyle(style)
55 {
56  if(!m_histogramStyle)
57  {
59  QPen barPen;
60  QBrush barBrush;
61 
64  barBrush.setStyle(Qt::SolidPattern);
65 
66  setPen(barPen);
67  setBrush(barBrush);
68  }
69 
70  setData();
71 
72  m_selection = new QwtPlotHistogram();
73  m_selection->setStyle(QwtPlotHistogram::Columns);
74 
75  //The default selection color is green
76  m_selection->setBrush(QColor("#00FF00"));
77  m_selection->attach(plot());
78 
79 }
80 
82 {
83  //Vector that will be populated by the histogram's data
84  QVector<QwtIntervalSample> samples;
85  if((m_histogram->getType() >= te::dt::INT16_TYPE && m_histogram->getType() <= te::dt::UINT64_TYPE) ||
86  m_histogram->getType() == te::dt::FLOAT_TYPE || m_histogram->getType() == te::dt::DOUBLE_TYPE ||
87  m_histogram->getType() == te::dt::NUMERIC_TYPE)
88  {
89  std::map<double, unsigned int> values;
90  values = m_histogram->getValues();
91 
92  std::map<double, unsigned int>::const_iterator it;
93  it = values.begin();
94 
95  std::map<int, unsigned int> vmap;
96 
97  int i = 0;
98 
99  double ini = m_histogram->getMinValue();
100 
101  double vx = ini + m_histogram->getInterval();
102 
103  while(vx <= values.rbegin()->first)
104  {
105  vmap[i] = 0;
106  if(fabs(vx) < 0.000000000001)
107  vx = 0.;
108  while(it != values.end())
109  {
110  if(it->first >= ini && it->first < vx)
111  vmap[i] += it->second;
112  else
113  break;
114  ++it;
115  }
116 
117  QwtInterval qinterval(ini, vx);
118  qinterval.setBorderFlags(QwtInterval::ExcludeMaximum);
119  samples.push_back(QwtIntervalSample(vmap[i], qinterval));
120 
121  ini = vx;
122  vx += m_histogram->getInterval();
123  ++i;
124  }
125  setSamples(samples);
126  }
127 
128  else if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
129  {
130  std::map<std::string, unsigned int> values;
131  values = m_histogram->getStringValues();
132 
133  std::map<std::string, unsigned int>::iterator it;
134  it = values.begin();
135 
136  m_histogramScaleDraw = new StringScaleDraw(m_histogram->getStringInterval());
137  QVector<QwtIntervalSample> samples((int)values.size());
138  double LabelInterval = 0.0;
139 
140  while (it != values.end())
141  {
142  QwtInterval qwtInterval(LabelInterval, LabelInterval+1);
143  qwtInterval.setBorderFlags(QwtInterval::ExcludeMaximum);
144  samples[LabelInterval] = QwtIntervalSample(it->second, qwtInterval);
145  LabelInterval++;
146  it++;
147  }
148  setSamples(samples);
149  }
150  else
151  {
152  std::map<double, unsigned int> values;
153  std::map<double, unsigned int>::const_iterator it;
154  values = m_histogram->getValues();
155  it = values.begin();
156 
157  // The raster's interval was adjusted
158  if (m_histogram->getInterval() != std::numeric_limits<double>::max())
159  {
160  double ini = m_histogram->getMinValue();
161  double vx = ini + m_histogram->getInterval();
162 
163  while (it != values.end())
164  {
165  QwtInterval qwtInterval(ini, vx);
166  samples.push_back(QwtIntervalSample(it->second, qwtInterval));
167  it++;
168  ini = vx;
169  vx += m_histogram->getInterval();
170  }
171  }
172  else
173  {
174  while (it != values.end())
175  {
176  double interval = it->first;
177  QwtInterval qwtInterval(interval, interval + 1);
178  samples.push_back(QwtIntervalSample(it->second, qwtInterval));
179  it++;
180  }
181  }
182 
183  QPen blankPen = QPen(Qt::transparent);
184  setPen(blankPen);
185 
186  te::se::Stroke* blankStroke = new te::se::Stroke();
187  blankStroke->setOpacity(QString::number(0, 'g', 2).toStdString());
188  m_histogramStyle->setStroke(blankStroke);
189  setSamples(samples);
190  }
191 }
192 
194 {
195  delete m_histogram;
196  delete m_histogramStyle;
197  delete m_selection;
198 }
199 
201 {
203 }
204 
206 {
207  return m_histogramScaleDraw;
208 }
209 
211 {
212  delete m_histogramScaleDraw;
213  m_histogramScaleDraw = newScaleDraw;
214  plot()->setAxisScaleDraw(QwtPlot::xBottom, m_histogramScaleDraw);
215 }
216 
218 {
219  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
220  {
221  plot->setAxisScaleDraw(QwtPlot::xBottom, m_histogramScaleDraw);
222  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
223  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelRotation(-60);
224  }
225 
226  QwtPlotHistogram::attach(plot);
227 }
228 
230 {
231  return m_histogram;
232 }
233 
235 {
236  delete m_histogram;
237  m_histogram = newHistogram;
238 }
239 
241 {
242  return m_histogramStyle->clone();
243 }
244 
246 {
247  delete m_histogramStyle;
248  m_histogramStyle = newStyle;
249 
250  //The pen and brush that will be used
251  QPen barPen;
252  QBrush barBrush;
253 
254  //Configuring the pen and brush based on the current style
255  te::qt::widgets::Config(barPen, m_histogramStyle->getStroke());
256  te::qt::widgets::Config(barBrush, m_histogramStyle->getFill());
257  barBrush.setStyle(Qt::SolidPattern);
258 
259  //Updating the chart's pen and brush.
260  setPen(barPen);
261  setBrush(barBrush);
262 }
263 
265 {
266  //Removing the previous selection, if there was any.
267  m_selection->detach();
268 
269  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator itObjSet;
270  QwtSeriesData<QwtIntervalSample>* values = data();
271 
272  //Acquiring all selected intervals:
273 
274  if((m_histogram->getType() >= te::dt::INT16_TYPE && m_histogram->getType() <= te::dt::UINT64_TYPE) ||
275  m_histogram->getType() == te::dt::FLOAT_TYPE || m_histogram->getType() == te::dt::DOUBLE_TYPE ||
276  m_histogram->getType() == te::dt::NUMERIC_TYPE)
277  {
278  std::map<double, unsigned int> highlightedIntervals;
279  std::set<std::string> highlightedPkeys;
280 
281  //Acquiring the slected intervals
282  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
283  {
284  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
285  if(data)
286  {
287  double interval = data->getValue();
288  highlightedIntervals.insert(std::make_pair(interval, 0));
289  }
290  }
291 
292  //Acquiring the name of the base dataset and how many of it's properties are included in it's primary key
293  std::pair<std::string, int> dsProps;
294  te::da::GetOIDDatasetProps(dataType, dsProps);
295 
296  //Acquiring the selected values' frequency
297  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
298  {
299  //Acquiring the value of the base primaryKey on the current objectId;
300  std::string pKey = te::da::getBasePkey((*itObjSet),dsProps);
301  if(m_histogram->isSummarized())
302  {
303  if(highlightedPkeys.insert(pKey).second)
304  {
305  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
306  if(data)
307  {
308  double interval = data->getValue();
309  ++highlightedIntervals.at(interval);
310  }
311  }
312  }
313  else
314  {
315  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
316  if(data)
317  {
318  double interval = data->getValue();
319  ++highlightedIntervals.at(interval);
320  }
321  }
322  }
323 
324  QVector<QwtIntervalSample> highlightedSamples((int)highlightedIntervals.size());
325 
326  //Acquiring all selected samples:
327  for(size_t i = 0; i < values->size(); ++i)
328  {
329  for (std::map<double, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
330  {
331  //Comparing with the minimum value. Our histogram is created based on the exclude maximum policy.
332  if(values->sample(i).interval.minValue() == it->first)
333  {
334  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
335  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
336  }
337  }
338  }
339  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
340  }
341 
342  else if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
343  {
344 
345  //A vector that will contain the selected strings
346  std::map<std::string, unsigned int> highlightedIntervals;
347 
348  //Acquiring the slected intervals
349  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
350  {
351  const te::dt::String* data = static_cast<const te::dt::String*>(m_histogram->find((*itObjSet)));
352  if (data)
353  {
354  std::string interval = data->getValue();
355  highlightedIntervals.insert(std::make_pair(interval, 0));
356  }
357  }
358 
359  //Acquiring the selected values' frequency
360  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
361  {
362  std::string interval = m_histogram->find((*itObjSet))->toString();
363  if(m_histogram->getStringValues().at(interval) > highlightedIntervals.at(interval))
364  ++highlightedIntervals.at(interval);
365  }
366 
367  //A vector containing that will be populated with the samples that match the selected strings
368  QVector<QwtIntervalSample> highlightedSamples((int)highlightedIntervals.size());
369 
370  //Acquiring all selected samples:
371  for(size_t i = 0; i < values->size(); ++i)
372  {
373  for (std::map<std::string, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
374  {
375  //Comparing label by label.
376  if(m_histogramScaleDraw->label(i).text().toStdString() == it->first)
377  {
378  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
379  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
380  }
381  }
382  }
383  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
384  }
385 
386  m_selection->attach(plot());
387  plot()->replot();
388 }
389 
391 {
392  QwtSeriesData<QwtIntervalSample>* values = data();
393 
394  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
395  {
396  std::auto_ptr<te::dt::String> data(new te::dt::String(""));
397  for(size_t i = 0; i < values->size(); ++i)
398  {
399  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
400  data.reset(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
401  }
402 
403  return m_histogram->find(data.get());
404  }
405  else
406  {
407  std::auto_ptr<te::dt::Double> data(new te::dt::Double(std::numeric_limits<double>::max()));
408 
409  for(size_t i = 0; i < values->size(); ++i)
410  {
411  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
412  data.reset(new te::dt::Double(values->sample(i).interval.minValue()));
413  }
414 
415  return m_histogram->find(data.get());
416  }
417 }
418 
420 {
421  QwtSeriesData<QwtIntervalSample>* values = data();
422  std::vector<te::dt::AbstractData*> selected;
423 
424  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
425  {
426  for(size_t i = 0; i < values->size(); ++i)
427  {
428  int min = values->sample(i).interval.minValue();
429  int max = values->sample(i).interval.maxValue();
430  int frequency = values->sample(i).value;
431 
432  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
433  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && (frequency > rect.y() && rect.y() + rect.height() > 0))
434  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
435 
436  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
437  else if(min < rect.x() && max > rect.x() && (frequency > rect.y() && rect.y() + rect.height() > 0))
438  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
439  }
440  }
441 
442  else
443  {
444  for(size_t i = 0; i < values->size(); ++i)
445  {
446 
447  int min = values->sample(i).interval.minValue();
448  int max = values->sample(i).interval.maxValue();
449  int frequency = values->sample(i).value;
450 
451  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
452  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && (frequency > rect.y() && rect.y() + rect.height() > 0))
453  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
454 
455  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
456  else if(min < rect.x() && max > rect.x() && (frequency > rect.y() && rect.y() + rect.height() > 0))
457  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
458  }
459  }
460 
461  return m_histogram->find(selected);
462 }
463 
465 {
466  m_selection->setBrush(selColor);
467 }
Utility functions for the data access module.
te::se::Fill * getFill()
Returns a pointer to the histogram bar's fill.
HistogramChart(Histogram *data, te::qt::widgets::HistogramStyle *style=0)
Constructor.
A class that models the description of a dataset.
Definition: DataSetType.h:72
void attach(QwtPlot *plot)
It atttaches a QwtPlot to this Cahrt.
virtual int rtti() const
Returns the chart's type.
void highlight(const te::da::ObjectIdSet *oids, te::da::DataSetType *dataType)
Highlights the objects identified by oids.
void setHistogramStyle(te::qt::widgets::HistogramStyle *newStyle)
It sets the chart's style.
T getValue() const
It returns the associated value.
Definition: SimpleData.h:139
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.
TEDATAACCESSEXPORT void GetOIDDatasetProps(const DataSetType *type, std::pair< std::string, int > &dsProps)
Definition: Utils.cpp:355
void setScaleDraw(StringScaleDraw *newScaleDraw)
It sets the chart's scale draw.
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:55
QwtPlotHistogram * m_selection
The PlotItems to be highlighted when a selection occurs;.
te::qt::widgets::Histogram * getHistogram()
It returns the chart's histogram.
A class to represent a histogram chart.
void setSelectionColor(QColor selColor)
color used to hgihlight selected objects on this chart.
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
TEDATAACCESSEXPORT std::string getBasePkey(te::da::ObjectId *oid, std::pair< std::string, int > &dsProps)
Definition: Utils.cpp:388
A template for atomic data types (integers, floats, strings and others).
Definition: SimpleData.h:59
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.