Commit bdb8bbf7 authored by Joachim Pouderoux's avatar Joachim Pouderoux

Introduce FunctionBagPlot and related filters.

Add a new plot type to draw functional bag plots.

Add vtkExtractFunctionalBagPlot filter to generate the two 2
components columns needed to fee a functional bag plot.

Add a TransposeTable filter to transpose tables, options allow
to create a new column containing initial row names, and use such
a column to name the new columns.

Change-Id: If7fedd9b99038ab7924f5e9b170ed72bd02f9189
parent 5b4532fe
......@@ -25,6 +25,7 @@ set(Module_SRCS
vtkPlot3D.cxx
vtkPlotBag.cxx
vtkPlotBar.cxx
vtkPlotFunctionalBag.cxx
vtkPlotGrid.cxx
vtkPlotHistogram2D.cxx
vtkPlotLine.cxx
......
......@@ -26,6 +26,7 @@ vtk_add_test_cxx(
TestContextUnicode.cxx
TestControlPointsHandleItem.cxx,-E30
TestDiagram.cxx
TestFunctionalBagPlot.cxx
TestHistogram2D.cxx
TestInteractiveChartXYZ.cxx
TestLegendHiddenPlots.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestFunctionalBagPlot.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 "vtkChartXY.h"
#include "vtkChartLegend.h"
#include "vtkContextScene.h"
#include "vtkContextView.h"
#include "vtkDoubleArray.h"
#include "vtkLookupTable.h"
#include "vtkPlotFunctionalBag.h"
#include "vtkMath.h"
#include "vtkNew.h"
#include "vtkPen.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include <sstream>
//----------------------------------------------------------------------------
int TestFunctionalBagPlot(int, char * [])
{
// Creates an input table
const int numCols = 7;
const int numVals = 100;
vtkNew<vtkTable> inputTable;
vtkNew<vtkDoubleArray> arr[numCols];
for (int i = 0; i < numCols; i++)
{
std::stringstream ss;
ss << "Y" << i;
arr[i]->SetName(ss.str().c_str());
arr[i]->SetNumberOfValues(numVals);
for (int j = 0; j < numVals; j++)
{
arr[i]->SetValue(j, (i+1) *
fabs(sin((j * 2.f *vtkMath::Pi()) /
static_cast<float>(numVals))) * j + i * 20);
}
inputTable->AddColumn(arr[i].GetPointer());
}
// Create a X-axis column
vtkNew<vtkDoubleArray> xArr;
xArr->SetName("X");
xArr->SetNumberOfValues(numVals);
for (int j = 0; j < numVals; j++)
{
xArr->SetValue(j, j * 2.0);
}
inputTable->AddColumn(xArr.GetPointer());
// Create the bag columns
vtkNew<vtkDoubleArray> q3Arr;
q3Arr->SetName("Q3");
q3Arr->SetNumberOfComponents(2);
q3Arr->SetNumberOfTuples(numVals);
vtkNew<vtkDoubleArray> q2Arr;
q2Arr->SetName("Q2");
q2Arr->SetNumberOfComponents(2);
q2Arr->SetNumberOfTuples(numVals);
for (int i = 0; i < numVals; i++)
{
double v0, v1;
v0 = arr[1]->GetVariantValue(i).ToFloat();
v1 = arr[5]->GetVariantValue(i).ToFloat();
q3Arr->SetTuple2(i, v0, v1);
v0 = arr[2]->GetVariantValue(i).ToFloat();
v1 = arr[4]->GetVariantValue(i).ToFloat();
q2Arr->SetTuple2(i, v0, v1);
}
inputTable->AddColumn(q3Arr.GetPointer());
inputTable->AddColumn(q2Arr.GetPointer());
// Set up a 2D scene and add an XY chart to it
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(400, 400);
view->GetRenderWindow()->SetMultiSamples(0);
vtkNew<vtkChartXY> chart;
view->GetScene()->AddItem(chart.GetPointer());
chart->SetShowLegend(true);
chart->GetLegend()->SetHorizontalAlignment(vtkChartLegend::LEFT);
chart->GetLegend()->SetVerticalAlignment(vtkChartLegend::TOP);
// Create the functional bag plots
vtkNew<vtkPlotFunctionalBag> q3Plot;
q3Plot->SetColor(0.5, 0, 0);
q3Plot->SetInputData(inputTable.GetPointer(), "X", "Q3");
chart->AddPlot(q3Plot.GetPointer());
vtkNew<vtkPlotFunctionalBag> q2Plot;
q2Plot->SetColor(1., 0, 0);
q2Plot->SetInputData(inputTable.GetPointer(), "X", "Q2");
chart->AddPlot(q2Plot.GetPointer());
vtkNew<vtkLookupTable> lookup;
lookup->SetNumberOfColors(numCols);
lookup->SetRange(0, numCols-1);
lookup->Build();
for (int j = 0; j < numCols; j++)
{
vtkNew<vtkPlotFunctionalBag> plot;
double rgb[3];
lookup->GetColor(j, rgb);
plot->SetColor(rgb[0], rgb[1], rgb[2]);
plot->SetInputData(inputTable.GetPointer(), "X",
inputTable->GetColumn(j)->GetName());
chart->AddPlot(plot.GetPointer());
}
// Render the scene
view->GetInteractor()->Initialize();
view->GetInteractor()->Start();
return EXIT_SUCCESS;
}
......@@ -52,7 +52,8 @@ public:
POINTS,
BAR,
STACKED,
BAG};
BAG,
FUNCTIONALBAG};
// Description:
// Enum of valid chart action types.
......
......@@ -34,6 +34,7 @@
#include "vtkPlotBar.h"
#include "vtkPlotBag.h"
#include "vtkPlotFunctionalBag.h"
#include "vtkPlotStacked.h"
#include "vtkPlotLine.h"
#include "vtkPlotPoints.h"
......@@ -1039,6 +1040,13 @@ vtkPlot * vtkChartXY::AddPlot(int type)
plot = bar;
break;
}
case FUNCTIONALBAG:
{
vtkPlotFunctionalBag *bag = vtkPlotFunctionalBag::New();
bag->GetBrush()->SetColor(color.GetData());
plot = bag;
break;
}
case STACKED:
{
vtkPlotStacked *stacked = vtkPlotStacked::New();
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkPlotFunctionalBag.h
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.
=========================================================================*/
// .NAME vtkPlotFunctionalBag - Class for drawing an XY line plot or bag
// given two columns from a vtkTable.
//
// .SECTION Description
// Depending on the number of components, this class will draw either
// a line plot (for 1 component column) or, for two components columns,
// a filled polygonal band (the bag) going from the first to the second
// component on the Y-axis along the X-axis. The filter
// vtkExtractFunctionalBagPlot is intended to create such "bag" columns.
//
// .SECTION See Also
// vtkExtractFunctionalBagPlot
#ifndef __vtkPlotFunctionalBag_h
#define __vtkPlotFunctionalBag_h
#include "vtkChartsCoreModule.h" // For export macro
#include "vtkPlot.h"
#include "vtkNew.h" // Needed to hold SP ivars
class vtkDataArray;
class vtkPlotFuntionalBagInternal;
class vtkPlotLine;
class vtkPoints2D;
class vtkScalarsToColors;
class VTKCHARTSCORE_EXPORT vtkPlotFunctionalBag : public vtkPlot
{
public:
vtkTypeMacro(vtkPlotFunctionalBag, vtkPlot);
virtual void PrintSelf(ostream &os, vtkIndent indent);
// Description:
// Creates a functional bag plot object.
static vtkPlotFunctionalBag *New();
// Description:
// Perform any updates to the item that may be necessary before rendering.
// The scene should take care of calling this on all items before their
// Paint function is invoked.
virtual void Update();
// Description:
// Paint event for the plot, called whenever the chart needs to be drawn.
virtual bool Paint(vtkContext2D *painter);
// Description:
// Paint legend event for the plot, called whenever the legend needs the
// plot items symbol/mark/line drawn. A rect is supplied with the lower left
// corner of the rect (elements 0 and 1) and with width x height (elements 2
// and 3). The plot can choose how to fill the space supplied.
virtual bool PaintLegend(vtkContext2D *painter, const vtkRectf& rect,
int legendIndex);
// Description:
// Get the bounds for this plot as (Xmin, Xmax, Ymin, Ymax).
virtual void GetBounds(double bounds[4]);
// Description:
// Get the non-log-scaled bounds on chart inputs for this plot as
// (Xmin, Xmax, Ymin, Ymax).
virtual void GetUnscaledInputBounds(double bounds[4]);
// Description:
// Specify a lookup table for the mapper to use.
void SetLookupTable(vtkScalarsToColors *lut);
vtkScalarsToColors *GetLookupTable();
// Description:
// Create default lookup table. Generally used to create one when none
// is available with the scalar data.
virtual void CreateDefaultLookupTable();
//BTX
// Description:
// Function to query a plot for the nearest point to the specified coordinate.
// Returns the index of the data series with which the point is associated or
// -1.
virtual vtkIdType GetNearestPoint(const vtkVector2f& point,
const vtkVector2f& tolerance,
vtkVector2f* location);
//ETX
protected:
vtkPlotFunctionalBag();
~vtkPlotFunctionalBag();
// Description:
// Populate the data arrays ready to operate on input data.
bool GetDataArrays(vtkTable *table, vtkDataArray *array[2]);
// Description:
// Update the table cache.
bool UpdateTableCache(vtkTable*);
// Description:
// The cache is marked dirty until it has been initialized.
vtkTimeStamp BuildTime;
// Description:
// Lookup Table for coloring points by scalar value
vtkScalarsToColors *LookupTable;
// Description:
// The plot line delegate for line series
vtkNew<vtkPlotLine> Line;
// Description:
// The bag points ordered in quadstrip fashion
vtkNew<vtkPoints2D> BagPoints;
bool LogX, LogY;
private:
vtkPlotFunctionalBag(const vtkPlotFunctionalBag &); // Not implemented.
void operator=(const vtkPlotFunctionalBag &); // Not implemented.
};
#endif //__vtkPlotFunctionalBag_h
......@@ -57,6 +57,7 @@ set(Module_SRCS
vtkTensorGlyph.cxx
vtkThreshold.cxx
vtkThresholdPoints.cxx
vtkTransposeTable.cxx
vtkTriangleFilter.cxx
vtkTubeFilter.cxx
vtkVectorDot.cxx
......
......@@ -25,6 +25,7 @@ vtk_add_test_cxx(
TestSMPPipelineContour.cxx,NO_VALID
TestThreshold.cxx,NO_VALID
TestThresholdPoints.cxx,NO_VALID
TestTransposeTable.cxx,NO_VALID
TestTubeFilter.cxx,NO_VALID
)
vtk_test_cxx_executable(${vtk-module}CxxTests)
/*=========================================================================
Program: Visualization Toolkit
Module: TestTransposeTable.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 "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkIntArray.h"
#include "vtkNew.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTransposeTable.h"
#include <sstream>
int TestTransposeTable(int, char *[])
{
vtkNew<vtkTable> table;
const int nbValues = 5;
vtkNew<vtkStringArray> colName;
colName->SetName("Name");
colName->SetNumberOfValues(nbValues);
colName->SetValue(0, "apple");
colName->SetValue(1, "milk");
colName->SetValue(2, "cream");
colName->SetValue(3, "pasta");
colName->SetValue(4, "tomato");
table->AddColumn(colName.GetPointer());
vtkNew<vtkIntArray> colId;
colId->SetName("Id");
colId->SetNumberOfValues(nbValues);
colId->SetValue(0, 0);
colId->SetValue(1, 1);
colId->SetValue(2, 2);
colId->SetValue(3, 3);
colId->SetValue(4, 4);
table->AddColumn(colId.GetPointer());
vtkNew<vtkDoubleArray> colDouble;
colDouble->SetName("Double");
colDouble->SetNumberOfValues(nbValues);
colDouble->SetValue(0, 5.);
colDouble->SetValue(1, 4.005);
colDouble->SetValue(2, 2.65);
colDouble->SetValue(3, 1.1);
colDouble->SetValue(4, 0.4);
table->AddColumn(colDouble.GetPointer());
vtkNew<vtkFloatArray> colFloat;
colFloat->SetName("Float");
colFloat->SetNumberOfValues(nbValues);
colFloat->SetValue(0, 15.f);
colFloat->SetValue(1, 14.005f);
colFloat->SetValue(2, 12.65f);
colFloat->SetValue(3, 11.1f);
colFloat->SetValue(4, 10.4f);
table->AddColumn(colFloat.GetPointer());
// Transpose the input table
vtkNew<vtkTransposeTable> filter;
filter->SetInputData(table.GetPointer());
filter->Update();
vtkTable* outTable = filter->GetOutput();
if (table->GetNumberOfColumns() != outTable->GetNumberOfRows())
{
cout << "Input table:" << endl;
table->Dump();
cout << "Transposed table:" << endl;
outTable->Dump();
cout << "Failed: Column/row mismatched!" << endl;
return EXIT_FAILURE;
}
if (table->GetNumberOfRows() != outTable->GetNumberOfColumns() - 1)
{
cout << "Input table:" << endl;
table->Dump();
cout << "Transposed table:" << endl;
outTable->Dump();
cout << "Failed: Row/Column mismatched!" << endl;
return EXIT_FAILURE;
}
for (int i = 0; i < table->GetNumberOfRows(); i++)
{
std::stringstream ss;
ss << i;
vtkAbstractArray* col = outTable->GetColumnByName(ss.str().c_str());
for (int j = 0; j < table->GetNumberOfColumns(); j++)
{
if (col->GetVariantValue(j) != table->GetValue(i, j))
{
cout << "Failed: Column/row mismatched!" << endl;
return EXIT_FAILURE;
}
}
}
// Let's transpose the transposed table and compare it with input table
vtkNew<vtkTransposeTable> filter2;
filter2->SetInputData(outTable);
filter2->SetAddIdColumn(false);
filter2->SetUseIdColumn(true);
filter2->Update();
vtkTable* outTable2 = filter2->GetOutput();
for (int i = 0; i < table->GetNumberOfRows(); i++)
{
for (int j = 0; j < table->GetNumberOfColumns(); j++)
{
if (table->GetValue(i, j) != outTable2->GetValue(i, j))
{
cout << "Transposed of transposed table:" << endl;
outTable2->Dump();
cout << "Failed: Column/row mismatch!" << endl;
return EXIT_FAILURE;
}
}
}
return EXIT_SUCCESS;
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkTransposeTable.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 "vtkTransposeTable.h"
#include "vtkAbstractArray.h"
#include "vtkCharArray.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkLongArray.h"
#include "vtkLongLongArray.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkSignedCharArray.h"
#include "vtkShortArray.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnsignedIntArray.h"
#include "vtkUnsignedLongArray.h"
#include "vtkUnsignedLongLongArray.h"
#include "vtkUnsignedShortArray.h"
#include "vtkVariantArray.h"
#include <sstream>
///////////////////////////////////////////////////////////////////////////////
class vtkTransposeTableInternal
{
public:
vtkTransposeTableInternal(vtkTransposeTable* parent) : Parent(parent) {}
bool TransposeTable(vtkTable* inTable, vtkTable* outTable);
protected:
bool InsertColumn(int, vtkAbstractArray*);
template<typename ArrayType, typename ValueType>
bool TransposeColumn(int, bool);
vtkTransposeTable* Parent;
vtkTable* InTable;
vtkTable* OutTable;
};
//----------------------------------------------------------------------------
template<typename ArrayType, typename ValueType>
bool vtkTransposeTableInternal::TransposeColumn(int columnId, bool useVariant)
{
vtkAbstractArray* column = this->InTable->GetColumn(columnId);
ArrayType* typeColumn = ArrayType::SafeDownCast(column);
if (!typeColumn && !useVariant)
{
return false;
}
int numberOfRowsInTransposedColumn = this->InTable->GetNumberOfColumns();
if (this->Parent->GetUseIdColumn())
{
columnId--;
numberOfRowsInTransposedColumn--;
}
for (int r = 0; r < column->GetNumberOfTuples() *
column->GetNumberOfComponents(); ++r)
{
vtkSmartPointer<ArrayType> transposedColumn;
if (columnId == 0)
{
transposedColumn = vtkSmartPointer<ArrayType>::New();
transposedColumn->SetNumberOfValues(numberOfRowsInTransposedColumn);
this->OutTable->AddColumn(transposedColumn);
}
else
{
transposedColumn = ArrayType::SafeDownCast(this->OutTable->GetColumn(r));
}
if (!useVariant)
{
ValueType value = typeColumn->GetValue(r);
transposedColumn->SetValue(columnId, value);
}
else
{
vtkVariant value = column->GetVariantValue(r);
transposedColumn->SetVariantValue(columnId, value);
}
}
return true;
}
//----------------------------------------------------------------------------
bool vtkTransposeTableInternal::InsertColumn(int pos, vtkAbstractArray* col)
{
if (!col || ((this->OutTable->GetNumberOfRows() !=
col->GetNumberOfComponents() * col->GetNumberOfTuples()) &&
(this->OutTable->GetNumberOfRows() != 0)))
{
return false;
}
int nbColsOutTable = this->OutTable->GetNumberOfColumns();
vtkNew<vtkTable> updatedTable;
for (int c = 0; c < nbColsOutTable; c++)
{
vtkAbstractArray* column = this->OutTable->GetColumn(c);
if (c == pos)
{
updatedTable->AddColumn(col);
}
updatedTable->AddColumn(column);
}
if (pos == nbColsOutTable)
{
updatedTable->AddColumn(col);
}
this->OutTable->ShallowCopy(updatedTable.GetPointer());
return true;
}
//----------------------------------------------------------------------------
bool vtkTransposeTableInternal::TransposeTable(vtkTable* inTable,
vtkTable* outTable)
{
this->InTable = inTable;
this->OutTable = outTable;
int idColOffset = this->Parent->GetUseIdColumn() ? 1 : 0;
// Check column type consistency
bool useVariant = false;
vtkAbstractArray* firstCol = this->InTable->GetColumn(idColOffset);
for (int c = idColOffset; c < this->InTable->GetNumberOfColumns(); c++)
{
if (strcmp(firstCol->GetClassName(),
this->InTable->GetColumn(c)->GetClassName()) != 0)
{
useVariant = true;
break;
}
}
for (int c = idColOffset; c < this->InTable->GetNumberOfColumns(); c++)
{
vtkAbstractArray* column = this->InTable->GetColumn(c);
if (!column)
{
return false;
}
if (!useVariant)
{
#define TransposeTypedColumn(_vt, _ta, _t) \
case _vt:\
if (!this->TransposeColumn<_ta, _t>(c, useVariant))\
{\
vtkErrorWithObjectMacro(this->Parent, <<\
"Unable to transpose column " << c);\
return false;\
}\
break;
switch (column->GetDataType())
{
TransposeTypedColumn(VTK_DOUBLE, vtkDoubleArray,
double);
TransposeTypedColumn(VTK_FLOAT, vtkFloatArray,
float);
TransposeTypedColumn(VTK_CHAR, vtkCharArray,
char);
TransposeTypedColumn(VTK_SIGNED_CHAR, vtkSignedCharArray,
signed char);
TransposeTypedColumn(VTK_SHORT, vtkShortArray,
short);
TransposeTypedColumn(VTK_INT, vtkIntArray,
int);
TransposeTypedColumn(VTK_LONG, vtkLongArray,
long);
TransposeTypedColumn(VTK_LONG_LONG, vtkLongLongArray,
long long);
TransposeTypedColumn(VTK_UNSIGNED_CHAR, vtkUnsignedCharArray,
unsigned char);
TransposeTypedColumn(VTK_UNSIGNED_SHORT, vtkUnsignedShortArray,
unsigned short);
TransposeTypedColumn(VTK_UNSIGNED_INT, vtkUnsignedIntArray,
unsigned int);
TransposeTypedColumn(VTK_UNSIGNED_LONG, vtkUnsignedLongArray,
unsigned long);
TransposeTypedColumn(VTK_UNSIGNED_LONG_LONG, vtkUnsignedLongLongArray,
unsigned long long);
TransposeTypedColumn(VTK_ID_TYPE, vtkIdTypeArray,
vtkIdType);
TransposeTypedColumn(VTK_STRING, vtkStringArray,
vtkStdString);
#undef TransposeTypedColumn
default:
useVariant = true;
break;
}
}
if (useVariant)
{
if (!this->TransposeColumn<vtkVariantArray, vtkVariant>(c, useVariant))
{
vtkErrorWithObjectMacro(this->Parent, << "Unable to transpose column " << c);
return false;
}