Commit e0cd2a5e authored by Zack Galbreath's avatar Zack Galbreath
Browse files

add scalar bar legend to vtkHeatmapItem

When double clicking on a column of continuous data, a scalar
bar depicting the range of values will now appear below the
heatmap.

Change-Id: I5da21f4eef1cb71a44c664682520eb6c6d880302
parent 6d639781
......@@ -46,6 +46,8 @@ vtkColorLegend::vtkColorLegend()
this->Callback->SetCallback(vtkColorLegend::OnScalarsToColorsModified);
this->TransferFunction = 0;
this->Orientation = vtkColorLegend::VERTICAL;
}
//-----------------------------------------------------------------------------
......@@ -85,6 +87,24 @@ void vtkColorLegend::Update()
{
this->ComputeTexture();
}
// check if the range of our TransferFunction changed
double bounds[4];
this->GetBounds(bounds);
if (bounds[0] == bounds[1])
{
vtkWarningMacro(<< "The color transfer function seems to be empty.");
this->Axis->Update();
return;
}
double axisBounds[2];
this->Axis->GetUnscaledRange(axisBounds);
if (bounds[0] != axisBounds[0] || bounds[1] != axisBounds[1])
{
this->Axis->SetUnscaledRange(bounds[0], bounds[1]);
}
this->Axis->Update();
}
......@@ -112,8 +132,18 @@ vtkScalarsToColors * vtkColorLegend::GetTransferFunction()
void vtkColorLegend::SetPosition(const vtkRectf& pos)
{
this->Position = pos;
this->Axis->SetPoint1(vtkVector2f(pos.GetX() + pos.GetWidth(), pos.GetY()));
this->Axis->SetPoint2(vtkVector2f(pos.GetX() + pos.GetWidth(), pos.GetY() + pos.GetHeight()));
if (this->Orientation == vtkColorLegend::VERTICAL)
{
this->Axis->SetPoint1(vtkVector2f(pos.GetX() + pos.GetWidth(), pos.GetY()));
this->Axis->SetPoint2(vtkVector2f(pos.GetX() + pos.GetWidth(),
pos.GetY() + pos.GetHeight()));
}
else
{
this->Axis->SetPoint1(vtkVector2f(pos.GetX(), pos.GetY()));
this->Axis->SetPoint2(vtkVector2f(pos.GetX() + pos.GetWidth(),
pos.GetY()));
}
}
//-----------------------------------------------------------------------------
......@@ -167,9 +197,18 @@ void vtkColorLegend::ComputeTexture()
const int dimension = 256;
double* values = new double[dimension];
// Texture 1D
this->ImageData->SetExtent(0, 0,
0, dimension-1,
0, 0);
if (this->Orientation == vtkColorLegend::VERTICAL)
{
this->ImageData->SetExtent(0, 0,
0, dimension-1,
0, 0);
}
else
{
this->ImageData->SetExtent(0, dimension-1,
0, 0,
0, 0);
}
this->ImageData->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
for (int i = 0; i < dimension; ++i)
......@@ -201,3 +240,30 @@ void vtkColorLegend::ScalarsToColorsModified(vtkObject* vtkNotUsed(object),
{
this->Modified();
}
//-----------------------------------------------------------------------------
void vtkColorLegend::SetOrientation(int orientation)
{
if (orientation < 0 || orientation > 1)
{
vtkErrorMacro("Error, invalid orientation value supplied: " << orientation)
return;
}
this->Orientation = orientation;
if (this->Orientation == vtkColorLegend::HORIZONTAL)
{
this->Axis->SetPosition(vtkAxis::BOTTOM);
}
}
//-----------------------------------------------------------------------------
void vtkColorLegend::SetTitle(const vtkStdString &title)
{
this->Axis->SetTitle(title);
}
//-----------------------------------------------------------------------------
vtkStdString vtkColorLegend::GetTitle()
{
return this->Axis->GetTitle();
}
......@@ -38,6 +38,13 @@ public:
virtual void PrintSelf(ostream &os, vtkIndent indent);
static vtkColorLegend* New();
// Description:
// Enum of legend orientation types
enum {
VERTICAL = 0,
HORIZONTAL
};
// Description:
// Bounds of the item, by default (0, 1, 0, 1) but it mainly depends on the
// range of the vtkScalarsToColors function.
......@@ -68,6 +75,17 @@ public:
// ensure the numbers are correct, Update() should be called first.
vtkRectf GetBoundingRect(vtkContext2D* painter);
// Description:
// Set/get the orientation of the legend.
// Valid orientations are VERTICAL (default) and HORIZONTAL.
virtual void SetOrientation(int orientation);
vtkGetMacro(Orientation, int);
// Description:
// Get/set the title text of the legend.
virtual void SetTitle(const vtkStdString &title);
virtual vtkStdString GetTitle();
protected:
vtkColorLegend();
virtual ~vtkColorLegend();
......@@ -91,6 +109,7 @@ protected:
vtkSmartPointer<vtkCallbackCommand> Callback;
bool Interpolate;
vtkRectf Position;
int Orientation;
private:
vtkColorLegend(const vtkColorLegend &); // Not implemented.
......
......@@ -10,6 +10,7 @@ vtk_module(vtkViewsInfovis
vtkFiltersModeling
vtkFiltersImaging
vtkCommonColor
vtkChartsCore
PRIVATE_DEPENDS
vtkFiltersGeometry
TEST_DEPENDS
......
......@@ -16,6 +16,7 @@
#include "vtkBitArray.h"
#include "vtkBrush.h"
#include "vtkColorLegend.h"
#include "vtkColorSeries.h"
#include "vtkContext2D.h"
#include "vtkContextMouseEvent.h"
......@@ -26,6 +27,7 @@
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPen.h"
#include "vtkRect.h"
#include "vtkStringArray.h"
#include "vtkTable.h"
#include "vtkTextProperty.h"
......@@ -59,6 +61,11 @@ vtkHeatmapItem::vtkHeatmapItem() : PositionVector(0, 0)
this->CellHeight = 18.0;
this->CellWidth = this->CellHeight * 2.0;
this->ColorLegend->SetVisible(false);
this->ColorLegend->SetDragEnabled(true);
this->AddItem(this->ColorLegend.GetPointer());
this->ColorLegendPositionSet = false;
this->Tooltip->SetVisible(false);
this->AddItem(this->Tooltip.GetPointer());
}
......@@ -211,6 +218,11 @@ void vtkHeatmapItem::GenerateContinuousDataLookupTable()
float f = static_cast<float>(i) / 84.0;
this->ContinuousDataLookupTable->SetTableValue(170 + i, 1.0, 1.0, f);
}
this->ColorLegendLookupTable->DeepCopy(
this->ContinuousDataLookupTable.GetPointer());
this->ColorLegend->SetTransferFunction(
this->ColorLegendLookupTable.GetPointer());
}
//-----------------------------------------------------------------------------
......@@ -486,7 +498,8 @@ void vtkHeatmapItem::PaintBuffers(vtkContext2D *painter)
break;
}
if (this->LineIsVisible(cellStartX, cellStartY, cellStartX + this->CellWidth,
if (this->LineIsVisible(cellStartX, cellStartY,
cellStartX + this->CellWidth,
cellStartY + this->CellHeight) ||
this->LineIsVisible(cellStartX, cellStartY + this->CellHeight,
cellStartX + this->CellWidth, cellStartY))
......@@ -813,6 +826,9 @@ void vtkHeatmapItem::SetOrientation(int orientation)
orientationArray->InsertNextValue(orientation);
this->Table->GetFieldData()->AddArray(orientationArray);
}
//reposition the color legend
this->PositionColorLegend(orientation);
}
//-----------------------------------------------------------------------------
......@@ -1018,6 +1034,93 @@ void vtkHeatmapItem::MarkRowAsBlank(std::string rowName)
this->BlankRows.insert(rowName);
}
//-----------------------------------------------------------------------------
bool vtkHeatmapItem::MouseDoubleClickEvent(const vtkContextMouseEvent &event)
{
// get the position of the double click and convert it to scene coordinates
double pos[3];
vtkNew<vtkMatrix3x3> inverse;
pos[0] = event.GetPos().GetX();
pos[1] = event.GetPos().GetY();
pos[2] = 0;
this->GetScene()->GetTransform()->GetInverse(inverse.GetPointer());
inverse->MultiplyPoint(pos, pos);
if (pos[0] <= this->MaxX && pos[0] >= this->MinX &&
pos[1] <= this->MaxY && pos[1] >= this->MinY)
{
vtkIdType column = 0;
int orientation = this->GetOrientation();
if (orientation == vtkHeatmapItem::UP_TO_DOWN ||
orientation == vtkHeatmapItem::DOWN_TO_UP)
{
column = floor((pos[1] - this->MinY) / this->CellWidth);
}
else
{
column = floor((pos[0] - this->MinX) / this->CellWidth);
}
++column;
if (!this->Table->GetValue(0, column).IsString())
{
this->ColorLegend->GetTransferFunction()->SetRange(
this->ColumnRanges[column].first,
this->ColumnRanges[column].second);
this->ColorLegend->SetTitle(this->Table->GetColumn(column)->GetName());
if (!this->ColorLegendPositionSet)
{
this->PositionColorLegend(this->GetOrientation());
}
this->ColorLegend->Update();
this->ColorLegend->SetVisible(true);
this->Scene->SetDirty(true);
return true;
}
}
bool shouldRepaint = this->ColorLegend->GetVisible();
this->ColorLegend->SetVisible(false);
if (shouldRepaint)
{
this->Scene->SetDirty(true);
}
return false;
}
//-----------------------------------------------------------------------------
void vtkHeatmapItem::PositionColorLegend(int orientation)
{
// bail out early if we don't have meaningful bounds yet.
if (this->MinX > this->MaxX || this->MinY > this->MaxY)
{
return;
}
switch(orientation)
{
case vtkHeatmapItem::DOWN_TO_UP:
case vtkHeatmapItem::UP_TO_DOWN:
this->ColorLegend->SetOrientation(vtkColorLegend::VERTICAL);
this->ColorLegend->SetPosition(
vtkRectf(this->MinX - this->CellWidth * 3, this->MinY,
this->ColorLegend->GetSymbolWidth(), this->MaxY - this->MinY));
break;
case vtkHeatmapItem::RIGHT_TO_LEFT:
case vtkHeatmapItem::LEFT_TO_RIGHT:
default:
this->ColorLegend->SetOrientation(vtkColorLegend::HORIZONTAL);
this->ColorLegend->SetPosition(
vtkRectf(this->MinX, this->MinY - this->CellHeight * 3,
this->MaxX - this->MinX, this->ColorLegend->GetSymbolWidth()));
break;
}
this->ColorLegendPositionSet = true;
}
//-----------------------------------------------------------------------------
bool vtkHeatmapItem::Hit(const vtkContextMouseEvent &vtkNotUsed(mouse))
{
......
......@@ -34,6 +34,7 @@
#include <vector> // For row mapping
class vtkBitArray;
class vtkColorLegend;
class vtkLookupTable;
class vtkStringArray;
class vtkTable;
......@@ -130,6 +131,10 @@ public:
// Display a tooltip when the user mouses over a cell in the heatmap.
virtual bool MouseMoveEvent(const vtkContextMouseEvent &event);
// Description:
// TODO
virtual bool MouseDoubleClickEvent(const vtkContextMouseEvent &event);
//ETX
protected:
......@@ -203,6 +208,10 @@ protected:
// longest column label. These values are used by GetBounds().
void ComputeLabelWidth(vtkContext2D *painter);
// Setup the position, size, and orientation of this heatmap's color
// legend based on the heatmap's current orientation.
void PositionColorLegend(int orientation);
vtkSmartPointer<vtkTable> Table;
private:
......@@ -210,9 +219,11 @@ private:
void operator=(const vtkHeatmapItem&); // Not implemented
unsigned long HeatmapBuildTime;
vtkNew<vtkColorLegend> ColorLegend;
vtkNew<vtkTooltipItem> Tooltip;
vtkNew<vtkLookupTable> ContinuousDataLookupTable;
vtkNew<vtkLookupTable> CategoricalDataLookupTable;
vtkNew<vtkLookupTable> ColorLegendLookupTable;
vtkNew<vtkStringArray> CategoricalDataValues;
double CellWidth;
double CellHeight;
......@@ -233,6 +244,7 @@ private:
vtkBitArray* CollapsedRowsArray;
vtkBitArray* CollapsedColumnsArray;
bool ColorLegendPositionSet;
};
#endif
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