Commit 9e3992ce authored by Marcus D. Hanwell's avatar Marcus D. Hanwell

ENH: Added scatter plot matrix column visibility.

Added the ability to set column visibility, along with a new test to
verify this works as expected.

Change-Id: Ibdcdab67bf602ae620f35beb524e8988a53d43e3
parent 549a4ed8
......@@ -36,6 +36,7 @@ IF(VTK_USE_RENDERING AND VTK_USE_VIEWS)
TestScalarsToColors.cxx
TestScatterPlot.cxx
TestScatterPlotMatrix.cxx
TestScatterPlotMatrixVisible.cxx
TestScientificPlot.cxx
TestStackedBarGraph.cxx
TestStackedPlot.cxx
......
......@@ -27,7 +27,7 @@
//----------------------------------------------------------------------------
int TestScatterPlotMatrix(int, char * [])
{
// Set up a 2D scene, add an XY chart to it
// Set up a 2D scene, add a chart to it
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(800, 600);
vtkNew<vtkScatterPlotMatrix> matrix;
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestScatterPlotMatrixVisible.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkScatterPlotMatrix.h"
#include "vtkRenderWindow.h"
#include "vtkChart.h"
#include "vtkPlot.h"
#include "vtkTable.h"
#include "vtkFloatArray.h"
#include "vtkContextView.h"
#include "vtkContextScene.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkNew.h"
//----------------------------------------------------------------------------
int TestScatterPlotMatrixVisible(int, char * [])
{
// Set up a 2D scene, add a chart to it.
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(800, 600);
vtkNew<vtkScatterPlotMatrix> matrix;
view->GetScene()->AddItem(matrix.GetPointer());
// Create a table with some points in it...
vtkNew<vtkTable> table;
vtkNew<vtkFloatArray> arrX;
arrX->SetName("x");
table->AddColumn(arrX.GetPointer());
vtkNew<vtkFloatArray> arrC;
arrC->SetName("cos(x)");
table->AddColumn(arrC.GetPointer());
vtkNew<vtkFloatArray> arrS;
arrS->SetName("sin(x)");
table->AddColumn(arrS.GetPointer());
vtkNew<vtkFloatArray> arrS2;
arrS2->SetName("sin(x + 0.5)");
table->AddColumn(arrS2.GetPointer());
vtkNew<vtkFloatArray> tangent;
tangent->SetName("tan(x)");
table->AddColumn(tangent.GetPointer());
// Test the chart scatter plot matrix
int numPoints = 42;
float inc = 7.5 / (numPoints-1);
table->SetNumberOfRows(numPoints);
for (int i = 0; i < numPoints; ++i)
{
table->SetValue(i, 0, i * inc);
table->SetValue(i, 1, cos(i * inc));
table->SetValue(i, 2, sin(i * inc));
table->SetValue(i, 3, sin(i * inc) + 0.5);
table->SetValue(i, 4, tan(i * inc));
}
// Select a few columns in the table to analyze.
matrix->SetInput(table.GetPointer());
matrix->SetColumnVisibilityAll(false);
matrix->SetColumnVisibility("x", true);
matrix->SetColumnVisibility("sin(x)", true);
matrix->SetColumnVisibility("cos(x)", true);
matrix->SetColumnVisibility("tan(x)", true);
//Finally render the scene and compare the image to a reference image
view->GetRenderWindow()->SetMultiSamples(0);
view->GetInteractor()->Initialize();
view->GetInteractor()->Start();
return EXIT_SUCCESS;
}
......@@ -59,20 +59,23 @@ bool vtkChartMatrix::Paint(vtkContext2D *painter)
// Update the chart element positions
this->Private->Geometry.Set(this->GetScene()->GetSceneWidth(),
this->GetScene()->GetSceneHeight());
vtkVector2f increments(this->Private->Geometry.X() / this->Size.X(),
this->Private->Geometry.Y() / this->Size.Y());
for (int i = 0; i < this->Size.X(); ++i)
if (this->Size.X() > 0 && this->Size.Y() > 0)
{
for (int j = 0; j < this->Size.Y(); ++j)
vtkVector2f increments(this->Private->Geometry.X() / this->Size.X(),
this->Private->Geometry.Y() / this->Size.Y());
for (int i = 0; i < this->Size.X(); ++i)
{
size_t index = j * this->Size.X() + i;
if (this->Private->Charts[index])
for (int j = 0; j < this->Size.Y(); ++j)
{
vtkChart *chart = this->Private->Charts[index];
chart->SetSize(vtkRectf(i * increments.X(),
j * increments.Y(),
increments.X(),
increments.Y()));
size_t index = j * this->Size.X() + i;
if (this->Private->Charts[index])
{
vtkChart *chart = this->Private->Charts[index];
chart->SetSize(vtkRectf(i * increments.X(),
j * increments.Y(),
increments.X(),
increments.Y()));
}
}
}
}
......
......@@ -22,6 +22,7 @@
#include "vtkPlot.h"
#include "vtkAxis.h"
#include "vtkStdString.h"
#include "vtkStringArray.h"
#include "vtkNew.h"
#include "vtkMathUtilities.h"
#include "vtkObjectFactory.h"
......@@ -29,10 +30,16 @@
class vtkScatterPlotMatrix::PIMPL
{
public:
PIMPL() {}
~PIMPL() {}
PIMPL() : VisibleColumnsModified(true)
{
}
~PIMPL()
{
}
vtkNew<vtkTable> Histogram;
bool VisibleColumnsModified;
};
namespace
......@@ -80,9 +87,6 @@ bool PopulateHistograms(vtkTable *input, vtkTable *output)
{
pops[k] = 0;
}
cout << "Attempting to bin " << name << "(" << minmax[0] <<
"->" << minmax[1] << ")" << endl;
cout << "inc: " << inc << " / 2 -> " << halfInc << endl;
for (vtkIdType j = 0; j < in->GetNumberOfTuples(); ++j)
{
double v(0.0);
......@@ -91,8 +95,6 @@ bool PopulateHistograms(vtkTable *input, vtkTable *output)
{
if (vtkFuzzyCompare(v, double(centers[k]), halfInc))
{
cout << "FuzzyCompare true: " << v << ", " << centers[k] << ": "
<< halfInc << endl;
++pops[k];
break;
}
......@@ -120,10 +122,20 @@ vtkScatterPlotMatrix::~vtkScatterPlotMatrix()
void vtkScatterPlotMatrix::Update()
{
if (this->Private->VisibleColumnsModified)
{
// We need to handle layout changes due to modified visibility.
// Build up our histograms data before updating the layout.
PopulateHistograms(this->Input.GetPointer(),
this->Private->Histogram.GetPointer());
this->UpdateLayout();
this->Private->VisibleColumnsModified = false;
}
}
bool vtkScatterPlotMatrix::Paint(vtkContext2D *painter)
{
this->Update();
return Superclass::Paint(painter);
}
......@@ -139,76 +151,161 @@ void vtkScatterPlotMatrix::SetInput(vtkTable *table)
if (table == NULL)
{
this->SetSize(vtkVector2i(0, 0));
this->SetColumnVisibilityAll(true);
return;
}
// Build up our histograms
PopulateHistograms(table, this->Private->Histogram.GetPointer());
int n = static_cast<int>(this->Input->GetNumberOfColumns());
this->SetColumnVisibilityAll(true);
this->SetSize(vtkVector2i(n, n));
// We want scatter plots on the lower-left triangle, then histograms along
// the diagonal and a big plot in the top-right. The basic layout is,
//
// 0 H +++
// 1 S H +++
// 2 S S H
// 3 S S S H
// 0 1 2 3
//
// Where the indices are those of the columns. The indices of the charts
// originate in the bottom-left.
for (int i = 0; i < n; ++i)
}
}
void vtkScatterPlotMatrix::SetColumnVisibility(const vtkStdString &name,
bool visible)
{
if (visible)
{
for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
{
for (int j = 0; j < n; ++j)
if (this->VisibleColumns->GetValue(i) == name)
{
vtkVector2i pos(i, j);
if (i + j + 1 < n)
{
vtkPlot *plot = this->GetChart(pos)->AddPlot(vtkChart::POINTS);
plot->SetInput(table, i, n - j - 1);
}
else if (i == n - j - 1)
{
// We are on the diagonal - need a histogram plot.
vtkPlot *plot = this->GetChart(pos)->AddPlot(vtkChart::BAR);
vtkStdString name(table->GetColumnName(i));
plot->SetInput(this->Private->Histogram.GetPointer(),
name + "_extents", name + "_pops");
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::TOP);
axis->SetTitle(name.c_str());
// Set the plot corner to the top-right
vtkChartXY *xy = vtkChartXY::SafeDownCast(this->GetChart(pos));
if (xy)
{
xy->SetPlotCorner(plot, 2);
}
}
// Only show bottom axis label for bottom plots
if (j > 0)
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
axis->SetTitle("");
axis->SetLabelsVisible(false);
}
else
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
axis->SetTitle(table->GetColumnName(i));
}
// Only show the left axis labels for left-most plots
if (i > 0)
// Already there, nothing more needs to be done
return;
}
}
// Add the column to the end of the list
this->VisibleColumns->InsertNextValue(name);
this->Private->VisibleColumnsModified = true;
this->SetSize(vtkVector2i(this->VisibleColumns->GetNumberOfTuples(),
this->VisibleColumns->GetNumberOfTuples()));
this->Modified();
}
else
{
// Remove the value if present
for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
{
if (this->VisibleColumns->GetValue(i) == name)
{
// Move all the later elements down by one, and reduce the size
while (i < this->VisibleColumns->GetNumberOfTuples()-1)
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
axis->SetTitle("");
axis->SetLabelsVisible(false);
this->VisibleColumns->SetValue(i,
this->VisibleColumns->GetValue(i+1));
++i;
}
else
this->VisibleColumns->SetNumberOfTuples(
this->VisibleColumns->GetNumberOfTuples()-1);
this->SetSize(vtkVector2i(this->VisibleColumns->GetNumberOfTuples(),
this->VisibleColumns->GetNumberOfTuples()));
this->Private->VisibleColumnsModified = true;
this->Modified();
return;
}
}
}
}
bool vtkScatterPlotMatrix::GetColumnVisibility(const vtkStdString &name)
{
for (vtkIdType i = 0; i < this->VisibleColumns->GetNumberOfTuples(); ++i)
{
if (this->VisibleColumns->GetValue(i) == name)
{
return true;
}
}
return false;
}
void vtkScatterPlotMatrix::SetColumnVisibilityAll(bool visible)
{
if (visible && this->Input)
{
vtkIdType n = this->Input->GetNumberOfColumns();
this->VisibleColumns->SetNumberOfTuples(n);
for (vtkIdType i = 0; i < n; ++i)
{
this->VisibleColumns->SetValue(i, this->Input->GetColumnName(i));
}
}
else
{
this->SetSize(vtkVector2i(0, 0));
this->VisibleColumns->SetNumberOfTuples(0);
}
}
vtkStringArray* vtkScatterPlotMatrix::GetVisibleColumns()
{
return this->VisibleColumns.GetPointer();
}
void vtkScatterPlotMatrix::UpdateLayout()
{
// We want scatter plots on the lower-left triangle, then histograms along
// the diagonal and a big plot in the top-right. The basic layout is,
//
// 0 H +++
// 1 S H +++
// 2 S S H
// 3 S S S H
// 0 1 2 3
//
// Where the indices are those of the columns. The indices of the charts
// originate in the bottom-left.
int n = this->Size.X();
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
vtkVector2i pos(i, j);
if (i + j + 1 < n)
{
vtkPlot *plot = this->GetChart(pos)->AddPlot(vtkChart::POINTS);
plot->SetInput(this->Input.GetPointer(), i, n - j - 1);
}
else if (i == n - j - 1)
{
// We are on the diagonal - need a histogram plot.
vtkPlot *plot = this->GetChart(pos)->AddPlot(vtkChart::BAR);
vtkStdString name(this->VisibleColumns->GetValue(i));
plot->SetInput(this->Private->Histogram.GetPointer(),
name + "_extents", name + "_pops");
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::TOP);
axis->SetTitle(name.c_str());
// Set the plot corner to the top-right
vtkChartXY *xy = vtkChartXY::SafeDownCast(this->GetChart(pos));
if (xy)
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
axis->SetTitle(table->GetColumnName(n - j - 1));
xy->SetPlotCorner(plot, 2);
}
}
// Only show bottom axis label for bottom plots
if (j > 0)
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
axis->SetTitle("");
axis->SetLabelsVisible(false);
}
else
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::BOTTOM);
axis->SetTitle(this->VisibleColumns->GetValue(i));
}
// Only show the left axis labels for left-most plots
if (i > 0)
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
axis->SetTitle("");
axis->SetLabelsVisible(false);
}
else
{
vtkAxis *axis = this->GetChart(pos)->GetAxis(vtkAxis::LEFT);
axis->SetTitle(this->VisibleColumns->GetValue(n - j - 1));
}
}
}
}
......
......@@ -25,7 +25,9 @@
#include "vtkChartMatrix.h"
#include "vtkSmartPointer.h" // For ivars
#include "vtkNew.h" // For ivars
class vtkStringArray;
class vtkTable;
class VTK_CHARTS_EXPORT vtkScatterPlotMatrix : public vtkChartMatrix
......@@ -51,14 +53,38 @@ public:
// columns to be plotted against each other - a square scatter plot matrix.
virtual void SetInput(vtkTable *table);
// Description:
// Set the visibility of the specified column.
void SetColumnVisibility(const vtkStdString& name, bool visible);
// Description:
// Get the visibility of the specified column.
bool GetColumnVisibility(const vtkStdString& name);
// Description:
// Set the visibility of all columns (true will make them all visible, false
// will remove all visible columns).
void SetColumnVisibilityAll(bool visible);
// Description:
// Get a list of the columns, and the order in which they are displayed.
virtual vtkStringArray* GetVisibleColumns();
protected:
vtkScatterPlotMatrix();
~vtkScatterPlotMatrix();
// Description:
// Internal helper to do the layout of the charts in the scatter plot matrix.
void UpdateLayout();
class PIMPL;
PIMPL *Private;
// Weakly owned input data for the scatter plot matrix.
vtkSmartPointer<vtkTable> Input;
// Strongly owned internal data for the column visibility.
vtkNew<vtkStringArray> VisibleColumns;
private:
vtkScatterPlotMatrix(const vtkScatterPlotMatrix &); // Not implemented.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment