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