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) 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(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  while (it != values.end())
158  {
159  double interval = it->first;
160  QwtInterval qwtInterval(interval, interval+1);
161  samples.push_back(QwtIntervalSample(it->second, qwtInterval));
162  it++;
163  }
164 
165  QPen blankPen = QPen(Qt::transparent);
166  setPen(blankPen);
167 
168  te::se::Stroke* blankStroke = new te::se::Stroke();
169  blankStroke->setOpacity(QString::number(0, 'g', 2).toStdString());
170  m_histogramStyle->setStroke(blankStroke);
171  setSamples(samples);
172  }
173 }
174 
176 {
177  delete m_histogram;
178  delete m_histogramStyle;
179  delete m_selection;
180  if(m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
181  delete m_histogramScaleDraw;
182 }
183 
185 {
187 }
188 
190 {
191  return m_histogramScaleDraw;
192 }
193 
195 {
196  delete m_histogramScaleDraw;
197  m_histogramScaleDraw = newScaleDraw;
198 }
199 
201 {
202  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
203  {
204  plot->setAxisScaleDraw(QwtPlot::xBottom, m_histogramScaleDraw);
205  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
206  plot->axisScaleDraw(QwtPlot::xBottom)->setLabelRotation(-60);
207  }
208 
209  QwtPlotHistogram::attach(plot);
210 }
211 
213 {
214  return m_histogram;
215 }
216 
218 {
219  delete m_histogram;
220  m_histogram = newHistogram;
221 }
222 
224 {
225  return m_histogramStyle->clone();
226 }
227 
229 {
230  delete m_histogramStyle;
231  m_histogramStyle = newStyle;
232 
233  //The pen and brush that will be used
234  QPen barPen;
235  QBrush barBrush;
236 
237  //Configuring the pen and brush based on the current style
238  te::qt::widgets::Config(barPen, m_histogramStyle->getStroke());
239  te::qt::widgets::Config(barBrush, m_histogramStyle->getFill());
240  barBrush.setStyle(Qt::SolidPattern);
241 
242  //Updating the chart's pen and brush.
243  setPen(barPen);
244  setBrush(barBrush);
245 }
246 
248 {
249  //Removing the previous selection, if there was any.
250  m_selection->detach();
251 
252  std::set<te::da::ObjectId*, te::common::LessCmp<te::da::ObjectId*> >::const_iterator itObjSet;
253  QwtSeriesData<QwtIntervalSample>* values = data();
254 
255  //Acquiring all selected intervals:
256 
257  if((m_histogram->getType() >= te::dt::INT16_TYPE && m_histogram->getType() <= te::dt::UINT64_TYPE) ||
258  m_histogram->getType() == te::dt::FLOAT_TYPE || m_histogram->getType() == te::dt::DOUBLE_TYPE ||
259  m_histogram->getType() == te::dt::NUMERIC_TYPE)
260  {
261  std::map<double, unsigned int> highlightedIntervals;
262  std::set<std::string> highlightedPkeys;
263 
264  //Acquiring the slected intervals
265  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
266  {
267  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
268  if(data)
269  {
270  double interval = data->getValue();
271  highlightedIntervals.insert(std::make_pair(interval, 0));
272  }
273  }
274 
275  //Acquiring the name of the base dataset and how many of it's properties are included in it's primary key
276  std::pair<std::string, int> dsProps;
277  te::da::GetOIDDatasetProps(dataType, dsProps);
278 
279  //Acquiring the selected values' frequency
280  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
281  {
282  //Acquiring the value of the base primaryKey on the current objectId;
283  std::string pKey = te::da::getBasePkey((*itObjSet),dsProps);
284  if(m_histogram->isSummarized())
285  {
286  if(highlightedPkeys.insert(pKey).second)
287  {
288  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
289  if(data)
290  {
291  double interval = data->getValue();
292  ++highlightedIntervals.at(interval);
293  }
294  }
295  }
296  else
297  {
298  const te::dt::Double* data = static_cast< const te::dt::Double*>(m_histogram->find((*itObjSet)));
299  if(data)
300  {
301  double interval = data->getValue();
302  ++highlightedIntervals.at(interval);
303  }
304  }
305  }
306 
307  QVector<QwtIntervalSample> highlightedSamples(highlightedIntervals.size());
308 
309  //Acquiring all selected samples:
310  for(size_t i = 0; i < values->size(); ++i)
311  {
312  for (std::map<double, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
313  {
314  //Comparing with the minimum value. Our histogram is created based on the exclude maximum policy.
315  if(values->sample(i).interval.minValue() == it->first)
316  {
317  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
318  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
319  }
320  }
321  }
322  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
323  }
324 
325  else if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
326  {
327 
328  //A vector that will contain the selected strings
329  std::map<std::string, unsigned int> highlightedIntervals;
330 
331  //Acquiring the slected intervals
332  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
333  {
334  std::string interval = m_histogram->find((*itObjSet))->toString();
335  highlightedIntervals.insert(std::make_pair(interval,0));
336  }
337 
338  //Acquiring the selected values' frequency
339  for(itObjSet = oids->begin(); itObjSet != oids->end(); ++itObjSet)
340  {
341  std::string interval = m_histogram->find((*itObjSet))->toString();
342  if(m_histogram->getStringValues().at(interval) > highlightedIntervals.at(interval))
343  ++highlightedIntervals.at(interval);
344  }
345 
346  //A vector containing that will be populated with the samples that match the selected strings
347  QVector<QwtIntervalSample> highlightedSamples(highlightedIntervals.size());
348 
349  //Acquiring all selected samples:
350  for(size_t i = 0; i < values->size(); ++i)
351  {
352  for (std::map<std::string, unsigned int>::iterator it = highlightedIntervals.begin(); it != highlightedIntervals.end(); ++it)
353  {
354  //Comparing label by label.
355  if(m_histogramScaleDraw->label(i).text().toStdString() == it->first)
356  {
357  QwtInterval qwtInterval(values->sample(i).interval.minValue(), values->sample(i).interval.maxValue());
358  highlightedSamples.push_back(QwtIntervalSample(it->second, qwtInterval));
359  }
360  }
361  }
362  m_selection->setData(new QwtIntervalSeriesData(highlightedSamples));
363  }
364 
365  m_selection->attach(plot());
366  plot()->replot();
367 }
368 
370 {
371  QwtSeriesData<QwtIntervalSample>* values = data();
372 
373  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
374  {
375  std::auto_ptr<te::dt::String> data(new te::dt::String(""));
376  for(size_t i = 0; i < values->size(); ++i)
377  {
378  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
379  data.reset(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
380  }
381 
382  return m_histogram->find(data.get());
383  }
384  else
385  {
386  std::auto_ptr<te::dt::Double> data(new te::dt::Double(std::numeric_limits<double>::max()));
387 
388  for(size_t i = 0; i < values->size(); ++i)
389  {
390  if(values->sample(i).interval.minValue() < point.rx() && values->sample(i).interval.maxValue() > point.rx() && values->sample(i).value > point.ry())
391  data.reset(new te::dt::Double(values->sample(i).interval.minValue()));
392  }
393 
394  return m_histogram->find(data.get());
395  }
396 }
397 
399 {
400  QwtSeriesData<QwtIntervalSample>* values = data();
401  std::vector<te::dt::AbstractData*> selected;
402 
403  if (m_histogram->getType() == te::dt::DATETIME_TYPE || m_histogram->getType() == te::dt::STRING_TYPE)
404  {
405  for(size_t i = 0; i < values->size(); ++i)
406  {
407  int min = values->sample(i).interval.minValue();
408  int max = values->sample(i).interval.maxValue();
409  int frequency = values->sample(i).value;
410 
411  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
412  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && (frequency > rect.y() && rect.y() + rect.height() > 0))
413  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
414 
415  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
416  else if(min < rect.x() && max > rect.x() && (frequency > rect.y() && rect.y() + rect.height() > 0))
417  selected.push_back(new te::dt::String(m_histogramScaleDraw->label(i).text().toStdString()));
418  }
419  }
420 
421  else
422  {
423  for(size_t i = 0; i < values->size(); ++i)
424  {
425 
426  int min = values->sample(i).interval.minValue();
427  int max = values->sample(i).interval.maxValue();
428  int frequency = values->sample(i).value;
429 
430  //Checking if the interval is within the rectangle, works when a rectangle is drawn around the intervals
431  if(min > rect.x() && (max < rect.x() + rect.width() || min < rect.x() + rect.width()) && (frequency > rect.y() && rect.y() + rect.height() > 0))
432  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
433 
434  //Checking if the rectangle is within the interval, works when the user simply clicked on an interval
435  else if(min < rect.x() && max > rect.x() && (frequency > rect.y() && rect.y() + rect.height() > 0))
436  selected.push_back(new te::dt::Double(values->sample(i).interval.minValue()));
437  }
438  }
439 
440  return m_histogram->find(selected);
441 }
442 
444 {
445  m_selection->setBrush(selColor);
446 }
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.