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