Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parallel coordinates chart #1082

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ int ctkVTKScalarsToColorsViewTest2(int argc, char * argv [] )
ctkVTKScalarsToColorsView view(0);
// add transfer function item
vtkPlot* ctfPlot = view.addColorTransferFunction(ctf);
view.chart()->SetPlotCorner(ctfPlot, 1);
view.chartXY()->SetPlotCorner(ctfPlot, 1);
ctfPlot->SetOpacity(0.7);
// add histogram item
view.addPlot(histogramPlot);
view.chart()->SetBarWidthFraction(1.);
view.chartXY()->SetBarWidthFraction(1.);
view.setAxesToChartBounds();
view.show();

Expand Down
187 changes: 143 additions & 44 deletions Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

// VTK includes
#include <vtkAxis.h>
#include <vtkChart.h>
#include <vtkChartParallelCoordinates.h>
#include <vtkChartXY.h>
#include <vtkContext2D.h>
#include <vtkContextMouseEvent.h>
Expand All @@ -53,12 +55,13 @@ class ctkVTKChartViewPrivate
ctkVTKChartViewPrivate(ctkVTKChartView& object);
void init();
void chartBounds(double* bounds)const;
void setChartType(int chartType);

#ifdef CTK_USE_QVTKOPENGLWIDGET
vtkSmartPointer<vtkGenericOpenGLRenderWindow> RenderWindow;
#endif
vtkSmartPointer<vtkContextView> ContextView;
vtkSmartPointer<vtkChartXY> Chart;
vtkSmartPointer<vtkChart> Chart;
double UserBounds[8];
mutable double OldBounds[8];
};
Expand All @@ -74,14 +77,75 @@ ctkVTKChartViewPrivate::ctkVTKChartViewPrivate(ctkVTKChartView& object)
#ifdef CTK_USE_QVTKOPENGLWIDGET
this->RenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
#endif
this->Chart = vtkSmartPointer<vtkChartXY>::New();
this->setChartType(ctkVTKChartView::ChartType::XYChart);
}

// ----------------------------------------------------------------------------
void ctkVTKChartViewPrivate::setChartType(int type)
{
if (this->ContextView->GetScene()->GetNumberOfItems() > 0)
{
this->ContextView->GetScene()->RemoveItem(this->Chart);
}
switch (type)
{
case ctkVTKChartView::ChartType::XYChart:
this->Chart = vtkSmartPointer<vtkChartXY>::New();
break;
case ctkVTKChartView::ChartType::ParallelCoordinatesChart:
this->Chart = vtkSmartPointer<vtkChartParallelCoordinates>::New();
break;
case ctkVTKChartView::ChartType::UnknownChart:
#if (QT_VERSION >= QT_VERSION_CHECK(5,8,0))
Q_FALLTHROUGH();
#else
/* FALLTHRU */
#endif
default:
qWarning() << "ctkVTKChartViewPrivate::setChartType - Unknown chart type: " << type;
return;
}
this->ContextView->GetScene()->AddItem(this->Chart);
this->UserBounds[0] = this->UserBounds[2] = this->UserBounds[4] = this->UserBounds[6] = 0.;
this->UserBounds[1] = this->UserBounds[3] = this->UserBounds[5] = this->UserBounds[7] = -1.;
this->OldBounds[0] = this->OldBounds[2] = this->OldBounds[4] = this->OldBounds[6] = 0.;
this->OldBounds[1] = this->OldBounds[3] = this->OldBounds[5] = this->OldBounds[7] = -1.;
}

// ----------------------------------------------------------------------------
int ctkVTKChartView::chartType()const
{
Q_D(const ctkVTKChartView);
if (d->Chart == nullptr)
{
return ctkVTKChartView::ChartType::UnknownChart;
}
if (d->Chart->IsA("vtkChartXY"))
{
return ctkVTKChartView::ChartType::XYChart;
}
else if (d->Chart->IsA("vtkChartParallelCoordinates"))
{
return ctkVTKChartView::ChartType::ParallelCoordinatesChart;
}
else
{
return ctkVTKChartView::ChartType::UnknownChart;
}
}

// ----------------------------------------------------------------------------
void ctkVTKChartView::setChartType(int type)
{
Q_D(ctkVTKChartView);
if (type == this->chartType())
{
return;
}
d->setChartType(type);
emit chartTypeChanged(type);
}

// ----------------------------------------------------------------------------
void ctkVTKChartViewPrivate::init()
{
Expand Down Expand Up @@ -118,9 +182,9 @@ void ctkVTKChartViewPrivate::init()
this->Chart->SetActionToButton(vtkChart::PAN, vtkContextMouseEvent::MIDDLE_BUTTON);
this->Chart->SetActionToButton(vtkChart::SELECT, vtkContextMouseEvent::RIGHT_BUTTON);

q->qvtkConnect(q->chart()->GetAxis(vtkAxis::BOTTOM),vtkCommand::ModifiedEvent,
q->qvtkConnect(q->abstractChart()->GetAxis(vtkAxis::BOTTOM),vtkCommand::ModifiedEvent,
q, SIGNAL(extentChanged()));
q->qvtkConnect(q->chart()->GetAxis(vtkAxis::LEFT),vtkCommand::ModifiedEvent,
q->qvtkConnect(q->abstractChart()->GetAxis(vtkAxis::LEFT),vtkCommand::ModifiedEvent,
q, SIGNAL(extentChanged()));

}
Expand All @@ -135,53 +199,68 @@ void ctkVTKChartViewPrivate::chartBounds(double* bounds)const
Q_Q(const ctkVTKChartView);
bounds[0] = bounds[2] = bounds[4] = bounds[6] = VTK_DOUBLE_MAX;
bounds[1] = bounds[3] = bounds[5] = bounds[7] = VTK_DOUBLE_MIN;
vtkChartXY* chart = q->chart();
vtkChart* chart = q->abstractChart();
vtkChartXY* chartXY = vtkChartXY::SafeDownCast(chart);
const vtkIdType plotCount = chart->GetNumberOfPlots();
for (vtkIdType i = 0; i < plotCount; ++i)
{
vtkPlot* plot = chart->GetPlot(i);

int corner = chart->GetPlotCorner(plot);
double plotBounds[4];
plot->GetBounds(plotBounds);
switch (corner)
if (chartXY)
{
int corner = chartXY->GetPlotCorner(plot);
double plotBounds[4];
plot->GetBounds(plotBounds);
switch (corner)
{
// bottom left
case 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't there enums for 0, 1, 2, 3?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel coordinates don't have plot corner function.

// x
bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2];
jcfr marked this conversation as resolved.
Show resolved Hide resolved
bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3];
// y
bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[0];
bounds[1] = bounds[1] < plotBounds[3] ? plotBounds[3] : bounds[1];
break;
// bottom right
case 1:
// x
bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2];
bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3];
// y
bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4];
bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5];
break;
// top right
case 2:
// x
bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6];
bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7];
// y
bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4];
bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5];
break;
// top left
case 3:
// x
bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6];
bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7];
// y
bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[1];
bounds[1] = bounds[0] < plotBounds[3] ? plotBounds[3] : bounds[1];
break;
}
}
else
{
// bottom left
case 0:
double plotBounds[4];
plot->GetBounds(plotBounds);
// x
bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2];
bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3];
// y
bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[0];
bounds[1] = bounds[1] < plotBounds[3] ? plotBounds[3] : bounds[1];
break;
// bottom right
case 1:
// x
bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2];
bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3];
// y
bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4];
bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5];
break;
// top right
case 2:
// x
bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6];
bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7];
// y
bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4];
bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5];
break;
// top left
case 3:
// x
bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6];
bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7];
// y
bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[1];
bounds[1] = bounds[0] < plotBounds[3] ? plotBounds[3] : bounds[1];
break;
}
}
}
Expand Down Expand Up @@ -230,12 +309,32 @@ QString ctkVTKChartView::title()const
}

// ----------------------------------------------------------------------------
vtkChartXY* ctkVTKChartView::chart()const
vtkChart* ctkVTKChartView::abstractChart()const
{
Q_D(const ctkVTKChartView);
return d->Chart;
}

// ----------------------------------------------------------------------------
vtkChartParallelCoordinates* ctkVTKChartView::parallelCoordinatesChart()const
{
Q_D(const ctkVTKChartView);
return vtkChartParallelCoordinates::SafeDownCast(d->Chart);
}

// ----------------------------------------------------------------------------
vtkChartXY* ctkVTKChartView::chartXY()const
{
Q_D(const ctkVTKChartView);
return vtkChartXY::SafeDownCast(d->Chart);
}

