Commit fe7406cd authored by Zack Galbreath's avatar Zack Galbreath Committed by Code Review
Browse files

Merge topic 'collapse_columns' into master

8c716e6d add test for column trees
728192ea Add a dendrogram for the columns of the heatmap
parents 3187129d 8c716e6d
vtk_add_test_cxx(
TestCoincidentGraphLayoutView.cxx
TestColumnTree.cxx
TestConeLayoutStrategy.cxx
TestDendrogramItem.cxx
TestGraphLayoutView.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestColumnTree.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 "vtkTreeHeatmapItem.h"
#include "vtkDataSetAttributes.h"
#include "vtkDoubleArray.h"
#include "vtkMutableDirectedGraph.h"
#include "vtkNew.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTree.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkContextInteractorStyle.h"
#include "vtkContextMouseEvent.h"
#include "vtkContextScene.h"
#include "vtkContextTransform.h"
#include "vtkContextView.h"
#include "vtkNew.h"
#include "vtkRegressionTestImage.h"
//----------------------------------------------------------------------------
int TestColumnTree(int argc, char* argv[])
{
// Construct a tree
vtkNew<vtkMutableDirectedGraph> graph;
vtkIdType root = graph->AddVertex();
vtkIdType internalOne = graph->AddChild(root);
vtkIdType internalTwo = graph->AddChild(internalOne);
vtkIdType a = graph->AddChild(internalTwo);
vtkIdType b = graph->AddChild(internalTwo);
vtkIdType c = graph->AddChild(internalOne);
vtkNew<vtkDoubleArray> weights;
weights->SetNumberOfTuples(5);
weights->SetValue(graph->GetEdgeId(root, internalOne), 1.0f);
weights->SetValue(graph->GetEdgeId(internalOne, internalTwo), 2.0f);
weights->SetValue(graph->GetEdgeId(internalTwo, a), 1.0f);
weights->SetValue(graph->GetEdgeId(internalTwo, b), 1.0f);
weights->SetValue(graph->GetEdgeId(internalOne, c), 3.0f);
weights->SetName("weight");
graph->GetEdgeData()->AddArray(weights.GetPointer());
vtkNew<vtkStringArray> names;
names->SetNumberOfTuples(6);
names->SetValue(a, "a");
names->SetValue(b, "b");
names->SetValue(c, "c");
names->SetName("node name");
graph->GetVertexData()->AddArray(names.GetPointer());
vtkNew<vtkDoubleArray> nodeWeights;
nodeWeights->SetNumberOfTuples(6);
nodeWeights->SetValue(root, 0.0f);
nodeWeights->SetValue(internalOne, 1.0f);
nodeWeights->SetValue(internalTwo, 3.0f);
nodeWeights->SetValue(a, 4.0f);
nodeWeights->SetValue(b, 4.0f);
nodeWeights->SetValue(c, 4.0f);
nodeWeights->SetName("node weight");
graph->GetVertexData()->AddArray(nodeWeights.GetPointer());
vtkNew<vtkTree> tree;
tree->ShallowCopy(graph.GetPointer());
vtkNew<vtkTree> tree2;
tree2->DeepCopy(tree.GetPointer());
// Construct a table
vtkNew<vtkTable> table;
vtkNew<vtkStringArray> tableNames;
vtkNew<vtkDoubleArray> m1;
vtkNew<vtkDoubleArray> m2;
vtkNew<vtkDoubleArray> m3;
tableNames->SetNumberOfTuples(3);
tableNames->SetValue(0, "c");
tableNames->SetValue(1, "b");
tableNames->SetValue(2, "a");
tableNames->SetName("name");
m1->SetNumberOfTuples(3);
m2->SetNumberOfTuples(3);
m3->SetNumberOfTuples(3);
m1->SetName("a");
m2->SetName("b");
m3->SetName("c");
m1->SetValue(0, 1.0f);
m1->SetValue(1, 3.0f);
m1->SetValue(2, 1.0f);
m2->SetValue(0, 2.0f);
m2->SetValue(1, 2.0f);
m2->SetValue(2, 2.0f);
m3->SetValue(0, 3.0f);
m3->SetValue(1, 1.0f);
m3->SetValue(2, 3.0f);
table->AddColumn(tableNames.GetPointer());
table->AddColumn(m1.GetPointer());
table->AddColumn(m2.GetPointer());
table->AddColumn(m3.GetPointer());
vtkNew<vtkTreeHeatmapItem> treeItem;
treeItem->SetTree(tree.GetPointer());
treeItem->SetColumnTree(tree2.GetPointer());
treeItem->SetTable(table.GetPointer());
vtkNew<vtkContextTransform> trans;
trans->SetInteractive(true);
trans->AddItem(treeItem.GetPointer());
// center the item within the render window
trans->Translate(80, 25);
trans->Scale(1.5, 1.5);
vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
view->GetRenderWindow()->SetSize(400, 200);
view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
view->GetScene()->AddItem(trans.GetPointer());
//Finally render the scene and compare the image to a reference image
view->GetRenderWindow()->SetMultiSamples(0);
view->GetRenderWindow()->Render();
// collapse a column subtree
vtkContextMouseEvent mouseEvent;
mouseEvent.SetInteractor(view->GetInteractor());
vtkVector2f pos;
mouseEvent.SetButton(vtkContextMouseEvent::LEFT_BUTTON);
pos.Set(62, 81);
mouseEvent.SetPos(pos);
treeItem->MouseDoubleClickEvent(mouseEvent);
view->GetRenderWindow()->Render();
int retVal = vtkRegressionTestImage(view->GetRenderWindow());
if (retVal == vtkRegressionTester::DO_INTERACTOR)
{
view->GetRenderWindow()->Render();
view->GetInteractor()->Start();
retVal = vtkRegressionTester::PASSED;
}
return !retVal;
}
......@@ -155,8 +155,8 @@ int TestTanglegramItem(int argc, char* argv[])
trans->SetInteractive(true);
trans->AddItem(tanglegram.GetPointer());
// center the item within the render window
trans->Translate(10, 75);
trans->Scale(1.375, 1.375);
trans->Translate(20, 75);
trans->Scale(1.25, 1.25);
actor->GetScene()->AddItem(trans.GetPointer());
vtkNew<vtkRenderer> renderer;
......
815d766a2d6d7419df3976ee11bfea0c
5548784a3f7181bc7c04c239180deac7
......@@ -57,6 +57,8 @@ vtkDendrogramItem::vtkDendrogramItem() : PositionVector(0, 0)
this->MaxX = 0.0;
this->MaxY = 0.0;
this->LabelWidth = 0.0;
this->NumberOfLeafNodes = 0;
this->MultiplierX = 100.0;
this->MultiplierY = 100.0;
......@@ -174,19 +176,20 @@ bool vtkDendrogramItem::Paint(vtkContext2D *painter)
return true;
}
this->PrepareToPaint();
this->PrepareToPaint(painter);
this->PaintBuffers(painter);
return true;
}
//-----------------------------------------------------------------------------
void vtkDendrogramItem::PrepareToPaint()
void vtkDendrogramItem::PrepareToPaint(vtkContext2D *painter)
{
if (this->IsDirty())
{
this->RebuildBuffers();
}
this->ComputeLabelWidth(painter);
}
//-----------------------------------------------------------------------------
......@@ -399,7 +402,6 @@ void vtkDendrogramItem::PaintBuffers(vtkContext2D *painter)
double xStart, yStart;
double sourcePoint[3];
double targetPoint[3];
double spacing = 25;
int numberOfCollapsedSubTrees = 0;
vtkUnsignedIntArray *vertexIsPruned = vtkUnsignedIntArray::SafeDownCast(
......@@ -564,119 +566,119 @@ void vtkDendrogramItem::PaintBuffers(vtkContext2D *painter)
}
}
// special case: all the true leaf nodes have been collapsed
if (this->NumberOfLeafNodes <= numberOfCollapsedSubTrees)
// the remainder of this function involves drawing the leaf node labels,
// so we can return now if that feature has been disabled.
if (!this->DrawLabels)
{
return;
}
// get array of node names from the tree
vtkStringArray *vertexNames = vtkStringArray::SafeDownCast(
this->LayoutTree->GetVertexData()->GetAbstractArray("node name"));
// leave a small amount of space between the tree and the vertex labels
spacing = this->LeafSpacing * 0.5;
// special case: all the true leaf nodes have been collapsed.
// This means that there aren't any labels left to draw.
if (this->NumberOfLeafNodes <= numberOfCollapsedSubTrees)
{
return;
}
//"Igq" selected for range of height
int fontSize = painter->ComputeFontSizeForBoundedString("Igq", VTK_FLOAT_MAX,
this->LeafSpacing);
bool canDrawText = true;
// make sure our current zoom level allows for a legibly-sized font
if (fontSize < 8)
{
canDrawText = false;
return;
}
if (this->DrawLabels)
// leave a small amount of space between the tree and the vertex labels
double spacing = this->LeafSpacing * 0.5;
// set up our text property to draw leaf node labels
painter->GetTextProp()->SetColor(0.0, 0.0, 0.0);
painter->GetTextProp()->SetJustificationToLeft();
painter->GetTextProp()->SetVerticalJustificationToCentered();
painter->GetTextProp()->SetOrientation(0);
painter->GetTextProp()->SetOrientation(
this->GetTextAngleForOrientation(orientation));
// make sure some of the labels would be visible on screen
switch (orientation)
{
// make sure some of the labels would be visible on screen
if (!canDrawText)
case vtkDendrogramItem::DOWN_TO_UP:
if (this->SceneBottomLeft[1] > this->MaxY + spacing ||
this->SceneTopRight[1] < this->MaxY + spacing)
{
return;
}
break;
case vtkDendrogramItem::RIGHT_TO_LEFT:
if (this->SceneBottomLeft[0] > this->MinX - spacing ||
this->SceneTopRight[0] < this->MinX - spacing)
{
return;
}
painter->GetTextProp()->SetJustificationToRight();
break;
case vtkDendrogramItem::UP_TO_DOWN:
if (this->SceneBottomLeft[1] > this->MinY - spacing ||
this->SceneTopRight[1] < this->MinY - spacing)
{
return;
}
painter->GetTextProp()->SetJustificationToRight();
break;
case vtkDendrogramItem::LEFT_TO_RIGHT:
default:
if (this->SceneBottomLeft[0] > this->MaxX + spacing ||
this->SceneTopRight[0] < this->MaxX + spacing)
{
return;
}
break;
}
// get array of node names from the tree
vtkStringArray *vertexNames = vtkStringArray::SafeDownCast(
this->LayoutTree->GetVertexData()->GetAbstractArray("node name"));
// find our leaf nodes & draw their labels
for (vtkIdType vertex = 0; vertex < this->LayoutTree->GetNumberOfVertices();
++vertex)
{
if (!this->LayoutTree->IsLeaf(vertex))
{
return;
continue;
}
// set up our text property to draw row names
painter->GetTextProp()->SetColor(0.0, 0.0, 0.0);
painter->GetTextProp()->SetJustificationToLeft();
painter->GetTextProp()->SetVerticalJustificationToCentered();
painter->GetTextProp()->SetOrientation(0);
double point[3];
this->LayoutTree->GetPoint(vertex, point);
switch (orientation)
{
case vtkDendrogramItem::DOWN_TO_UP:
if (this->SceneBottomLeft[1] > this->MaxY + spacing ||
this->SceneTopRight[1] < this->MaxY + spacing)
{
return;
}
xStart = this->Position[0] + point[0] * this->MultiplierX;
yStart = this->MaxY + spacing;
break;
case vtkDendrogramItem::RIGHT_TO_LEFT:
if (this->SceneBottomLeft[0] > this->MinX - spacing ||
this->SceneTopRight[0] < this->MinX - spacing)
{
return;
}
painter->GetTextProp()->SetJustificationToRight();
xStart = this->MinX - spacing;
yStart = this->Position[1] + point[1] * this->MultiplierY;
break;
case vtkDendrogramItem::UP_TO_DOWN:
if (this->SceneBottomLeft[1] > this->MinY - spacing ||
this->SceneTopRight[1] < this->MinY - spacing)
{
return;
}
painter->GetTextProp()->SetJustificationToRight();
xStart = this->Position[0] + point[0] * this->MultiplierX;
yStart = this->MinY - spacing;
break;
case vtkDendrogramItem::LEFT_TO_RIGHT:
default:
if (this->SceneBottomLeft[0] > this->MaxX + spacing ||
this->SceneTopRight[0] < this->MaxX + spacing)
{
return;
}
xStart = this->MaxX + spacing;
yStart = this->Position[1] + point[1] * this->MultiplierY;
break;
}
painter->GetTextProp()->SetOrientation(
this->GetTextAngleForOrientation(orientation));
for (vtkIdType vertex = 0; vertex < this->LayoutTree->GetNumberOfVertices();
++vertex)
std::string vertexName = vertexNames->GetValue(vertex);
if (this->SceneBottomLeft[0] < xStart &&
this->SceneTopRight[0] > xStart &&
this->SceneBottomLeft[1] < yStart &&
this->SceneTopRight[1] > yStart)
{
if (!this->LayoutTree->IsLeaf(vertex))
{
continue;
}
double point[3];
this->LayoutTree->GetPoint(vertex, point);
switch (orientation)
{
case vtkDendrogramItem::DOWN_TO_UP:
xStart = this->Position[0] + point[0] * this->MultiplierX;
yStart = this->MaxY + spacing;
break;
case vtkDendrogramItem::RIGHT_TO_LEFT:
xStart = this->MinX - spacing;
yStart = this->Position[1] + point[1] * this->MultiplierY;
break;
case vtkDendrogramItem::UP_TO_DOWN:
xStart = this->Position[0] + point[0] * this->MultiplierX;
yStart = this->MinY - spacing;
break;
case vtkDendrogramItem::LEFT_TO_RIGHT:
default:
xStart = this->MaxX + spacing;
yStart = this->Position[1] + point[1] * this->MultiplierY;
break;
}
std::string vertexName = vertexNames->GetValue(vertex);
if (this->SceneBottomLeft[0] < xStart &&
this->SceneTopRight[0] > xStart &&
this->SceneBottomLeft[1] < yStart &&
this->SceneTopRight[1] > yStart)
{
painter->DrawString(xStart, yStart, vertexName);
}
painter->DrawString(xStart, yStart, vertexName);
}
}
}
......@@ -1294,17 +1296,55 @@ void vtkDendrogramItem::GetBounds(double bounds[4])
bounds[1] = this->MaxX;
bounds[2] = this->MinY;
bounds[3] = this->MaxY;
if (this->LabelWidth == 0.0)
{
return;
}
double spacing = this->LeafSpacing * 0.5;
switch (this->GetOrientation())
{
case vtkDendrogramItem::LEFT_TO_RIGHT:
default:
bounds[1] += spacing + this->LabelWidth;
break;
case vtkDendrogramItem::UP_TO_DOWN:
bounds[2] -= spacing + this->LabelWidth;
break;
case vtkDendrogramItem::RIGHT_TO_LEFT:
bounds[0] -= spacing + this->LabelWidth;
break;
case vtkDendrogramItem::DOWN_TO_UP:
bounds[3] += spacing + this->LabelWidth;
break;
}
}
//-----------------------------------------------------------------------------
float vtkDendrogramItem::GetLabelWidth()
{
return this->LabelWidth;
}
//-----------------------------------------------------------------------------
float vtkDendrogramItem::GetLabelWidth(vtkContext2D *painter)
void vtkDendrogramItem::ComputeLabelWidth(vtkContext2D *painter)
{
int fontSize = painter->ComputeFontSizeForBoundedString("Igq", VTK_FLOAT_MAX,
this->LabelWidth = 0.0;
if (!this->DrawLabels)
{
return;
}
int fontSize = painter->ComputeFontSizeForBoundedString("Igq", VTK_FLOAT_MAX,
this->LeafSpacing);
if (fontSize < 8)
{
return 0.0;
}
if (fontSize < 8)
{
return;
}
// temporarily set text to default orientation
int orientation = painter->GetTextProp()->GetOrientation();
......@@ -1313,21 +1353,19 @@ float vtkDendrogramItem::GetLabelWidth(vtkContext2D *painter)
// get array of node names from the tree
vtkStringArray *vertexNames = vtkStringArray::SafeDownCast(
this->LayoutTree->GetVertexData()->GetAbstractArray("node name"));
double maxLength = 0.0;
float bounds[4];
for (vtkIdType i = 0; i < vertexNames->GetNumberOfTuples(); ++i)
{
painter->ComputeStringBounds(vertexNames->GetValue(i), bounds);
if (bounds[2] > maxLength)
if (bounds[2] > this->LabelWidth)
{
maxLength = bounds[2];
this->LabelWidth = bounds[2];
}
}
// restore orientation
painter->GetTextProp()->SetOrientation(orientation);
return maxLength;
}
//-----------------------------------------------------------------------------
......
......@@ -137,7 +137,7 @@ public:
// This function calls RebuildBuffers() if necessary.
// Once PrepareToPaint() has been called, GetBounds() is guaranteed
// to provide useful information.
void PrepareToPaint();
void PrepareToPaint(vtkContext2D *painter);
// Description:
// Get the bounds for this item as (Xmin,Xmax,Ymin,Ymax).
......@@ -145,9 +145,13 @@ public:
// PrepareToPaint() has been called.
virtual void GetBounds(double bounds[4]);
// Description:
// Compute the width of the longest leaf node label.
void ComputeLabelWidth(vtkContext2D *painter);
// Description:
// Get the width of the longest leaf node label.
float GetLabelWidth(vtkContext2D *painter);
float GetLabelWidth();
// Description:
// Find the position of the vertex with the specified name. Store
......@@ -155,6 +159,10 @@ public:
// was found, false otherwise.
bool GetPositionOfVertex(std::string vertexName, double position[2]);
// Description:
// Paints the input tree as a dendrogram.
virtual bool Paint(vtkContext2D *painter);
// this struct & class allow us to generate a priority queue of vertices.
struct WeightedVertex
{
......@@ -226,10 +234,6 @@ protected:
// Compute the bounds of our tree in pixel coordinates.
void ComputeBounds();
// Description:
// Paints the input tree as a dendrogram.
virtual bool Paint(vtkContext2D *painter);
// Description:
// Count the number of leaf nodes in the tree
void CountLeafNodes();
......@@ -307,6 +311,7 @@ private:
double MaxY;
double SceneBottomLeft[3];
double SceneTopRight[3];
float LabelWidth;
bool ColorTree;
bool ExtendLeafNodes;
bool DrawLabels;
......
This diff is collapsed.
......@@ -33,6 +33,7 @@
#include <set> // For blank row support
#include <vector> // For row mapping
class vtkBitArray;
class vtkLookupTable;
class vtkStringArray;
class vtkTable;
......@@ -99,6 +100,16 @@ public:
// Used by vtkTreeHeatmapItem to represent missing data.
void MarkRowAsBlank(std::string rowName);
// Description:
// Paints the table as a heatmap.
virtual bool Paint(vtkContext2D *painter);
// Description:
// Get the width of the largest row or column label drawn by this
// heatmap.
vtkGetMacro(RowLabelWidth, float);
vtkGetMacro(ColumnLabelWidth, float);
//BTX
// Description:
......@@ -146,10 +157,6 @@ protected:
// Generate a separate vtkLookupTable for each column in the table.
void InitializeLookupTables();