1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkScatterPlotMatrix.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm 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 =========================================================================*/
15 
16 #include "vtkScatterPlotMatrix.h"
17 
18 #include "vtkAnnotationLink.h"
19 #include "vtkAxis.h"
20 #include "vtkBrush.h"
21 #include "vtkCallbackCommand.h"
22 #include "vtkChartXY.h"
23 #include "vtkChartXYZ.h"
24 #include "vtkCommand.h"
25 #include "vtkContext2D.h"
26 #include "vtkContextMouseEvent.h"
27 #include "vtkContextScene.h"
28 #include "vtkFloatArray.h"
29 #include "vtkIntArray.h"
30 #include "vtkMathUtilities.h"
31 #include "vtkNew.h"
32 #include "vtkObjectFactory.h"
33 #include "vtkPen.h"
34 #include "vtkPlot.h"
35 #include "vtkPlotPoints.h"
36 #include "vtkPlotPoints3D.h"
37 #include "vtkRenderWindowInteractor.h"
38 #include "vtkStdString.h"
39 #include "vtkStringArray.h"
40 #include "vtkTable.h"
41 #include "vtkTextProperty.h"
42 #include "vtkTooltipItem.h"
43 #include "vtkVectorOperators.h"
44 
45 // STL includes
46 #include <algorithm>
47 #include <cassert>
48 #include <map>
49 #include <vector>
50 
51 class vtkScatterPlotMatrix::PIMPL
52 {
53 public:
PIMPL()54   PIMPL() : VisibleColumnsModified(true), BigChart(nullptr), BigChartPos(0, 0),
55     ResizingBigChart(false), AnimationCallbackInitialized(false), TimerId(0),
56     TimerCallbackInitialized(false)
57   {
58     pimplChartSetting* scatterplotSettings = new pimplChartSetting();
59     scatterplotSettings->BackgroundBrush->SetColor(255, 255, 255, 255);
60     this->ChartSettings[vtkScatterPlotMatrix::SCATTERPLOT] =
61         scatterplotSettings;
62     pimplChartSetting* histogramSettings = new pimplChartSetting();
63     histogramSettings->BackgroundBrush->SetColor(127, 127, 127, 102);
64     histogramSettings->PlotPen->SetColor(255, 255, 255, 255);
65     histogramSettings->ShowAxisLabels = true;
66     this->ChartSettings[vtkScatterPlotMatrix::HISTOGRAM] = histogramSettings;
67     pimplChartSetting* activeplotSettings = new pimplChartSetting();
68     activeplotSettings->BackgroundBrush->SetColor(255, 255, 255, 255);
69     activeplotSettings->ShowAxisLabels = true;
70     this->ChartSettings[vtkScatterPlotMatrix::ACTIVEPLOT] = activeplotSettings;
71     activeplotSettings->MarkerSize = 8.0;
72     this->SelectedChartBGBrush->SetColor(0, 204, 0, 102);
73     this->SelectedRowColumnBGBrush->SetColor(204, 0, 0, 102);
74     this->TooltipItem = vtkSmartPointer<vtkTooltipItem>::New();
75   }
76 
~PIMPL()77   ~PIMPL()
78   {
79     delete this->ChartSettings[vtkScatterPlotMatrix::SCATTERPLOT];
80     delete this->ChartSettings[vtkScatterPlotMatrix::HISTOGRAM];
81     delete this->ChartSettings[vtkScatterPlotMatrix::ACTIVEPLOT];
82   }
83 
84   // Store columns settings such as axis range, title, number of tick marks.
85   class ColumnSetting
86   {
87   public:
ColumnSetting()88     ColumnSetting() : min(0), max(0), nTicks(0), title("?!?")
89     {
90     }
91 
92     double min;
93     double max;
94     int    nTicks;
95     std::string title;
96   };
97 
98   class pimplChartSetting
99   {
100   public:
pimplChartSetting()101     pimplChartSetting()
102     {
103       this->PlotPen->SetColor(0, 0, 0, 255);
104       this->MarkerStyle = vtkPlotPoints::CIRCLE;
105       this->MarkerSize = 3.0;
106       this->AxisColor.Set(0, 0, 0, 255);
107       this->GridColor.Set(242, 242, 242, 255);
108       this->LabelNotation = vtkAxis::STANDARD_NOTATION;
109       this->LabelPrecision = 2;
110       this->TooltipNotation = vtkAxis::STANDARD_NOTATION;
111       this->TooltipPrecision = 2;
112       this->ShowGrid = true;
113       this->ShowAxisLabels = false;
114       this->LabelFont = vtkSmartPointer<vtkTextProperty>::New();
115       this->LabelFont->SetFontFamilyToArial();
116       this->LabelFont->SetFontSize(12);
117       this->LabelFont->SetColor(0.0, 0.0, 0.0);
118       this->LabelFont->SetOpacity(1.0);
119     }
120     ~pimplChartSetting() = default;
121 
122     int MarkerStyle;
123     float MarkerSize;
124     vtkColor4ub AxisColor;
125     vtkColor4ub GridColor;
126     int LabelNotation;
127     int LabelPrecision;
128     int TooltipNotation;
129     int TooltipPrecision;
130     bool ShowGrid;
131     bool ShowAxisLabels;
132     vtkSmartPointer<vtkTextProperty> LabelFont;
133     vtkNew<vtkBrush> BackgroundBrush;
134     vtkNew<vtkPen> PlotPen;
135     vtkNew<vtkBrush> PlotBrush;
136   };
137 
UpdateAxis(vtkAxis * axis,pimplChartSetting * setting,bool updateLabel=true)138   void UpdateAxis(vtkAxis* axis, pimplChartSetting* setting,
139                   bool updateLabel = true)
140   {
141     if(axis && setting)
142     {
143       axis->GetPen()->SetColor(setting->AxisColor);
144       axis->GetGridPen()->SetColor(setting->GridColor);
145       axis->SetGridVisible(setting->ShowGrid);
146       if (updateLabel)
147       {
148         vtkTextProperty *prop = setting->LabelFont;
149         axis->SetNotation(setting->LabelNotation);
150         axis->SetPrecision(setting->LabelPrecision);
151         axis->SetLabelsVisible(setting->ShowAxisLabels);
152         axis->GetLabelProperties()->SetFontSize(prop->GetFontSize());
153         axis->GetLabelProperties()->SetColor(prop->GetColor());
154         axis->GetLabelProperties()->SetOpacity(prop->GetOpacity());
155         axis->GetLabelProperties()->SetFontFamilyAsString(
156           prop->GetFontFamilyAsString());
157         axis->GetLabelProperties()->SetBold(prop->GetBold());
158         axis->GetLabelProperties()->SetItalic(prop->GetItalic());
159       }
160     }
161   }
162 
UpdateChart(vtkChart * chart,pimplChartSetting * setting)163   void UpdateChart(vtkChart* chart, pimplChartSetting* setting)
164   {
165     if(chart && setting)
166     {
167       vtkPlot *plot = chart->GetPlot(0);
168       if (plot)
169       {
170         plot->SetTooltipNotation(setting->TooltipNotation);
171         plot->SetTooltipPrecision(setting->TooltipPrecision);
172       }
173     }
174   }
175 
176   vtkNew<vtkTable> Histogram;
177   bool VisibleColumnsModified;
178   vtkWeakPointer<vtkChart> BigChart;
179   vtkVector2i BigChartPos;
180   bool ResizingBigChart;
181   vtkNew<vtkAnnotationLink> Link;
182 
183   // Settings for the charts in the scatter plot matrix.
184   std::map<int, pimplChartSetting*> ChartSettings;
185   typedef std::map<int, pimplChartSetting*>::iterator chartIterator;
186 
187   // Axis ranges for the columns in the scatter plot matrix.
188   std::map<std::string, ColumnSetting> ColumnSettings;
189 
190   vtkNew<vtkBrush> SelectedRowColumnBGBrush;
191   vtkNew<vtkBrush> SelectedChartBGBrush;
192   std::vector<vtkVector2i>           AnimationPath;
193   std::vector<vtkVector2i>::iterator AnimationIter;
194   vtkRenderWindowInteractor* Interactor;
195   vtkNew<vtkCallbackCommand> AnimationCallback;
196   bool                       AnimationCallbackInitialized;
197   unsigned long int          TimerId;
198   bool                       TimerCallbackInitialized;
199   int                        AnimationPhase;
200   float                      CurrentAngle;
201   float                      IncAngle;
202   float                      FinalAngle;
203   vtkVector2i                NextActivePlot;
204 
205   vtkNew<vtkChartXYZ> BigChart3D;
206   vtkNew<vtkAxis>     TestAxis;   // Used to get ranges/number of ticks
207   vtkSmartPointer<vtkTooltipItem> TooltipItem;
208   vtkSmartPointer<vtkStringArray> IndexedLabelsArray;
209 };
210 
211 namespace
212 {
213 
214 // This is just here for now - quick and dirty historgram calculations...
PopulateHistograms(vtkTable * input,vtkTable * output,vtkStringArray * s,int NumberOfBins)215 bool PopulateHistograms(vtkTable *input, vtkTable *output, vtkStringArray *s,
216                         int NumberOfBins)
217 {
218   // The output table will have the twice the number of columns, they will be
219   // the x and y for input column. This is the bin centers, and the population.
220   for (vtkIdType i = 0; i < s->GetNumberOfTuples(); ++i)
221   {
222     double minmax[2] = { 0.0, 0.0 };
223     vtkStdString name(s->GetValue(i));
224     vtkDataArray *in =
225         vtkArrayDownCast<vtkDataArray>(input->GetColumnByName(name.c_str()));
226     if (in)
227     {
228       // The bin values are the centers, extending +/- half an inc either side
229       in->GetRange(minmax);
230       if (minmax[0] == minmax[1])
231       {
232         minmax[1] = minmax[0] + 1.0;
233       }
234       double inc = (minmax[1] - minmax[0]) / (NumberOfBins) * 1.001;
235       double halfInc = inc / 2.0;
236       vtkSmartPointer<vtkFloatArray> extents =
237           vtkArrayDownCast<vtkFloatArray>(
238             output->GetColumnByName(vtkStdString(name + "_extents").c_str()));
239       if (!extents)
240       {
241         extents = vtkSmartPointer<vtkFloatArray>::New();
242         extents->SetName(vtkStdString(name + "_extents").c_str());
243       }
244       extents->SetNumberOfTuples(NumberOfBins);
245       float *centers = static_cast<float *>(extents->GetVoidPointer(0));
246       double min = minmax[0] - 0.0005 * inc + halfInc;
247       for (int j = 0; j < NumberOfBins; ++j)
248       {
249         extents->SetValue(j, min + j * inc);
250       }
251       vtkSmartPointer<vtkIntArray> populations =
252           vtkArrayDownCast<vtkIntArray>(
253             output->GetColumnByName(vtkStdString(name + "_pops").c_str()));
254       if (!populations)
255       {
256         populations = vtkSmartPointer<vtkIntArray>::New();
257         populations->SetName(vtkStdString(name + "_pops").c_str());
258       }
259       populations->SetNumberOfTuples(NumberOfBins);
260       int *pops = static_cast<int *>(populations->GetVoidPointer(0));
261       for (int k = 0; k < NumberOfBins; ++k)
262       {
263         pops[k] = 0;
264       }
265       for (vtkIdType j = 0; j < in->GetNumberOfTuples(); ++j)
266       {
267         double v(0.0);
268         in->GetTuple(j, &v);
269         for (int k = 0; k < NumberOfBins; ++k)
270         {
271           if (vtkMathUtilities::FuzzyCompare(v, double(centers[k]), halfInc))
272           {
273             ++pops[k];
274             break;
275           }
276         }
277       }
278       output->AddColumn(extents);
279       output->AddColumn(populations);
280     }
281   }
282   return true;
283 }
284 
MoveColumn(vtkStringArray * visCols,int fromCol,int toCol)285 bool MoveColumn(vtkStringArray* visCols, int fromCol, int toCol)
286 {
287   if(!visCols || visCols->GetNumberOfTuples() == 0
288     || fromCol == toCol || fromCol == (toCol-1) || fromCol < 0 || toCol < 0)
289   {
290     return false;
291   }
292   int numCols = visCols->GetNumberOfTuples();
293   if( fromCol >= numCols || toCol > numCols)
294   {
295     return false;
296   }
297 
298   std::vector<vtkStdString> newVisCols;
299   vtkIdType c;
300   if(toCol == numCols)
301   {
302     for(c=0; c<numCols; c++)
303     {
304       if(c!=fromCol)
305       {
306         newVisCols.push_back(visCols->GetValue(c));
307       }
308     }
309     // move the fromCol to the end
310     newVisCols.push_back(visCols->GetValue(fromCol));
311   }
312   // insert the fromCol before toCol
313   else if(fromCol < toCol)
314   {
315     // move Cols in the middle up
316     for(c=0; c<fromCol; c++)
317     {
318       newVisCols.push_back(visCols->GetValue(c));
319     }
320     for(c=fromCol+1; c<numCols; c++)
321     {
322       if(c == toCol)
323       {
324         newVisCols.push_back(visCols->GetValue(fromCol));
325       }
326       newVisCols.push_back(visCols->GetValue(c));
327     }
328   }
329   else
330   {
331     for(c=0; c<toCol; c++)
332     {
333       newVisCols.push_back(visCols->GetValue(c));
334     }
335     newVisCols.push_back(visCols->GetValue(fromCol));
336     for(c=toCol; c<numCols; c++)
337     {
338       if(c != fromCol)
339       {
340         newVisCols.push_back(visCols->GetValue(c));
341       }
342     }
343   }
344 
345   // repopulate the visCols
346   vtkIdType visId=0;
347   std::vector<vtkStdString>::iterator arrayIt;
348   for(arrayIt=newVisCols.begin(); arrayIt!=newVisCols.end(); ++arrayIt)
349   {
350     visCols->SetValue(visId++, *arrayIt);
351   }
352   return true;
353 }
354 } // End of anonymous namespace
355 
vtkObjectFactoryNewMacro(vtkScatterPlotMatrix)356 vtkObjectFactoryNewMacro(vtkScatterPlotMatrix)
357 
358 vtkScatterPlotMatrix::vtkScatterPlotMatrix()
359   : NumberOfBins(10), NumberOfFrames(25),
360   LayoutUpdatedTime(0)
361 {
362   this->Private = new PIMPL;
363   this->TitleProperties = vtkSmartPointer<vtkTextProperty>::New();
364   this->TitleProperties->SetFontSize(12);
365   this->SelectionMode = vtkContextScene::SELECTION_NONE;
366   this->ActivePlot = vtkVector2i(0, -2);
367   this->ActivePlotValid = false;
368   this->Animating = false;
369 }
370 
~vtkScatterPlotMatrix()371 vtkScatterPlotMatrix::~vtkScatterPlotMatrix()
372 {
373   delete this->Private;
374 }
375 
Update()376 void vtkScatterPlotMatrix::Update()
377 {
378   if (this->Private->VisibleColumnsModified)
379   {
380     // We need to handle layout changes due to modified visibility.
381     // Build up our histograms data before updating the layout.
382     PopulateHistograms(this->Input,
383                        this->Private->Histogram,
384                        this->VisibleColumns,
385                        this->NumberOfBins);
386     this->UpdateLayout();
387     this->Private->VisibleColumnsModified = false;
388   }
389   else if (this->GetMTime() > this->LayoutUpdatedTime)
390   {
391     this->UpdateLayout();
392   }
393 }
394 
Paint(vtkContext2D * painter)395 bool vtkScatterPlotMatrix::Paint(vtkContext2D *painter)
396 {
397   this->CurrentPainter = painter;
398   this->Update();
399   bool ret = this->Superclass::Paint(painter);
400   this->ResizeBigChart();
401   return ret;
402 }
403 
SetScene(vtkContextScene * scene)404 void vtkScatterPlotMatrix::SetScene(vtkContextScene *scene)
405 {
406   // The internal axis shouldn't be a child as it isn't rendered with the
407   // chart, but it does need access to the scene.
408   this->Private->TestAxis->SetScene(scene);
409 
410   this->Superclass::SetScene(scene);
411 }
412 
SetActivePlot(const vtkVector2i & pos)413 bool vtkScatterPlotMatrix::SetActivePlot(const vtkVector2i &pos)
414 {
415   if (pos.GetX() + pos.GetY() + 1 < this->Size.GetX() && pos.GetX() < this->Size.GetX() &&
416       pos.GetY() < this->Size.GetY())
417   {
418     // The supplied index is valid (in the lower quadrant).
419     this->ActivePlot = pos;
420     this->ActivePlotValid = true;
421 
422     // Invoke an interaction event, to let observers know something changed.
423     this->InvokeEvent(vtkCommand::AnnotationChangedEvent);
424 
425     // set background colors for plots
426     if (this->GetChart(this->ActivePlot)->GetPlot(0))
427     {
428       int plotCount = this->GetSize().GetX();
429       for (int i = 0; i < plotCount; ++i)
430       {
431         for (int j = 0; j < plotCount; ++j)
432         {
433           if (this->GetPlotType(i, j) == SCATTERPLOT)
434           {
435             vtkChartXY *chart =
436                 vtkChartXY::SafeDownCast(this->GetChart(vtkVector2i(i, j)));
437 
438             if (pos[0] == i && pos[1] == j)
439             {
440               // set the new active chart background color to light green
441               chart->SetBackgroundBrush(
442                     this->Private->SelectedChartBGBrush);
443             }
444             else if (pos[0] == i || pos[1] == j)
445             {
446               // set background color for all other charts in the selected
447               // chart's row and column to light red
448               chart->SetBackgroundBrush(
449                     this->Private->SelectedRowColumnBGBrush);
450             }
451             else
452             {
453               // set all else to white
454               chart->SetBackgroundBrush(
455                     this->Private->ChartSettings[SCATTERPLOT]
456                     ->BackgroundBrush);
457             }
458           }
459         }
460       }
461     }
462     if (this->Private->BigChart)
463     {
464       vtkPlot *plot = this->Private->BigChart->GetPlot(0);
465       vtkStdString column = this->GetColumnName(pos.GetX());
466       vtkStdString row = this->GetRowName(pos.GetY());
467       if (!plot)
468       {
469         plot = this->Private->BigChart->AddPlot(vtkChart::POINTS);
470         vtkChart *active = this->GetChart(this->ActivePlot);
471         vtkChartXY *xy = vtkChartXY::SafeDownCast(this->Private->BigChart);
472         if (xy)
473         {
474           // Set plot corner, and axis visibility
475           xy->SetPlotCorner(plot, 2);
476           xy->SetAutoAxes(false);
477           xy->GetAxis(vtkAxis::TOP)->SetVisible(true);
478           xy->GetAxis(vtkAxis::RIGHT)->SetVisible(true);
479           xy->GetAxis(vtkAxis::BOTTOM)->SetLabelsVisible(false);
480           xy->GetAxis(vtkAxis::BOTTOM)->SetGridVisible(false);
481           xy->GetAxis(vtkAxis::BOTTOM)->SetTicksVisible(false);
482           xy->GetAxis(vtkAxis::BOTTOM)->SetVisible(true);
483           xy->GetAxis(vtkAxis::LEFT)->SetLabelsVisible(false);
484           xy->GetAxis(vtkAxis::LEFT)->SetGridVisible(false);
485           xy->GetAxis(vtkAxis::LEFT)->SetTicksVisible(false);
486           xy->GetAxis(vtkAxis::LEFT)->SetVisible(true);
487 
488           // set labels array
489           if(this->Private->IndexedLabelsArray)
490           {
491               plot->SetIndexedLabels(this->Private->IndexedLabelsArray);
492               plot->SetTooltipLabelFormat("%i");
493           }
494         }
495         if (xy && active)
496         {
497           vtkAxis *a = active->GetAxis(vtkAxis::BOTTOM);
498           xy->GetAxis(vtkAxis::TOP)->SetUnscaledRange(
499             a->GetUnscaledMinimum(), a->GetUnscaledMaximum());
500           a = active->GetAxis(vtkAxis::LEFT);
501           xy->GetAxis(vtkAxis::RIGHT)->SetUnscaledRange(
502             a->GetUnscaledMinimum(), a->GetUnscaledMaximum());
503         }
504       }
505       else
506       {
507         this->Private->BigChart->ClearPlots();
508         plot = this->Private->BigChart->AddPlot(vtkChart::POINTS);
509         vtkChartXY *xy = vtkChartXY::SafeDownCast(this->Private->BigChart);
510         if (xy)
511         {
512           xy->SetPlotCorner(plot, 2);
513         }
514 
515         // set labels array
516         if(this->Private->IndexedLabelsArray)
517         {
518           plot->SetIndexedLabels(this->Private->IndexedLabelsArray);
519           plot->SetTooltipLabelFormat("%i");
520         }
521       }
522       plot->SetInputData(this->Input, column, row);
523       plot->SetPen(this->Private->ChartSettings[ACTIVEPLOT]
524                    ->PlotPen);
525       this->ApplyAxisSetting(this->Private->BigChart, column, row);
526 
527       // Set marker size and style.
528       vtkPlotPoints *plotPoints = vtkPlotPoints::SafeDownCast(plot);
529       plotPoints->SetMarkerSize(this->Private->ChartSettings[ACTIVEPLOT]
530                                 ->MarkerSize);
531       plotPoints->SetMarkerStyle(this->Private->ChartSettings[ACTIVEPLOT]
532                                  ->MarkerStyle);
533 
534       // Add supplementary plot if any
535       this->AddSupplementaryPlot(this->Private->BigChart, ACTIVEPLOT, row, column, 2);
536 
537       // Set background color.
538       this->Private->BigChart->SetBackgroundBrush(
539             this->Private->ChartSettings[ACTIVEPLOT]
540             ->BackgroundBrush);
541       this->Private->BigChart->GetAxis(vtkAxis::TOP)->SetTitle(
542             this->VisibleColumns->GetValue(pos.GetX()));
543       this->Private->BigChart->GetAxis(vtkAxis::RIGHT)->SetTitle(
544             this->VisibleColumns->GetValue(this->GetSize().GetX() - pos.GetY() - 1));
545       // Calculate the ideal range.
546       //this->Private->BigChart->RecalculateBounds();
547     }
548     return true;
549   }
550   else
551   {
552     return false;
553   }
554 }
555 
GetActivePlot()556 vtkVector2i vtkScatterPlotMatrix::GetActivePlot()
557 {
558   return this->ActivePlot;
559 }
560 
UpdateAnimationPath(const vtkVector2i & newActivePos)561 void vtkScatterPlotMatrix::UpdateAnimationPath(const vtkVector2i& newActivePos)
562 {
563   this->Private->AnimationPath.clear();
564   if (newActivePos[0] != this->ActivePlot[0] ||
565       newActivePos[1] != this->ActivePlot[1])
566   {
567     if (newActivePos[1] >= this->ActivePlot[1])
568     {
569       // x direction first
570       if (this->ActivePlot[0]>newActivePos[0])
571       {
572         for(int r = this->ActivePlot[0] - 1; r >= newActivePos[0]; r--)
573         {
574           this->Private->AnimationPath.push_back(vtkVector2i(r,
575                                                              this->ActivePlot[1]));
576         }
577       }
578       else
579       {
580         for (int r = this->ActivePlot[0] + 1; r <= newActivePos[0]; r++)
581         {
582           this->Private->AnimationPath.push_back(vtkVector2i(r,
583                                                              this->ActivePlot[1]));
584         }
585       }
586       // then y direction
587       for (int c = this->ActivePlot[1] + 1; c <= newActivePos[1]; c++)
588       {
589         this->Private->AnimationPath.push_back(vtkVector2i(newActivePos[0], c));
590       }
591     }
592     else
593     {
594       // y direction first
595       for (int c = this->ActivePlot[1] - 1; c >= newActivePos[1]; c--)
596       {
597         this->Private->AnimationPath.push_back(vtkVector2i(this->ActivePlot[0],
598                                                            c));
599       }
600       // then x direction
601       if (this->ActivePlot[0]>newActivePos[0])
602       {
603         for (int r = this->ActivePlot[0] - 1; r >= newActivePos[0]; r--)
604         {
605           this->Private->AnimationPath.push_back(vtkVector2i(r,
606                                                              newActivePos[1]));
607         }
608       }
609       else
610       {
611         for (int r = this->ActivePlot[0] + 1; r <= newActivePos[0]; r++)
612         {
613           this->Private->AnimationPath.push_back(vtkVector2i(r, newActivePos[1]));
614         }
615       }
616     }
617   }
618 }
619 
StartAnimation(vtkRenderWindowInteractor * interactor)620 void vtkScatterPlotMatrix::StartAnimation(vtkRenderWindowInteractor* interactor)
621 {
622   // Start a simple repeating timer to advance along the path until completion.
623   if (!this->Private->TimerCallbackInitialized && interactor)
624   {
625     this->Animating = true;
626     if (!this->Private->AnimationCallbackInitialized)
627     {
628       this->Private->AnimationCallback->SetClientData(this);
629       this->Private->AnimationCallback->SetCallback(
630             vtkScatterPlotMatrix::ProcessEvents);
631       interactor->AddObserver(vtkCommand::TimerEvent,
632                               this->Private->AnimationCallback,
633                               0);
634       this->Private->Interactor = interactor;
635       this->Private->AnimationCallbackInitialized = true;
636     }
637     this->Private->TimerCallbackInitialized = true;
638     // This defines the interval at which the animation will proceed. 25Hz?
639     this->Private->TimerId = interactor->CreateRepeatingTimer(1000 / 50);
640     this->Private->AnimationIter = this->Private->AnimationPath.begin();
641     this->Private->AnimationPhase = 0;
642   }
643 }
644 
AdvanceAnimation()645 void vtkScatterPlotMatrix::AdvanceAnimation()
646 {
647   // The animation has several phases, and we must track where we are.
648 
649   // 1: Remove decoration from the big chart.
650   // 2: Set three dimensions to plot in the BigChart3D.
651   // 3: Make BigChart invisible, and BigChart3D visible.
652   // 4: Rotate between the two dimensions we are transitioning between.
653   //    -> Loop from start to end angle to complete the effect.
654   // 5: Make the new dimensionality active, update BigChart.
655   // 5: Make BigChart3D invisible and BigChart visible.
656   // 6: Stop the timer.
657   this->InvokeEvent(vtkCommand::AnimationCueTickEvent);
658   switch (this->Private->AnimationPhase)
659   {
660   case 0: // Remove decoration from the big chart, load up the 3D chart
661   {
662     this->Private->NextActivePlot = *this->Private->AnimationIter;
663     vtkChartXYZ *chart = this->Private->BigChart3D;
664     chart->SetVisible(false);
665     chart->SetAutoRotate(true);
666     chart->SetDecorateAxes(false);
667     chart->SetFitToScene(false);
668 
669     int yColumn = this->GetSize().GetY() - this->ActivePlot.GetY() - 1;
670     bool isX = false;
671     int zColumn = 0;
672 
673     vtkRectf size = this->Private->BigChart->GetSize();
674     float zSize;
675     this->Private->FinalAngle = 90.0;
676     this->Private->IncAngle = this->Private->FinalAngle / this->NumberOfFrames;
677 
678     if (this->Private->NextActivePlot.GetY() == this->ActivePlot.GetY())
679     {
680       // Horizontal move.
681       zColumn = this->Private->NextActivePlot.GetX();
682       isX = false;
683       if (this->ActivePlot.GetX() < zColumn)
684       {
685         this->Private->IncAngle *= 1.0;
686         zSize = size.GetWidth();
687       }
688       else
689       {
690         this->Private->IncAngle *= -1.0;
691         zSize = -size.GetWidth();
692       }
693     }
694     else
695     {
696       // Vertical move.
697       zColumn = this->GetSize().GetY() - this->Private->NextActivePlot.GetY() - 1;
698       isX = true;
699       if (this->GetSize().GetY() - this->ActivePlot.GetY() - 1 < zColumn)
700       {
701         this->Private->IncAngle *= -1.0;
702         zSize = size.GetHeight();
703       }
704       else
705       {
706         this->Private->IncAngle *= 1.0;
707         zSize = -size.GetHeight();
708       }
709     }
710     chart->SetAroundX(isX);
711     chart->SetGeometry(size);
712 
713     vtkStdString names[3];
714     names[0] = this->VisibleColumns->GetValue(this->ActivePlot.GetX());
715     names[1] = this->VisibleColumns->GetValue(yColumn);
716     names[2] = this->VisibleColumns->GetValue(zColumn);
717 
718     // Setup the 3D chart
719     this->Private->BigChart3D->ClearPlots();
720     vtkNew<vtkPlotPoints3D> scatterPlot3D;
721     scatterPlot3D->SetInputData(
722       this->Input, names[0], names[1], names[2]);
723     this->Private->BigChart3D->AddPlot(scatterPlot3D);
724 
725     // Set the z axis up so that it ends in the right orientation.
726     chart->GetAxis(2)->SetPoint2(0, zSize);
727     // Now set the ranges for the three axes.
728     for (int i = 0; i < 3; ++i)
729     {
730       PIMPL::ColumnSetting &settings = this->Private->ColumnSettings[names[i]];
731       chart->GetAxis(i)->SetUnscaledRange(settings.min, settings.max);
732     }
733     chart->RecalculateTransform();
734     this->GetScene()->SetDirty(true);
735     ++this->Private->AnimationPhase;
736     return;
737   }
738   case 1: // Make BigChart invisible, and BigChart3D visible.
739     this->Private->BigChart->SetVisible(false);
740     this->AddItem(this->Private->BigChart3D);
741     this->Private->BigChart3D->SetVisible(true);
742     this->GetScene()->SetDirty(true);
743     ++this->Private->AnimationPhase;
744     this->Private->CurrentAngle = 0.0;
745     return;
746   case 2: // Rotation of the 3D chart from start to end angle.
747     if (fabs(this->Private->CurrentAngle) < (this->Private->FinalAngle - 0.001))
748     {
749       this->Private->CurrentAngle += this->Private->IncAngle;
750       this->Private->BigChart3D->SetAngle(this->Private->CurrentAngle);
751     }
752     else
753     {
754       ++this->Private->AnimationPhase;
755     }
756     this->GetScene()->SetDirty(true);
757     return;
758   case 3: // Transition to new dimensionality, update the big chart.
759     this->SetActivePlot(this->Private->NextActivePlot);
760     this->Private->BigChart->Update();
761     this->GetScene()->SetDirty(true);
762     ++this->Private->AnimationPhase;
763     break;
764   case 4:
765     this->GetScene()->SetDirty(true);
766     ++this->Private->AnimationIter;
767     // Clean up - we are done.
768     this->Private->AnimationPhase = 0;
769     if (this->Private->AnimationIter == this->Private->AnimationPath.end())
770     {
771       this->Private->BigChart->SetVisible(true);
772       this->RemoveItem(this->Private->BigChart3D);
773       this->Private->BigChart3D->SetVisible(false);
774       this->Private->Interactor->DestroyTimer(this->Private->TimerId);
775       this->Private->TimerId = 0;
776       this->Private->TimerCallbackInitialized = false;
777       this->Animating = false;
778 
779       // Make sure the active plot is redrawn completely after the animation
780       this->Modified();
781       this->ActivePlotValid = false;
782       this->Update();
783     }
784   }
785 }
786 
ProcessEvents(vtkObject *,unsigned long event,void * clientData,void * callerData)787 void vtkScatterPlotMatrix::ProcessEvents(vtkObject *, unsigned long event,
788                                          void *clientData, void *callerData)
789 {
790   vtkScatterPlotMatrix *self =
791       reinterpret_cast<vtkScatterPlotMatrix *>(clientData);
792   switch (event)
793   {
794     case vtkCommand::TimerEvent:
795     {
796       // We must filter the events to ensure we actually get the timer event we
797       // created. I would love signals and slots...
798       int timerId = *reinterpret_cast<int *>(callerData);   // Seems to work.
799       if (self->Private->TimerCallbackInitialized &&
800           timerId == static_cast<int>(self->Private->TimerId))
801       {
802         self->AdvanceAnimation();
803       }
804       break;
805     }
806     default:
807       break;
808   }
809 }
810 
GetAnnotationLink()811 vtkAnnotationLink* vtkScatterPlotMatrix::GetAnnotationLink()
812 {
813   return this->Private->Link;
814 }
815 
SetInput(vtkTable * table)816 void vtkScatterPlotMatrix::SetInput(vtkTable *table)
817 {
818   if(table && table->GetNumberOfRows() == 0)
819   {
820     // do nothing if the table is empty
821     return;
822   }
823 
824   if (this->Input != table)
825   {
826     // Set the input, then update the size of the scatter plot matrix, set
827     // their inputs and all the other stuff needed.
828     this->Input = table;
829     this->SetSize(vtkVector2i(0, 0));
830     this->Modified();
831 
832     if (table == nullptr)
833     {
834       this->SetColumnVisibilityAll(true);
835       return;
836     }
837     int n = static_cast<int>(this->Input->GetNumberOfColumns());
838     this->SetColumnVisibilityAll(true);
839     this->SetSize(vtkVector2i(n, n));
840   }
841 }
842 
SetColumnVisibility(const vtkStdString & name,bool visible)843 void vtkScatterPlotMatrix::SetColumnVisibility(const vtkStdString &name,
844                                                bool visible)
845 {
846   if (visible)
847   {
848     for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
849     {
850       if (this->VisibleColumns->GetValue(i) == name)
851       {
852         // Already there, nothing more needs to be done
853         return;
854       }
855     }
856     // Add the column to the end of the list if it is a numeric column
857     if (this->Input && this->Input->GetColumnByName(name.c_str()) &&
858         vtkArrayDownCast<vtkDataArray>(this->Input->GetColumnByName(name.c_str())))
859     {
860       this->VisibleColumns->InsertNextValue(name);
861       this->Private->VisibleColumnsModified = true;
862       this->SetSize(vtkVector2i(0, 0));
863       this->SetSize(vtkVector2i(this->VisibleColumns->GetNumberOfTuples(),
864                                 this->VisibleColumns->GetNumberOfTuples()));
865       this->Modified();
866     }
867   }
868   else
869   {
870     // Remove the value if present
871     for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
872     {
873       if (this->VisibleColumns->GetValue(i) == name)
874       {
875         // Move all the later elements down by one, and reduce the size
876         while (i < this->VisibleColumns->GetNumberOfTuples() - 1)
877         {
878           this->VisibleColumns->SetValue(i,
879                                          this->VisibleColumns->GetValue(i + 1));
880           ++i;
881         }
882         this->VisibleColumns->SetNumberOfTuples(
883             this->VisibleColumns->GetNumberOfTuples() - 1);
884         this->SetSize(vtkVector2i(0, 0));
885         this->SetSize(vtkVector2i(this->VisibleColumns->GetNumberOfTuples(),
886                                   this->VisibleColumns->GetNumberOfTuples()));
887         if (this->ActivePlot.GetX() + this->ActivePlot.GetY() + 1 >=
888             this->VisibleColumns->GetNumberOfTuples())
889         {
890           this->ActivePlot.Set(0, this->VisibleColumns->GetNumberOfTuples() - 1);
891         }
892         this->Private->VisibleColumnsModified = true;
893         this->Modified();
894       }
895     }
896   }
897 }
898 
InsertVisibleColumn(const vtkStdString & name,int index)899 void vtkScatterPlotMatrix::InsertVisibleColumn(const vtkStdString &name,
900                                                int index)
901 {
902   if(!this->Input || !this->Input->GetColumnByName(name.c_str()))
903   {
904     return;
905   }
906 
907   // Check if the column is already in the list. If yes,
908   // we may need to rearrange the order of the columns.
909   vtkIdType currIdx = -1;
910   vtkIdType numCols = this->VisibleColumns->GetNumberOfTuples();
911   for (vtkIdType i = 0; i < numCols; ++i)
912   {
913     if (this->VisibleColumns->GetValue(i) == name)
914     {
915       currIdx = i;
916       break;
917     }
918   }
919 
920   if(currIdx > 0 && currIdx == index)
921   {
922     //This column is already there.
923     return;
924   }
925 
926   if(currIdx < 0)
927   {
928     this->VisibleColumns->SetNumberOfTuples(numCols+1);
929     if(index >= numCols)
930     {
931       this->VisibleColumns->SetValue(numCols, name);
932     }
933     else // move all the values after index down 1
934     {
935       vtkIdType startidx = numCols;
936       vtkIdType idx = (index < 0) ? 0 : index;
937       while (startidx > idx)
938       {
939         this->VisibleColumns->SetValue(startidx,
940           this->VisibleColumns->GetValue(startidx-1));
941         startidx--;
942       }
943       this->VisibleColumns->SetValue(idx, name);
944     }
945     this->Private->VisibleColumnsModified = true;
946   }
947   else // need to rearrange table columns
948   {
949     vtkIdType toIdx = (index < 0) ? 0 : index;
950     toIdx = toIdx>numCols ? numCols : toIdx;
951     this->Private->VisibleColumnsModified =
952       MoveColumn(this->VisibleColumns, currIdx, toIdx);
953   }
954   this->LayoutIsDirty = true;
955 }
956 
GetColumnVisibility(const vtkStdString & name)957 bool vtkScatterPlotMatrix::GetColumnVisibility(const vtkStdString &name)
958 {
959   for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
960   {
961     if (this->VisibleColumns->GetValue(i) == name)
962     {
963       return true;
964     }
965   }
966   return false;
967 }
968 
SetColumnVisibilityAll(bool visible)969 void vtkScatterPlotMatrix::SetColumnVisibilityAll(bool visible)
970 {
971   if (visible && this->Input)
972   {
973     vtkIdType n = this->Input->GetNumberOfColumns();
974     this->VisibleColumns->SetNumberOfTuples(n);
975     for (vtkIdType i = 0; i < n; ++i)
976     {
977       this->VisibleColumns->SetValue(i, this->Input->GetColumnName(i));
978     }
979   }
980   else
981   {
982     this->SetSize(vtkVector2i(0, 0));
983     this->VisibleColumns->SetNumberOfTuples(0);
984   }
985 
986   this->Private->VisibleColumnsModified = true;
987 }
988 
GetVisibleColumns()989 vtkStringArray* vtkScatterPlotMatrix::GetVisibleColumns()
990 {
991   return this->VisibleColumns;
992 }
993 
SetVisibleColumns(vtkStringArray * visColumns)994 void vtkScatterPlotMatrix::SetVisibleColumns(vtkStringArray* visColumns)
995 {
996   if(!visColumns || visColumns->GetNumberOfTuples() == 0)
997   {
998     this->SetSize(vtkVector2i(0, 0));
999     this->VisibleColumns->SetNumberOfTuples(0);
1000   }
1001   else
1002   {
1003     this->VisibleColumns->SetNumberOfTuples(
1004       visColumns->GetNumberOfTuples());
1005     this->VisibleColumns->DeepCopy(visColumns);
1006   }
1007   this->Private->VisibleColumnsModified = true;
1008   this->LayoutIsDirty = true;
1009 }
1010 
SetNumberOfBins(int numberOfBins)1011 void vtkScatterPlotMatrix::SetNumberOfBins(int numberOfBins)
1012 {
1013   if (this->NumberOfBins != numberOfBins)
1014   {
1015     this->NumberOfBins = numberOfBins;
1016     if (this->Input)
1017     {
1018       PopulateHistograms(this->Input,
1019                          this->Private->Histogram,
1020                          this->VisibleColumns,
1021                          this->NumberOfBins);
1022     }
1023     this->Modified();
1024   }
1025 }
1026 
SetPlotColor(int plotType,const vtkColor4ub & color)1027 void vtkScatterPlotMatrix::SetPlotColor(int plotType, const vtkColor4ub& color)
1028 {
1029   if(plotType >= 0 && plotType < NOPLOT)
1030   {
1031     if (plotType == ACTIVEPLOT || plotType == SCATTERPLOT)
1032     {
1033       this->Private->ChartSettings[plotType]->PlotPen->SetColor(color);
1034     }
1035     else
1036     {
1037       this->Private->ChartSettings[HISTOGRAM]->PlotBrush->SetColor(color);
1038     }
1039     this->Modified();
1040   }
1041 }
1042 
SetPlotMarkerStyle(int plotType,int style)1043 void vtkScatterPlotMatrix::SetPlotMarkerStyle(int plotType, int style)
1044 {
1045   if(plotType >= 0 && plotType < NOPLOT &&
1046      style != this->Private->ChartSettings[plotType]->MarkerStyle)
1047   {
1048     this->Private->ChartSettings[plotType]->MarkerStyle = style;
1049 
1050     if (plotType == ACTIVEPLOT)
1051     {
1052       vtkChart *chart = this->Private->BigChart;
1053       if (chart)
1054       {
1055         vtkPlotPoints *plot = vtkPlotPoints::SafeDownCast(chart->GetPlot(0));
1056         if (plot)
1057         {
1058           plot->SetMarkerStyle(style);
1059         }
1060       }
1061       this->Modified();
1062     }
1063     else if (plotType == SCATTERPLOT)
1064     {
1065       int plotCount = this->GetSize().GetX();
1066       for (int i = 0; i < plotCount - 1; ++i)
1067       {
1068         for(int j = 0; j < plotCount - 1; ++j)
1069         {
1070           if(this->GetPlotType(i, j) == SCATTERPLOT &&
1071              this->GetChart(vtkVector2i(i, j)))
1072           {
1073             vtkChart *chart = this->GetChart(vtkVector2i(i, j));
1074             vtkPlotPoints *plot = vtkPlotPoints::SafeDownCast(chart->GetPlot(0));
1075             if (plot)
1076             {
1077               plot->SetMarkerStyle(style);
1078             }
1079           }
1080         }
1081       }
1082       this->Modified();
1083     }
1084   }
1085 }
1086 
SetPlotMarkerSize(int plotType,float size)1087 void vtkScatterPlotMatrix::SetPlotMarkerSize(int plotType, float size)
1088 {
1089   if(plotType >= 0 && plotType < NOPLOT &&
1090      size != this->Private->ChartSettings[plotType]->MarkerSize)
1091   {
1092     this->Private->ChartSettings[plotType]->MarkerSize = size;
1093 
1094     if (plotType == ACTIVEPLOT)
1095     {
1096       // update marker size on current active plot
1097       vtkChart *chart = this->Private->BigChart;
1098       if(chart)
1099       {
1100         vtkPlotPoints *plot = vtkPlotPoints::SafeDownCast(chart->GetPlot(0));
1101         if (plot)
1102         {
1103           plot->SetMarkerSize(size);
1104         }
1105       }
1106       this->Modified();
1107     }
1108     else if (plotType == SCATTERPLOT)
1109     {
1110       int plotCount = this->GetSize().GetX();
1111 
1112       for(int i = 0; i < plotCount - 1; i++)
1113       {
1114         for(int j = 0; j < plotCount - 1; j++)
1115         {
1116           if(this->GetPlotType(i, j) == SCATTERPLOT &&
1117              this->GetChart(vtkVector2i(i, j)))
1118           {
1119             vtkChart *chart = this->GetChart(vtkVector2i(i, j));
1120             vtkPlotPoints *plot = vtkPlotPoints::SafeDownCast(chart
1121                                                               ->GetPlot(0));
1122             if (plot)
1123             {
1124               plot->SetMarkerSize(size);
1125             }
1126           }
1127         }
1128       }
1129       this->Modified();
1130     }
1131   }
1132 }
1133 
Hit(const vtkContextMouseEvent &)1134 bool vtkScatterPlotMatrix::Hit(const vtkContextMouseEvent &)
1135 {
1136   return true;
1137 }
1138 
MouseMoveEvent(const vtkContextMouseEvent &)1139 bool vtkScatterPlotMatrix::MouseMoveEvent(const vtkContextMouseEvent &)
1140 {
1141   // Eat the event, don't do anything for now...
1142   return true;
1143 }
1144 
MouseButtonPressEvent(const vtkContextMouseEvent &)1145 bool vtkScatterPlotMatrix::MouseButtonPressEvent(const vtkContextMouseEvent &)
1146 {
1147   return true;
1148 }
1149 
MouseButtonReleaseEvent(const vtkContextMouseEvent & mouse)1150 bool vtkScatterPlotMatrix::MouseButtonReleaseEvent(
1151     const vtkContextMouseEvent &mouse)
1152 {
1153   // Check we are not currently already animating
1154   if (this->Private->TimerCallbackInitialized)
1155   {
1156     return true;
1157   }
1158 
1159   // Work out which scatter plot was clicked - make that one the active plot.
1160   vtkVector2i pos = this->GetChartIndex(mouse.GetPos());
1161 
1162   if(pos.GetX() == -1 || pos.GetX() + pos.GetY() + 1 >= this->Size.GetX())
1163   {
1164     // We didn't click a chart in the bottom-left triangle of the matrix.
1165     return true;
1166   }
1167 
1168   // If the left button was used, hyperjump, if the right was used full path.
1169   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
1170   {
1171     if (this->NumberOfFrames == 0)
1172     {
1173       this->SetActivePlot(pos);
1174       return true;
1175     }
1176     this->Private->AnimationPath.clear();
1177     bool horizontalFirst = pos[0] > this->ActivePlot[0] ? false : true;
1178     if (horizontalFirst)
1179     {
1180       if (pos[0] != this->ActivePlot[0])
1181       {
1182         this->Private->AnimationPath.push_back(vtkVector2i(pos[0],
1183                                                            this->ActivePlot[1]));
1184       }
1185     }
1186     else
1187     {
1188       if (pos[1] != this->ActivePlot[1])
1189       {
1190         this->Private->AnimationPath.push_back(vtkVector2i(this->ActivePlot[0],
1191                                                            pos[1]));
1192       }
1193     }
1194     if ((this->Private->AnimationPath.size() == 1 &&
1195          this->Private->AnimationPath.back() != pos) ||
1196         (this->Private->AnimationPath.empty() && this->ActivePlot != pos))
1197     {
1198       this->Private->AnimationPath.push_back(pos);
1199     }
1200     if (!this->Private->AnimationPath.empty())
1201     {
1202       this->InvokeEvent(vtkCommand::CreateTimerEvent);
1203       this->StartAnimation(mouse.GetInteractor());
1204     }
1205   }
1206   else if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON)
1207   {
1208     if (this->NumberOfFrames == 0)
1209     {
1210       this->SetActivePlot(pos);
1211       return true;
1212     }
1213     this->UpdateAnimationPath(pos);
1214     if (!this->Private->AnimationPath.empty())
1215     {
1216       this->InvokeEvent(vtkCommand::CreateTimerEvent);
1217       this->StartAnimation(mouse.GetInteractor());
1218     }
1219     else
1220     {
1221       this->SetActivePlot(pos);
1222     }
1223   }
1224 
1225   return true;
1226 }
1227 
SetNumberOfFrames(int frames)1228 void vtkScatterPlotMatrix::SetNumberOfFrames(int frames)
1229 {
1230   this->NumberOfFrames = frames;
1231 }
1232 
GetNumberOfFrames()1233 int vtkScatterPlotMatrix::GetNumberOfFrames()
1234 {
1235   return this->NumberOfFrames;
1236 }
1237 
ClearAnimationPath()1238 void vtkScatterPlotMatrix::ClearAnimationPath()
1239 {
1240   this->Private->AnimationPath.clear();
1241 }
1242 
GetNumberOfAnimationPathElements()1243 vtkIdType vtkScatterPlotMatrix::GetNumberOfAnimationPathElements()
1244 {
1245   return static_cast<vtkIdType>(this->Private->AnimationPath.size());
1246 }
1247 
GetAnimationPathElement(vtkIdType i)1248 vtkVector2i vtkScatterPlotMatrix::GetAnimationPathElement(vtkIdType i)
1249 {
1250   return this->Private->AnimationPath.at(i);
1251 }
1252 
AddAnimationPath(const vtkVector2i & move)1253 bool vtkScatterPlotMatrix::AddAnimationPath(const vtkVector2i &move)
1254 {
1255   vtkVector2i pos = this->ActivePlot;
1256   if (!this->Private->AnimationPath.empty())
1257   {
1258     pos = this->Private->AnimationPath.back();
1259   }
1260   if (move.GetX() != pos.GetX() && move.GetY() != pos.GetY())
1261   {
1262     // Can only move in x or y, not both. Do not append the element.
1263     return false;
1264   }
1265   else
1266   {
1267     this->Private->AnimationPath.push_back(move);
1268     return true;
1269   }
1270 }
1271 
BeginAnimationPath(vtkRenderWindowInteractor * interactor)1272 bool vtkScatterPlotMatrix::BeginAnimationPath(vtkRenderWindowInteractor* interactor)
1273 {
1274   if (interactor && !this->Private->AnimationPath.empty())
1275   {
1276     this->StartAnimation(interactor);
1277     return true;
1278   }
1279   else
1280   {
1281     return false;
1282   }
1283 }
1284 
GetPlotType(const vtkVector2i & pos)1285 int vtkScatterPlotMatrix::GetPlotType(const vtkVector2i &pos)
1286 {
1287   int plotCount = this->GetSize().GetX();
1288 
1289   if(pos.GetX() + pos.GetY() + 1 < plotCount)
1290   {
1291     return SCATTERPLOT;
1292   }
1293   else if(pos.GetX() + pos.GetY() + 1 == plotCount)
1294   {
1295     return HISTOGRAM;
1296   }
1297   else if(pos.GetX() == pos.GetY() &&
1298           pos.GetX() == static_cast<int>(plotCount / 2.0) + plotCount % 2)
1299   {
1300     return ACTIVEPLOT;
1301   }
1302   else
1303   {
1304       return NOPLOT;
1305   }
1306 }
1307 
GetPlotType(int row,int column)1308 int vtkScatterPlotMatrix::GetPlotType(int row, int column)
1309 {
1310   return this->GetPlotType(vtkVector2i(row, column));
1311 }
1312 
UpdateAxes()1313 void vtkScatterPlotMatrix::UpdateAxes()
1314 {
1315   if (!this->Input)
1316   {
1317     return;
1318   }
1319   // We need to iterate through all visible columns and set up the axis ranges.
1320   vtkAxis *axis(this->Private->TestAxis);
1321   axis->SetPoint1(0, 0);
1322   axis->SetPoint2(0, 200);
1323   for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
1324   {
1325     double range[2] = { 0, 0 };
1326     std::string name(this->VisibleColumns->GetValue(i));
1327     vtkDataArray *arr =
1328         vtkArrayDownCast<vtkDataArray>(this->Input->GetColumnByName(name.c_str()));
1329     if (arr)
1330     {
1331       PIMPL::ColumnSetting settings;
1332       arr->GetRange(range);
1333       // Apply a little padding either side of the ranges.
1334       range[0] = range[0] - (0.01 * range[0]);
1335       range[1] = range[1] + (0.01 * range[1]);
1336       axis->SetUnscaledRange(range);
1337       axis->AutoScale();
1338       settings.min = axis->GetUnscaledMinimum();
1339       settings.max = axis->GetUnscaledMaximum();
1340       settings.nTicks = axis->GetNumberOfTicks();
1341       settings.title = name;
1342       this->Private->ColumnSettings[name] = settings;
1343     }
1344     else
1345     {
1346       vtkDebugMacro(<< "No valid data array available. " << name);
1347     }
1348   }
1349 }
1350 
GetColumnName(int column)1351 vtkStdString vtkScatterPlotMatrix::GetColumnName(int column)
1352 {
1353   assert(column < this->VisibleColumns->GetNumberOfTuples());
1354   return this->VisibleColumns->GetValue(column);
1355 }
1356 
GetRowName(int row)1357 vtkStdString vtkScatterPlotMatrix::GetRowName(int row)
1358 {
1359   assert(row < this->VisibleColumns->GetNumberOfTuples());
1360   return this->VisibleColumns->GetValue(this->Size.GetY() - row - 1);
1361 }
1362 
ApplyAxisSetting(vtkChart * chart,const vtkStdString & x,const vtkStdString & y)1363 void vtkScatterPlotMatrix::ApplyAxisSetting(vtkChart *chart,
1364                                             const vtkStdString &x,
1365                                             const vtkStdString &y)
1366 {
1367   PIMPL::ColumnSetting &xSettings = this->Private->ColumnSettings[x];
1368   PIMPL::ColumnSetting &ySettings = this->Private->ColumnSettings[y];
1369   vtkAxis *axis = chart->GetAxis(vtkAxis::BOTTOM);
1370   axis->SetUnscaledRange(xSettings.min, xSettings.max);
1371   axis->SetBehavior(vtkAxis::FIXED);
1372   axis = chart->GetAxis(vtkAxis::TOP);
1373   axis->SetUnscaledRange(xSettings.min, xSettings.max);
1374   axis->SetBehavior(vtkAxis::FIXED);
1375   axis = chart->GetAxis(vtkAxis::LEFT);
1376   axis->SetUnscaledRange(ySettings.min, ySettings.max);
1377   axis->SetBehavior(vtkAxis::FIXED);
1378   axis = chart->GetAxis(vtkAxis::RIGHT);
1379   axis->SetUnscaledRange(ySettings.min, ySettings.max);
1380   axis->SetBehavior(vtkAxis::FIXED);
1381 }
1382 
UpdateLayout()1383 void vtkScatterPlotMatrix::UpdateLayout()
1384 {
1385   // We want scatter plots on the lower-left triangle, then histograms along
1386   // the diagonal and a big plot in the top-right. The basic layout is,
1387   //
1388   // 3 H   +++
1389   // 2 S H +++
1390   // 1 S S H
1391   // 0 S S S H
1392   //   0 1 2 3
1393   //
1394   // Where the indices are those of the columns. The indices of the charts
1395   // originate in the bottom-left. S = scatter plot, H = histogram and + is the
1396   // big chart.
1397   this->LayoutUpdatedTime = this->GetMTime();
1398   int n = this->Size.GetX();
1399   this->UpdateAxes();
1400   this->Private->BigChart3D->SetAnnotationLink(this->Private->Link);
1401   for (int i = 0; i < n; ++i)
1402     {
1403     vtkStdString column = this->GetColumnName(i);
1404     for (int j = 0; j < n; ++j)
1405       {
1406       vtkStdString row = this->GetRowName(j);
1407       vtkVector2i pos(i, j);
1408       if (this->GetPlotType(pos) == SCATTERPLOT)
1409         {
1410         vtkChart* chart = this->GetChart(pos);
1411         this->ApplyAxisSetting(chart, column, row);
1412         chart->ClearPlots();
1413         chart->SetInteractive(false);
1414         chart->SetAnnotationLink(this->Private->Link);
1415         // Lower-left triangle - scatter plots.
1416         chart->SetActionToButton(vtkChart::PAN, -1);
1417         chart->SetActionToButton(vtkChart::ZOOM, -1);
1418         chart->SetActionToButton(vtkChart::SELECT, -1);
1419         vtkPlot *plot = chart->AddPlot(vtkChart::POINTS);
1420         plot->SetInputData(this->Input, column, row);
1421         plot->SetPen(this->Private->ChartSettings[SCATTERPLOT]
1422                      ->PlotPen);
1423         // set plot marker size and style
1424         vtkPlotPoints *plotPoints = vtkPlotPoints::SafeDownCast(plot);
1425         plotPoints->SetMarkerSize(this->Private->ChartSettings[SCATTERPLOT]
1426                                   ->MarkerSize);
1427         plotPoints->SetMarkerStyle(this->Private->ChartSettings[SCATTERPLOT]
1428                                    ->MarkerStyle);
1429         this->AddSupplementaryPlot(chart, SCATTERPLOT, row, column);
1430         }
1431       else if (this->GetPlotType(pos) == HISTOGRAM)
1432         {
1433         // We are on the diagonal - need a histogram plot.
1434         vtkChart* chart = this->GetChart(pos);
1435         chart->SetInteractive(false);
1436         this->ApplyAxisSetting(chart, column, row);
1437         chart->ClearPlots();
1438         vtkPlot *plot = chart->AddPlot(vtkChart::BAR);
1439         plot->SetPen(this->Private->ChartSettings[HISTOGRAM]
1440                      ->PlotPen);
1441         plot->SetBrush(this->Private->ChartSettings[HISTOGRAM]
1442                        ->PlotBrush);
1443         vtkStdString name(this->VisibleColumns->GetValue(i));
1444         plot->SetInputData(this->Private->Histogram,
1445                            name + "_extents", name + "_pops");
1446         vtkAxis *axis = chart->GetAxis(vtkAxis::TOP);
1447         axis->SetTitle(name);
1448         axis->SetLabelsVisible(false);
1449         // Show the labels on the right for populations of bins.
1450         axis = chart->GetAxis(vtkAxis::RIGHT);
1451         axis->SetLabelsVisible(true);
1452         axis->SetBehavior(vtkAxis::AUTO);
1453         axis->AutoScale();
1454         // Set the plot corner to the top-right
1455         vtkChartXY *xy = vtkChartXY::SafeDownCast(chart);
1456         if (xy)
1457           {
1458           xy->SetBarWidthFraction(1.0);
1459           xy->SetPlotCorner(plot, 2);
1460           }
1461 
1462         // set background color to light gray
1463         xy->SetBackgroundBrush(this->Private->ChartSettings[HISTOGRAM]
1464                                ->BackgroundBrush);
1465         }
1466       else if (this->GetPlotType(pos) == ACTIVEPLOT)
1467         {
1468         // This big plot in the top-right
1469         this->Private->BigChart = this->GetChart(pos);
1470         this->Private->BigChartPos = pos;
1471         this->Private->BigChart->SetAnnotationLink(
1472               this->Private->Link);
1473         this->Private->BigChart->AddObserver(
1474           vtkCommand::SelectionChangedEvent, this,
1475           &vtkScatterPlotMatrix::BigChartSelectionCallback);
1476 
1477         // set tooltip item
1478         vtkChartXY *chartXY =
1479           vtkChartXY::SafeDownCast(this->Private->BigChart);
1480         if(chartXY)
1481           {
1482           chartXY->SetTooltip(this->Private->TooltipItem);
1483           }
1484 
1485         this->SetChartSpan(pos, vtkVector2i(n - i, n - j));
1486         if (!this->ActivePlotValid)
1487         {
1488           if (this->ActivePlot.GetY() < 0)
1489           {
1490             this->ActivePlot = vtkVector2i(0, n - 2);
1491           }
1492           this->SetActivePlot(this->ActivePlot);
1493         }
1494         }
1495       // Only show bottom axis label for bottom plots
1496       if (j > 0)
1497         {
1498         vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
1499         axis->SetTitle("");
1500         axis->SetLabelsVisible(false);
1501         axis->SetBehavior(vtkAxis::FIXED);
1502         }
1503       else
1504         {
1505         vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
1506         axis->SetTitle(this->VisibleColumns->GetValue(i));
1507         axis->SetLabelsVisible(false);
1508         this->AttachAxisRangeListener(axis);
1509         }
1510       // Only show the left axis labels for left-most plots
1511       if (i > 0)
1512         {
1513         vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
1514         axis->SetTitle("");
1515         axis->SetLabelsVisible(false);
1516         axis->SetBehavior(vtkAxis::FIXED);
1517         }
1518       else
1519         {
1520         vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
1521         axis->SetTitle(this->VisibleColumns->GetValue(n - j - 1));
1522         axis->SetLabelsVisible(false);
1523         this->AttachAxisRangeListener(axis);
1524         }
1525       }
1526     }
1527 }
1528 
ResizeBigChart()1529 void vtkScatterPlotMatrix::ResizeBigChart()
1530 {
1531   if (!this->Private->ResizingBigChart)
1532     {
1533     this->ClearSpecificResizes();
1534     int n = this->Size.GetX();
1535     // The big chart need to be resized only when it is
1536     // "between" the histograms, ie. when n is even.
1537     if (n%2 == 0)
1538       {
1539       // 30*30 is an acceptable default size to resize with
1540       int resizeX = 30;
1541       int resizeY = 30;
1542       if (this->CurrentPainter)
1543         {
1544         // Try to use painter to resize the big plot
1545         int i = this->Private->BigChartPos.GetX();
1546         int j = this->Private->BigChartPos.GetY();
1547         vtkVector2i posLeft(i - 1, j);
1548         vtkVector2i posBottom(i, j - 1);
1549         vtkChart* leftChart = this->GetChart(posLeft);
1550         vtkChart* bottomChart = this->GetChart(posLeft);
1551         if (leftChart)
1552           {
1553           vtkAxis* leftAxis = leftChart->GetAxis(vtkAxis::RIGHT);
1554           if (leftAxis)
1555             {
1556             resizeX = std::max(leftAxis->GetBoundingRect(
1557               this->CurrentPainter).GetWidth() - this->Gutter.GetX(), this->Gutter.GetX());
1558             }
1559           }
1560         if (bottomChart)
1561           {
1562           vtkAxis* bottomAxis = bottomChart->GetAxis(vtkAxis::TOP);
1563           if (bottomAxis)
1564             {
1565             resizeY = std::max(bottomAxis->GetBoundingRect(
1566               this->CurrentPainter).GetHeight() - this->Gutter.GetY(), this->Gutter.GetY());
1567             }
1568           }
1569         }
1570 
1571       // Move big plot bottom left point to avoid overlap
1572       vtkVector2f resize(resizeX, resizeY);
1573       this->SetSpecificResize(this->Private->BigChartPos, resize);
1574       if (this->LayoutIsDirty)
1575         {
1576         this->Private->ResizingBigChart = true;
1577         this->GetScene()->SetDirty(true);
1578         }
1579       }
1580     }
1581   else
1582     {
1583     this->Private->ResizingBigChart = false;
1584     }
1585 }
1586 
AttachAxisRangeListener(vtkAxis * axis)1587 void vtkScatterPlotMatrix::AttachAxisRangeListener(vtkAxis* axis)
1588 {
1589   axis->AddObserver(vtkChart::UpdateRange, this,
1590                     &vtkScatterPlotMatrix::AxisRangeForwarderCallback);
1591 }
1592 
AxisRangeForwarderCallback(vtkObject *,unsigned long,void *)1593 void vtkScatterPlotMatrix::AxisRangeForwarderCallback(vtkObject*,
1594                                                       unsigned long, void*)
1595 {
1596   // Only set on the end axes, and propagated to all other matching axes.
1597   double r[2];
1598   int n = this->GetSize().GetX() - 1;
1599   for (int i = 0; i < n; ++i)
1600   {
1601     this->GetChart(vtkVector2i(i, 0))
1602       ->GetAxis(vtkAxis::BOTTOM)
1603       ->GetUnscaledRange(r);
1604     for (int j = 1; j < n - i; ++j)
1605     {
1606       this->GetChart(vtkVector2i(i, j))
1607         ->GetAxis(vtkAxis::BOTTOM)
1608         ->SetUnscaledRange(r);
1609     }
1610     this->GetChart(vtkVector2i(i, n-i))
1611       ->GetAxis(vtkAxis::TOP)
1612       ->SetUnscaledRange(r);
1613     this->GetChart(vtkVector2i(0, i))
1614       ->GetAxis(vtkAxis::LEFT)
1615       ->GetUnscaledRange(r);
1616     for (int j = 1; j < n - i; ++j)
1617     {
1618       this->GetChart(vtkVector2i(j, i))
1619         ->GetAxis(vtkAxis::LEFT)
1620         ->SetUnscaledRange(r);
1621     }
1622   }
1623 }
1624 
BigChartSelectionCallback(vtkObject *,unsigned long event,void *)1625 void vtkScatterPlotMatrix::BigChartSelectionCallback(vtkObject*,
1626   unsigned long event, void*)
1627 {
1628   // forward the SelectionChangedEvent from the Big Chart plot
1629   this->InvokeEvent(event);
1630 }
1631 
SetTitle(const vtkStdString & title)1632 void vtkScatterPlotMatrix::SetTitle(const vtkStdString& title)
1633 {
1634   if (this->Title != title)
1635   {
1636     this->Title = title;
1637     this->Modified();
1638   }
1639 }
1640 
GetTitle()1641 vtkStdString vtkScatterPlotMatrix::GetTitle()
1642 {
1643   return this->Title;
1644 }
1645 
SetTitleProperties(vtkTextProperty * prop)1646 void vtkScatterPlotMatrix::SetTitleProperties(vtkTextProperty *prop)
1647 {
1648   if (this->TitleProperties != prop)
1649   {
1650     this->TitleProperties = prop;
1651     this->Modified();
1652   }
1653 }
1654 
GetTitleProperties()1655 vtkTextProperty* vtkScatterPlotMatrix::GetTitleProperties()
1656 {
1657   return this->TitleProperties;
1658 }
1659 
SetAxisLabelProperties(int plotType,vtkTextProperty * prop)1660 void vtkScatterPlotMatrix::SetAxisLabelProperties(int plotType,
1661                                                   vtkTextProperty *prop)
1662 {
1663   if (plotType >= 0 && plotType < vtkScatterPlotMatrix::NOPLOT &&
1664       this->Private->ChartSettings[plotType]->LabelFont != prop)
1665   {
1666     this->Private->ChartSettings[plotType]->LabelFont = prop;
1667     this->Modified();
1668   }
1669 }
1670 
GetAxisLabelProperties(int plotType)1671 vtkTextProperty* vtkScatterPlotMatrix::GetAxisLabelProperties(int plotType)
1672 {
1673   if (plotType >= 0 && plotType < vtkScatterPlotMatrix::NOPLOT)
1674   {
1675     return this->Private->ChartSettings[plotType]->LabelFont;
1676   }
1677   return nullptr;
1678 }
1679 
1680 //----------------------------------------------------------------------------
SetBackgroundColor(int plotType,const vtkColor4ub & color)1681 void vtkScatterPlotMatrix::SetBackgroundColor(int plotType,
1682                                               const vtkColor4ub& color)
1683 {
1684   if (plotType >= 0 && plotType < vtkScatterPlotMatrix::NOPLOT)
1685   {
1686     this->Private->ChartSettings[plotType]->BackgroundBrush->SetColor(color);
1687     this->Modified();
1688   }
1689 }
1690 
1691 //----------------------------------------------------------------------------
SetAxisColor(int plotType,const vtkColor4ub & color)1692 void vtkScatterPlotMatrix::SetAxisColor(int plotType,
1693                                         const vtkColor4ub& color)
1694 {
1695   if (plotType >= 0 && plotType < vtkScatterPlotMatrix::NOPLOT)
1696   {
1697     this->Private->ChartSettings[plotType]->AxisColor = color;
1698     this->Modified();
1699   }
1700 }
1701 
1702 //----------------------------------------------------------------------------
SetGridVisibility(int plotType,bool visible)1703 void vtkScatterPlotMatrix::SetGridVisibility(int plotType, bool visible)
1704 {
1705   if(plotType!= NOPLOT)
1706   {
1707     this->Private->ChartSettings[plotType]->ShowGrid = visible;
1708     // How to update
1709     this->Modified();
1710   }
1711 }
1712 
1713 //----------------------------------------------------------------------------
SetGridColor(int plotType,const vtkColor4ub & color)1714 void vtkScatterPlotMatrix::SetGridColor(int plotType,
1715                                         const vtkColor4ub& color)
1716 {
1717   if (plotType >= 0 && plotType < vtkScatterPlotMatrix::NOPLOT)
1718   {
1719     this->Private->ChartSettings[plotType]->GridColor = color;
1720     // How to update
1721     this->Modified();
1722   }
1723 }
1724 
1725 //----------------------------------------------------------------------------
SetAxisLabelVisibility(int plotType,bool visible)1726 void vtkScatterPlotMatrix::SetAxisLabelVisibility(int plotType, bool visible)
1727 {
1728   if(plotType!= NOPLOT)
1729   {
1730     this->Private->ChartSettings[plotType]->ShowAxisLabels = visible;
1731     // How to update
1732     this->Modified();
1733   }
1734 }
1735 
1736 //----------------------------------------------------------------------------
SetAxisLabelNotation(int plotType,int notation)1737 void vtkScatterPlotMatrix::SetAxisLabelNotation(int plotType, int notation)
1738 {
1739   if(plotType!= NOPLOT)
1740   {
1741     this->Private->ChartSettings[plotType]->LabelNotation = notation;
1742     // How to update
1743     this->Modified();
1744   }
1745 }
1746 
1747 //----------------------------------------------------------------------------
SetAxisLabelPrecision(int plotType,int precision)1748 void vtkScatterPlotMatrix::SetAxisLabelPrecision(int plotType, int precision)
1749 {
1750   if(plotType!= NOPLOT)
1751   {
1752     this->Private->ChartSettings[plotType]->LabelPrecision = precision;
1753     // How to update
1754     this->Modified();
1755   }
1756 }
1757 
1758 //----------------------------------------------------------------------------
SetTooltipNotation(int plotType,int notation)1759 void vtkScatterPlotMatrix::SetTooltipNotation(int plotType, int notation)
1760 {
1761   if(plotType!= NOPLOT)
1762   {
1763     this->Private->ChartSettings[plotType]->TooltipNotation = notation;
1764     // How to update
1765     this->Modified();
1766   }
1767 }
1768 
1769 //----------------------------------------------------------------------------
SetTooltipPrecision(int plotType,int precision)1770 void vtkScatterPlotMatrix::SetTooltipPrecision(int plotType, int precision)
1771 {
1772   if(plotType!= NOPLOT)
1773   {
1774     this->Private->ChartSettings[plotType]->TooltipPrecision = precision;
1775     // How to update
1776     this->Modified();
1777   }
1778 }
1779 
1780 //----------------------------------------------------------------------------
SetScatterPlotSelectedRowColumnColor(const vtkColor4ub & color)1781 void vtkScatterPlotMatrix::SetScatterPlotSelectedRowColumnColor(
1782     const vtkColor4ub& color)
1783 {
1784   this->Private->SelectedRowColumnBGBrush->SetColor(color);
1785   this->Modified();
1786 }
1787 
1788 //----------------------------------------------------------------------------
SetScatterPlotSelectedActiveColor(const vtkColor4ub & color)1789 void vtkScatterPlotMatrix::SetScatterPlotSelectedActiveColor(
1790     const vtkColor4ub& color)
1791 {
1792   this->Private->SelectedChartBGBrush->SetColor(color);
1793   this->Modified();
1794 }
1795 
1796 //----------------------------------------------------------------------------
UpdateChartSettings(int plotType)1797 void vtkScatterPlotMatrix::UpdateChartSettings(int plotType)
1798 {
1799   if (plotType == HISTOGRAM)
1800   {
1801     int plotCount = this->GetSize().GetX();
1802 
1803     for(int i = 0; i < plotCount; i++)
1804     {
1805       vtkChart *chart = this->GetChart(vtkVector2i(i, plotCount - i - 1));
1806       this->Private->UpdateAxis(chart->GetAxis(vtkAxis::TOP),
1807                                 this->Private->ChartSettings[HISTOGRAM]);
1808       this->Private->UpdateAxis(chart->GetAxis(vtkAxis::RIGHT),
1809                                 this->Private->ChartSettings[HISTOGRAM]);
1810       this->Private->UpdateChart(chart, this->Private->ChartSettings[HISTOGRAM]);
1811     }
1812   }
1813   else if (plotType == SCATTERPLOT)
1814   {
1815     int plotCount = this->GetSize().GetX();
1816 
1817     for (int i = 0; i < plotCount - 1; i++)
1818     {
1819       for (int j = 0; j < plotCount - 1; j++)
1820       {
1821         if (this->GetPlotType(i, j) == SCATTERPLOT)
1822         {
1823           vtkChart *chart = this->GetChart(vtkVector2i(i, j));
1824           bool updateleft = i==0 ? true : false;
1825           bool updatebottom = j==0 ? true : false;
1826           this->Private->UpdateAxis(chart->GetAxis(vtkAxis::LEFT),
1827             this->Private->ChartSettings[SCATTERPLOT], updateleft);
1828           this->Private->UpdateAxis(chart->GetAxis(vtkAxis::BOTTOM),
1829             this->Private->ChartSettings[SCATTERPLOT], updatebottom);
1830         }
1831       }
1832     }
1833   }
1834   else if (plotType == ACTIVEPLOT && this->Private->BigChart)
1835   {
1836     this->Private->UpdateAxis(this->Private->BigChart->GetAxis(vtkAxis::TOP),
1837                               this->Private->ChartSettings[ACTIVEPLOT]);
1838     this->Private->UpdateAxis(this->Private->BigChart->GetAxis(vtkAxis::RIGHT),
1839                               this->Private->ChartSettings[ACTIVEPLOT]);
1840     this->Private->UpdateChart(this->Private->BigChart,
1841                                this->Private->ChartSettings[ACTIVEPLOT]);
1842     this->Private->BigChart->SetSelectionMode(this->SelectionMode);
1843   }
1844   this->Modified();
1845 }
1846 //-----------------------------------------------------------------------------
SetSelectionMode(int selMode)1847 void vtkScatterPlotMatrix::SetSelectionMode(int selMode)
1848 {
1849   if (this->SelectionMode == selMode ||
1850       selMode < vtkContextScene::SELECTION_NONE ||
1851       selMode > vtkContextScene::SELECTION_TOGGLE)
1852   {
1853     return;
1854   }
1855   this->SelectionMode = selMode;
1856   if(this->Private->BigChart)
1857   {
1858     this->Private->BigChart->SetSelectionMode(selMode);
1859   }
1860 
1861   this->Modified();
1862 }
1863 
1864 //-----------------------------------------------------------------------------
SetSize(const vtkVector2i & size)1865 void vtkScatterPlotMatrix::SetSize(const vtkVector2i &size)
1866 {
1867   if (this->Size.GetX() != size.GetX() || this->Size.GetY() != size.GetY())
1868   {
1869     this->ActivePlotValid = false;
1870     this->ActivePlot = vtkVector2i(0, this->Size.GetX() - 2);
1871   }
1872   this->Superclass::SetSize(size);
1873 }
1874 
1875 //----------------------------------------------------------------------------
UpdateSettings()1876 void vtkScatterPlotMatrix::UpdateSettings()
1877 {
1878 
1879 // TODO: Should update the Scatter plot title
1880 
1881   this->UpdateChartSettings(ACTIVEPLOT);
1882   this->UpdateChartSettings(HISTOGRAM);
1883   this->UpdateChartSettings(SCATTERPLOT);
1884 }
1885 
1886 //----------------------------------------------------------------------------
GetGridVisibility(int plotType)1887 bool vtkScatterPlotMatrix::GetGridVisibility(int plotType)
1888 {
1889   assert(plotType != NOPLOT);
1890   return this->Private->ChartSettings[plotType]->ShowGrid;
1891 }
1892 
1893 //----------------------------------------------------------------------------
GetBackgroundColor(int plotType)1894 vtkColor4ub vtkScatterPlotMatrix::GetBackgroundColor(int plotType)
1895 {
1896   assert(plotType != NOPLOT);
1897   return this->Private->ChartSettings[plotType]->BackgroundBrush
1898       ->GetColorObject();
1899 }
1900 
1901 //----------------------------------------------------------------------------
GetAxisColor(int plotType)1902 vtkColor4ub vtkScatterPlotMatrix::GetAxisColor(int plotType)
1903 {
1904   assert(plotType != NOPLOT);
1905   return this->Private->ChartSettings[plotType]->AxisColor;
1906 }
1907 
1908 //----------------------------------------------------------------------------
GetGridColor(int plotType)1909 vtkColor4ub vtkScatterPlotMatrix::GetGridColor(int plotType)
1910 {
1911   assert(plotType != NOPLOT);
1912   return this->Private->ChartSettings[plotType]->GridColor;
1913 }
1914 
1915 //----------------------------------------------------------------------------
GetAxisLabelVisibility(int plotType)1916 bool vtkScatterPlotMatrix::GetAxisLabelVisibility(int plotType)
1917 {
1918   assert(plotType != NOPLOT);
1919   return this->Private->ChartSettings[plotType]->ShowAxisLabels;
1920 }
1921 
1922 //----------------------------------------------------------------------------
GetAxisLabelNotation(int plotType)1923 int vtkScatterPlotMatrix::GetAxisLabelNotation(int plotType)
1924 {
1925   assert(plotType != NOPLOT);
1926   return this->Private->ChartSettings[plotType]->LabelNotation;
1927 }
1928 
1929 //----------------------------------------------------------------------------
GetAxisLabelPrecision(int plotType)1930 int vtkScatterPlotMatrix::GetAxisLabelPrecision(int plotType)
1931 {
1932   assert(plotType != NOPLOT);
1933   return this->Private->ChartSettings[plotType]->LabelPrecision;
1934 }
1935 
1936 //----------------------------------------------------------------------------
GetTooltipNotation(int plotType)1937 int vtkScatterPlotMatrix::GetTooltipNotation(int plotType)
1938 {
1939   assert(plotType != NOPLOT);
1940   return this->Private->ChartSettings[plotType]->TooltipNotation;
1941 }
1942 
GetTooltipPrecision(int plotType)1943 int vtkScatterPlotMatrix::GetTooltipPrecision(int plotType)
1944 {
1945   assert(plotType != NOPLOT);
1946   return this->Private->ChartSettings[plotType]->TooltipPrecision;
1947 }
1948 
1949 //----------------------------------------------------------------------------
SetTooltip(vtkTooltipItem * tooltip)1950 void vtkScatterPlotMatrix::SetTooltip(vtkTooltipItem *tooltip)
1951 {
1952   if(tooltip != this->Private->TooltipItem)
1953   {
1954     this->Private->TooltipItem = tooltip;
1955     this->Modified();
1956 
1957     vtkChartXY *chartXY =
1958       vtkChartXY::SafeDownCast(this->Private->BigChart);
1959 
1960     if(chartXY)
1961     {
1962       chartXY->SetTooltip(tooltip);
1963     }
1964   }
1965 }
1966 
1967 //----------------------------------------------------------------------------
GetTooltip() const1968 vtkTooltipItem* vtkScatterPlotMatrix::GetTooltip() const
1969 {
1970   return this->Private->TooltipItem;
1971 }
1972 
1973 //----------------------------------------------------------------------------
SetIndexedLabels(vtkStringArray * labels)1974 void vtkScatterPlotMatrix::SetIndexedLabels(vtkStringArray *labels)
1975 {
1976   if(labels != this->Private->IndexedLabelsArray)
1977   {
1978     this->Private->IndexedLabelsArray = labels;
1979     this->Modified();
1980 
1981     if(this->Private->BigChart)
1982     {
1983       vtkPlot *plot = this->Private->BigChart->GetPlot(0);
1984 
1985       if(plot)
1986       {
1987         plot->SetIndexedLabels(labels);
1988       }
1989     }
1990   }
1991 }
1992 
1993 //----------------------------------------------------------------------------
GetIndexedLabels() const1994 vtkStringArray* vtkScatterPlotMatrix::GetIndexedLabels() const
1995 {
1996   return this->Private->IndexedLabelsArray;
1997 }
1998 
1999 //----------------------------------------------------------------------------
GetScatterPlotSelectedRowColumnColor()2000 vtkColor4ub vtkScatterPlotMatrix::GetScatterPlotSelectedRowColumnColor()
2001 {
2002   return this->Private->SelectedRowColumnBGBrush->GetColorObject();
2003 }
2004 
2005 //----------------------------------------------------------------------------
GetScatterPlotSelectedActiveColor()2006 vtkColor4ub vtkScatterPlotMatrix::GetScatterPlotSelectedActiveColor()
2007 {
2008   return this->Private->SelectedChartBGBrush->GetColorObject();
2009 }
2010 
2011 //----------------------------------------------------------------------------
GetMainChart()2012 vtkChart * vtkScatterPlotMatrix::GetMainChart()
2013 {
2014   return this->Private->BigChart;
2015 }
2016 
2017 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)2018 void vtkScatterPlotMatrix::PrintSelf(ostream &os, vtkIndent indent)
2019 {
2020   Superclass::PrintSelf(os, indent);
2021 
2022   os << indent << "NumberOfBins: " << this->NumberOfBins << endl;
2023   os << indent << "Title: " << this->Title << endl;
2024   os << indent << "SelectionMode: " << this->SelectionMode << endl;
2025 }
2026