vtkXYChartRepresentationInternals.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: ParaView
4  Module: vtkXYChartRepresentationInternals.h
5 
6  Copyright (c) Kitware, Inc.
7  All rights reserved.
8  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
21 #ifndef vtkXYChartRepresentationInternals_h
22 #define vtkXYChartRepresentationInternals_h
23 
24 #include "vtkCSVExporter.h"
25 #include "vtkChartXY.h"
26 #include "vtkColor.h"
27 #include "vtkDataArray.h"
28 #include "vtkPen.h"
29 #include "vtkPlotBar.h"
30 #include "vtkPlotFunctionalBag.h"
31 #include "vtkPlotPoints.h"
32 #include "vtkSmartPointer.h"
33 #include "vtkTable.h"
34 
35 #include <array>
36 #include <map>
37 #include <string>
38 
40 {
41 protected:
42  struct PlotInfo
43  {
45  std::string TableName;
46  std::string ColumnName;
47  };
48 
49  typedef std::map<std::string, PlotInfo> PlotsMapItem;
50  class PlotsMap : public std::map<std::string, PlotsMapItem>
51  {
52  bool Contains(const std::string& key, const std::string& role) const
53  {
54  PlotsMap::const_iterator iter1 = this->find(key);
55  if (iter1 != this->end())
56  {
57  PlotsMapItem::const_iterator iter2 = iter1->second.find(role);
58  return (iter2 != iter1->second.end());
59  }
60  return false;
61  }
62 
63  public:
64  vtkSmartPointer<vtkPlot> GetPlot(vtkChartRepresentation* self, const std::string& tableName,
65  const std::string& columnName, const std::string& role = std::string()) const
66  {
67  const std::string key = self->GetDefaultSeriesLabel(tableName, columnName);
68  PlotsMap::const_iterator iter1 = this->find(key);
69  if (iter1 != this->end())
70  {
71  PlotsMapItem::const_iterator iter2 = iter1->second.find(role);
72  if (iter2 != iter1->second.end())
73  {
74  return iter2->second.Plot;
75  }
76  }
77  return vtkSmartPointer<vtkPlot>();
78  }
79 
80  bool RemovePlot(vtkChartRepresentation* self, const std::string& tableName,
81  const std::string& columnName, const std::string& role = std::string())
82  {
83  const std::string key = self->GetDefaultSeriesLabel(tableName, columnName);
84  PlotsMap::iterator iter1 = this->find(key);
85  if (iter1 != this->end())
86  {
87  PlotsMapItem::iterator iter2 = iter1->second.find(role);
88  if (iter2 != iter1->second.end())
89  {
90  iter1->second.erase(iter2);
91  return true;
92  }
93  }
94  return false;
95  }
96 
97  void AddPlot(vtkChartRepresentation* self, const std::string& tableName,
98  const std::string& columnName, const std::string& role, vtkPlot* plot)
99  {
100  const std::string key = self->GetDefaultSeriesLabel(tableName, columnName);
101  PlotInfo& info = (*this)[key][role];
102  info.TableName = tableName;
103  info.ColumnName = columnName;
104  info.Plot = plot;
105  }
106 
107  void SetPlotVisibility(bool val) const
108  {
109  for (PlotsMap::const_iterator iter1 = this->begin(); iter1 != this->end(); ++iter1)
110  {
111  for (PlotsMapItem::const_iterator iter2 = iter1->second.begin();
112  iter2 != iter1->second.end(); ++iter2)
113  {
114  iter2->second.Plot->SetVisible(val);
115  }
116  }
117  }
118 
119  void RemoveAllPlots(vtkChartXY* chartXY)
120  {
121  for (PlotsMap::const_iterator iter1 = this->begin(); iter1 != this->end(); ++iter1)
122  {
123  for (PlotsMapItem::const_iterator iter2 = iter1->second.begin();
124  iter2 != iter1->second.end(); ++iter2)
125  {
126  chartXY->RemovePlotInstance(iter2->second.Plot.GetPointer());
127  }
128  }
129  this->clear();
130  }
131 
132  void Intersect(const PlotsMap& other, vtkChartXY* chartXY)
133  {
134  for (PlotsMap::iterator iter1 = this->begin(); iter1 != this->end(); ++iter1)
135  {
136  for (PlotsMapItem::iterator iter2 = iter1->second.begin(); iter2 != iter1->second.end();)
137  {
138  if (other.Contains(iter1->first, iter2->first) == false)
139  {
140  chartXY->RemovePlotInstance(iter2->second.Plot.GetPointer());
141  PlotsMapItem::iterator iter2old = iter2;
142  ++iter2;
143  iter1->second.erase(iter2old);
144  }
145  else
146  {
147  ++iter2;
148  }
149  }
150  }
151  }
152  };
153 
155 
156  //---------------------------------------------------------------------------
157  // Makes is easy to obtain a value for a series parameter, is set, else the
158  // default. This class supports two mechanisms for addresses series in a
159  // collection (multiblock) of tables: (1) using a name that combines the
160  // table name and the column name (using
161  // vtkChartRepresentation::GetDefaultSeriesLabel), or (2) using the column
162  // name alone. (1) is always checked before (2).
163  template <class T>
164  T GetSeriesParameter(vtkXYChartRepresentation* self, const std::string& tableName,
165  const std::string& columnName, const std::string& vtkNotUsed(role),
166  const std::map<std::string, T>& parameter_map, const T default_value = T()) const
167  {
168  typename std::map<std::string, T>::const_iterator iter;
169 
170  // when setting properties for a series, I want to support two mechanisms:
171  // simply specifying the array name or suffixing it with the block-name.
172  // This logic makes that possible.
173 
174  // first try most specific form of identifying the series.
175  std::string key = self->GetDefaultSeriesLabel(tableName, columnName);
176  iter = parameter_map.find(key);
177  if (iter != parameter_map.end())
178  {
179  return iter->second;
180  }
181 
182  // now try the cheap form for identifying it.
183  key = self->GetDefaultSeriesLabel(std::string(), columnName);
184  iter = parameter_map.find(key);
185  if (iter != parameter_map.end())
186  {
187  return iter->second;
188  }
189  return default_value;
190  }
191 
192 public:
194 
195  // we have to keep these separate since they are set by different properties
196  // and hence may not always match up.
197  std::map<std::string, bool> SeriesVisibilities;
198  std::map<std::string, int> SeriesOrder;
199  std::map<std::string, int> LineThicknesses;
200  std::map<std::string, int> LineStyles;
201  std::map<std::string, vtkColor3d> Colors;
202  std::map<std::string, int> AxisCorners;
203  std::map<std::string, int> MarkerStyles;
204  std::map<std::string, double> MarkerSizes;
205  std::map<std::string, std::string> Labels;
206  std::map<std::string, bool> UseColorMapping;
207  std::map<std::string, vtkScalarsToColors*> Lut;
208 
209  // These are used to determine when to recalculate chart bounds. If user
210  // changes the X axis, we force recalculation of the chart bounds
211  // automatically.
214 
216  : PreviousUseIndexForXAxis(false)
217  {
218  }
219 
220  virtual ~vtkInternals() {}
221 
222  //---------------------------------------------------------------------------
223  // Hide all plots.
224  void HideAllPlots() { this->SeriesPlots.SetPlotVisibility(false); }
225 
226  //---------------------------------------------------------------------------
227  // Destroy all vtkPlot instances.
228  void RemoveAllPlots(vtkChartXY* chartXY) { this->SeriesPlots.RemoveAllPlots(chartXY); }
229 
230  //---------------------------------------------------------------------------
236  virtual std::vector<std::string> GetSeriesRoles(
237  const std::string& vtkNotUsed(tableName), const std::string& vtkNotUsed(columnName))
238  {
239  return { std::string() };
240  }
241 
242  virtual vtkPlot* NewPlot(vtkXYChartRepresentation* self, const std::string& tableName,
243  const std::string& columnName, const std::string& role)
244  {
245  (void)tableName;
246  (void)columnName;
247  (void)role;
248 
249  assert(self);
250  vtkChartXY* chartXY = self->GetChart();
251 
252  assert(chartXY);
253  return chartXY->AddPlot(self->GetChartType());
254  }
255 
256  //---------------------------------------------------------------------------
257  virtual int GetInputArrayIndex(const std::string& vtkNotUsed(tableName),
258  const std::string& vtkNotUsed(columnName), const std::string& vtkNotUsed(role))
259  {
260  return 1;
261  }
262 
263  //---------------------------------------------------------------------------
264  // Update i.e. add/remove plots based on the data in the tables.
265  virtual void UpdatePlots(vtkXYChartRepresentation* self, const MapOfTables& tables)
266  {
267  PlotsMap newPlots;
268  assert(self != NULL);
269  vtkChartXY* chartXY = self->GetChart();
270  this->RemoveAllPlots(chartXY);
271  std::multimap<int, std::pair<vtkTable*, std::array<std::string, 3> > > orderMap;
272  for (MapOfTables::const_iterator tablesIter = tables.begin(); tablesIter != tables.end();
273  ++tablesIter)
274  {
275  const std::string& tableName = tablesIter->first;
276  vtkTable* table = tablesIter->second.GetPointer();
277  vtkIdType numCols = table->GetNumberOfColumns();
278  for (vtkIdType cc = 0; cc < numCols; ++cc)
279  {
280  std::string columnName = table->GetColumnName(cc);
281  auto roles = this->GetSeriesRoles(tableName, columnName);
282 
283  for (const auto& role : roles)
284  {
285  // recover the order of the current table column
286  const int order =
287  this->GetSeriesParameter(self, tableName, columnName, role, this->SeriesOrder, -1);
288 
289  // store all info in a (sorted) map
290  std::array<std::string, 3> mapValue;
291  mapValue[0] = tableName;
292  mapValue[1] = columnName;
293  mapValue[2] = role;
294  orderMap.insert(std::make_pair(order, std::make_pair(table, mapValue)));
295  }
296  }
297  }
298 
299  // for each ordered column
300  for (auto it = orderMap.begin(); it != orderMap.end(); ++it)
301  {
302  vtkTable* table = it->second.first;
303  const std::string& tableName = it->second.second[0];
304  const std::string& columnName = it->second.second[1];
305  const std::string& role = it->second.second[2];
306 
307  vtkSmartPointer<vtkPlot> plot = this->SeriesPlots.GetPlot(self, tableName, columnName, role);
308  if (!plot)
309  {
310  // Create the plot in the right order
311  plot = this->NewPlot(self, tableName, columnName, role);
312  if (!plot)
313  {
314  continue;
315  }
316  }
317  plot->SetInputData(table);
318  plot->SetUseIndexForXSeries(self->GetUseIndexForXAxis());
319  plot->SetInputArray(0, self->GetXAxisSeriesName());
320  plot->SetInputArray(this->GetInputArrayIndex(tableName, columnName, role), columnName);
321  this->SeriesPlots.AddPlot(self, tableName, columnName, role, plot);
322  newPlots.AddPlot(self, tableName, columnName, role, plot);
323  }
324 
325  // Remove any plots in this->SeriesPlots that are not in newPlots.
326  this->SeriesPlots.Intersect(newPlots, chartXY);
327  }
328 
329  //---------------------------------------------------------------------------
330  // Update properties for plots in the chart.
332  {
333  vtkChartXY* chartXY = self->GetChart();
334  vtkPlot* lastFunctionalBagPlot = 0;
335  for (PlotsMap::iterator iter1 = this->SeriesPlots.begin(); iter1 != this->SeriesPlots.end();
336  ++iter1)
337  {
338  for (PlotsMapItem::const_iterator iter2 = iter1->second.begin(); iter2 != iter1->second.end();
339  ++iter2)
340  {
341  const PlotInfo& plotInfo = iter2->second;
342  const std::string& tableName = plotInfo.TableName;
343  const std::string& columnName = plotInfo.ColumnName;
344  vtkPlot* plot = plotInfo.Plot;
345  const std::string& role = iter2->first;
346 
347  if (this->UpdateSinglePlotProperties(self, tableName, columnName, role, plot))
348  {
349  // Functional bag plots shall be stacked under the other plots.
351  if (plotBag)
352  {
353  // We can't select the median line as it may not exist in other dataset.
354  if (columnName == "QMedianLine")
355  {
356  plotBag->SelectableOff();
357  }
358  if (plotBag->IsBag())
359  {
360  if (!lastFunctionalBagPlot)
361  {
362  chartXY->LowerPlot(plotBag);
363  }
364  else
365  {
366  chartXY->StackPlotAbove(plotBag, lastFunctionalBagPlot);
367  }
368  lastFunctionalBagPlot = plotBag;
369  }
370  }
371  }
372  }
373  }
374  }
375 
376  //---------------------------------------------------------------------------
377  // Export visible plots to a CSV file.
378  virtual bool Export(vtkXYChartRepresentation* self, vtkCSVExporter* exporter)
379  {
380  for (PlotsMap::iterator iter1 = this->SeriesPlots.begin(); iter1 != this->SeriesPlots.end();
381  ++iter1)
382  {
383  for (PlotsMapItem::const_iterator iter2 = iter1->second.begin(); iter2 != iter1->second.end();
384  ++iter2)
385  {
386  const PlotInfo& plotInfo = iter2->second;
387  vtkPlot* plot = plotInfo.Plot;
388  if (!plot->GetVisible())
389  {
390  continue;
391  }
392  const std::string& columnName = plotInfo.ColumnName;
393  vtkTable* table = plot->GetInput();
394  vtkDataArray* xarray = self->GetUseIndexForXAxis()
395  ? NULL
396  : vtkDataArray::SafeDownCast(table->GetColumnByName(self->GetXAxisSeriesName()));
397  vtkAbstractArray* yarray = table->GetColumnByName(columnName.c_str());
398  if (yarray != NULL)
399  {
400  exporter->AddColumn(yarray, plot->GetLabel().c_str(), xarray);
401  }
402  }
403  }
404  return true;
405  }
406 
407 protected:
408  //---------------------------------------------------------------------------
409  // Returns false for in-visible plots.
411  const std::string& tableName, const std::string& columnName, const std::string& role,
412  vtkPlot* plot)
413  {
414  vtkChartXY* chartXY = self->GetChart();
415  const bool visible =
416  this->GetSeriesParameter(self, tableName, columnName, role, this->SeriesVisibilities, false);
417  plot->SetVisible(visible);
418  if (!visible)
419  {
420  return false;
421  }
422 
423  std::string default_label = self->GetDefaultSeriesLabel(tableName, columnName);
424  std::string label =
425  this->GetSeriesParameter(self, tableName, columnName, role, this->Labels, default_label);
426  if (self->GetSeriesLabelPrefix())
427  {
428  label = std::string(self->GetSeriesLabelPrefix()) + label;
429  }
430  plot->SetLabel(label);
431 
433  self, tableName, columnName, role, this->Colors, vtkColor3d(0, 0, 0));
434  plot->SetColor(color.GetRed(), color.GetGreen(), color.GetBlue());
435  plot->GetSelectionPen()->SetColorF(self->SelectionColor);
436 
437  plot->SetWidth(
438  this->GetSeriesParameter(self, tableName, columnName, role, this->LineThicknesses, 2));
439  plot->GetPen()->SetLineType(this->GetSeriesParameter(
440  self, tableName, columnName, role, this->LineStyles, static_cast<int>(vtkPen::SOLID_LINE)));
441 
442  if (vtkPlotPoints* plotPoints = vtkPlotPoints::SafeDownCast(plot))
443  {
444  plotPoints->SetMarkerStyle(this->GetSeriesParameter(self, tableName, columnName, role,
445  this->MarkerStyles, static_cast<int>(vtkPlotPoints::NONE)));
446  plotPoints->SetMarkerSize(
447  this->GetSeriesParameter(self, tableName, columnName, role, this->MarkerSizes, 1.0));
448  // the vtkValidPointMask array is used by some filters (like plot
449  // over line) to indicate invalid points. this instructs the line
450  // plot to not render those points
451  plotPoints->SetValidPointMaskName("vtkValidPointMask");
452  }
453 
454  chartXY->SetPlotCorner(
455  plot, this->GetSeriesParameter(self, tableName, columnName, role, this->AxisCorners, 0));
456 
457  // for now only vtkPlotBar has color mapping
458  vtkPlotBar* plotBar = vtkPlotBar::SafeDownCast(plot);
459  if (plotBar && columnName == "bin_values")
460  {
461  bool colorMapping =
462  this->GetSeriesParameter(self, tableName, columnName, role, this->UseColorMapping, false);
463  plotBar->SetScalarVisibility(colorMapping);
464  plotBar->SelectColorArray("bin_extents");
466  self, tableName, columnName, role, this->Lut, static_cast<vtkScalarsToColors*>(NULL));
467  if (lut)
468  {
469  plotBar->SetLookupTable(lut);
470  }
471  }
472  return true;
473  }
474 };
475 
476 #endif
477 // VTK-HeaderTest-Exclude: vtkXYChartRepresentationInternals.h
color
std::map< std::string, vtkScalarsToColors * > Lut
order
bool RemovePlot(vtkChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &role=std::string())
static vtkDataArray * SafeDownCast(vtkObjectBase *o)
T GetSeriesParameter(vtkXYChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &vtkNotUsed(role), const std::map< std::string, T > &parameter_map, const T default_value=T()) const
virtual void SetWidth(float width)
vtkXYChartRepresentation is representation that is used to add vtkPlot subclasses to a vtkChartXY ins...
void AddPlot(vtkChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &role, vtkPlot *plot)
info
vtkXYChartRepresentation::MapOfTables MapOfTables
static vtkPlotFunctionalBag * SafeDownCast(vtkObjectBase *o)
int vtkIdType
virtual void SetColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
virtual std::vector< std::string > GetSeriesRoles(const std::string &vtkNotUsed(tableName), const std::string &vtkNotUsed(columnName))
Subclasses can override this method to assign a role for a specific data array in the input dataset.
void SetPlotCorner(vtkPlot *plot, int corner)
std::map< std::string, vtkSmartPointer< vtkTable > > MapOfTables
virtual int GetInputArrayIndex(const std::string &vtkNotUsed(tableName), const std::string &vtkNotUsed(columnName), const std::string &vtkNotUsed(role))
void AddColumn(vtkAbstractArray *yarray, const char *yarrayname=NULL, vtkDataArray *xarray=NULL)
In STREAM_COLUMNS mode, use this method to add a column (yarray).
virtual bool UpdateSinglePlotProperties(vtkXYChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &role, vtkPlot *plot)
vtkPen * GetPen()
vtkSmartPointer< vtkPlot > GetPlot(vtkChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &role=std::string()) const
virtual void SetLookupTable(vtkScalarsToColors *lut)
vtkAbstractArray * GetColumnByName(const char *name)
virtual vtkPlot * AddPlot(int type)
static vtkPlotPoints * SafeDownCast(vtkObjectBase *o)
const char * GetColumnName(vtkIdType col)
virtual bool RemovePlotInstance(vtkPlot *plot)
virtual void UpdatePlotProperties(vtkXYChartRepresentation *self)
virtual bool IsBag()
virtual vtkTable * GetInput()
virtual void SetInputArray(int index, const vtkStdString &name)
vtkIdType LowerPlot(vtkPlot *plot)
virtual void SetScalarVisibility(bool)
virtual void SetInputData(vtkTable *table)
virtual vtkIdType StackPlotAbove(vtkPlot *plot, vtkPlot *under)
virtual vtkStdString GetLabel()
virtual void UpdatePlots(vtkXYChartRepresentation *self, const MapOfTables &tables)
void SelectColorArray(vtkIdType arrayNum)
vtkChartRepresentation is the base representation for charting representations.
void SetColorF(double color[3])
virtual void SetUseIndexForXSeries(bool)
exporter used by certain views to export data as a CSV file.
static vtkPlotBar * SafeDownCast(vtkObjectBase *o)
virtual vtkPlot * NewPlot(vtkXYChartRepresentation *self, const std::string &tableName, const std::string &columnName, const std::string &role)
vtkPen * GetSelectionPen()
virtual bool Export(vtkXYChartRepresentation *self, vtkCSVExporter *exporter)
vtkIdType GetNumberOfColumns()
virtual void SetVisible(bool)
virtual void SetLabel(const vtkStdString &label)
void SetLineType(int type)
virtual bool GetVisible()
void Intersect(const PlotsMap &other, vtkChartXY *chartXY)
virtual void SelectableOff()
key