// ----------------------------------------------------------------------------
vtkChartXY* ctkVTKChartView::chart()const
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
{
qWarning() << "This function is deprecated. Use xyChart() or abstractChart() instead";

return this->chartXY();
}

// ----------------------------------------------------------------------------
vtkContextScene* ctkVTKChartView::scene()const
{
Expand Down Expand Up @@ -321,7 +420,7 @@ void ctkVTKChartView::chartExtent(double* extent)const
}
extent[0] = extent[2] = extent[4] = extent[6] = VTK_DOUBLE_MAX;
extent[1] = extent[3] = extent[5] = extent[7] = VTK_DOUBLE_MIN;
vtkChartXY* chart = this->chart();
vtkChart* chart = this->abstractChart();
vtkAxis* axis = chart->GetAxis(vtkAxis::BOTTOM);
extent[0] = qMin(axis->GetMinimum(), extent[0]);
extent[1] = qMax(axis->GetMaximum(), extent[1]);
Expand All @@ -344,7 +443,7 @@ void ctkVTKChartView::setChartUserExtent(double* userExtent)
qCritical() << Q_FUNC_INFO << ": Invalid user extent";
return;
}
vtkChartXY* chart = this->chart();
vtkChart* chart = this->abstractChart();
vtkAxis* axis = chart->GetAxis(vtkAxis::BOTTOM);
axis->SetRange(userExtent[0], userExtent[1]);
axis = chart->GetAxis(vtkAxis::LEFT);
Expand Down Expand Up @@ -395,7 +494,7 @@ void ctkVTKChartView::chartUserBounds(double* bounds)const
// ----------------------------------------------------------------------------
void ctkVTKChartView::setAxesToChartBounds()
{
vtkChartXY* chart = this->chart();
vtkChart* chart = this->abstractChart();
double bounds[8];
this->chartBounds(bounds);
for (int i = 0; i < chart->GetNumberOfAxes(); ++i)
Expand All @@ -410,7 +509,7 @@ void ctkVTKChartView::setAxesToChartBounds()
// ----------------------------------------------------------------------------
void ctkVTKChartView::boundAxesToChartBounds()
{
vtkChartXY* chart = this->chart();
vtkChart* chart = this->abstractChart();
double bounds[8];
this->chartBounds(bounds);
for (int i = 0; i < chart->GetNumberOfAxes(); ++i)
Expand Down
26 changes: 25 additions & 1 deletion Libs/Visualization/VTK/Widgets/ctkVTKChartView.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
class ctkVTKChartViewPrivate;

// VTK includes
class vtkChart;
class vtkChartParallelCoordinates;
class vtkChartXY;
class vtkContextScene;
class vtkPlot;
Expand All @@ -38,7 +40,7 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKChartView : public ctkVTKOpenGL
Q_OBJECT
QVTK_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle)

Q_PROPERTY(int chartType READ chartType WRITE setChartType)
public:
typedef ctkVTKOpenGLNativeWidget Superclass;
ctkVTKChartView(QWidget* parent = 0);
Expand All @@ -58,9 +60,28 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKChartView : public ctkVTKOpenGL

/// Utility function that returns the view chart. It can be used for customizing
/// the chart display options (axes, legend...)
Q_INVOKABLE vtkChart* abstractChart()const;
Q_INVOKABLE vtkChartParallelCoordinates* parallelCoordinatesChart()const;
Q_INVOKABLE vtkChartXY* chartXY()const;
/// \deprecated Use chartXY() instead
Q_INVOKABLE vtkChartXY* chart()const;
Q_INVOKABLE vtkContextScene* scene()const;

/// Describe the chart associated with the view.
enum ChartType
{
UnknownChart,
XYChart,
ParallelCoordinatesChart,
};
Q_ENUM(ChartType)

///@{
/// Set/Get the type of the chart. Default chart type is XYChart.
int chartType() const;
void setChartType(int type);
///}@

/// Title that appears inside the view
QString title()const;
void setTitle(const QString& title);
Expand Down Expand Up @@ -100,6 +121,9 @@ public Q_SLOTS:
/// Fired anytime an axis is modified.
void extentChanged();

/// \sa setChartType()
void chartTypeChanged(int chartType);

protected:
QScopedPointer<ctkVTKChartViewPrivate> d_ptr;

Expand Down