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

Make VtkPlot more object-oriented #379

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions avogadro/qtplugins/plotpdf/plotpdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,14 @@ void PlotPdf::displayDialog()
const char* yTitle = "g(r)";
const char* windowName = "Pair Distribution Function";

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
m_plot.reset(new VTK::VtkPlot());
m_plot->setData(data);
m_plot->setWindowName(windowName);
m_plot->setXTitle(xTitle);
m_plot->setYTitle(yTitle);
m_plot->setLineLabels(lineLabels);
m_plot->setLineColors(lineColors);
m_plot->show();
}

bool PlotPdf::generatePdfPattern(QtGui::Molecule& mol, PdfData& results,
Expand Down
5 changes: 5 additions & 0 deletions avogadro/qtplugins/plotpdf/plotpdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
class QByteArray;
class QStringList;

namespace VTK {
class VtkPlot;
}

namespace Avogadro {
namespace QtPlugins {

Expand Down Expand Up @@ -71,6 +75,7 @@ private slots:

QScopedPointer<PdfOptionsDialog> m_pdfOptionsDialog;
QScopedPointer<QAction> m_displayDialogAction;
QScopedPointer<VTK::VtkPlot> m_plot;
};

inline QString PlotPdf::description() const
Expand Down
10 changes: 8 additions & 2 deletions avogadro/qtplugins/plotrmsd/plotrmsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,14 @@ void PlotRmsd::displayDialog()
const char* yTitle = "RMSD (Angstrom)";
const char* windowName = "RMSD Curve";

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
m_plot.reset(new VTK::VtkPlot());
m_plot->setData(data);
m_plot->setWindowName(windowName);
m_plot->setXTitle(xTitle);
m_plot->setYTitle(yTitle);
m_plot->setLineLabels(lineLabels);
m_plot->setLineColors(lineColors);
m_plot->show();
}

void PlotRmsd::generateRmsdPattern(RmsdData& results)
Expand Down
5 changes: 5 additions & 0 deletions avogadro/qtplugins/plotrmsd/plotrmsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
class QByteArray;
class QStringList;

namespace VTK {
class VtkPlot;
}

namespace Avogadro {
namespace QtPlugins {

Expand Down Expand Up @@ -66,6 +70,7 @@ private slots:
QtGui::Molecule* m_molecule;

std::unique_ptr<QAction> m_displayDialogAction;
std::unique_ptr<VTK::VtkPlot> m_plot;
};

inline QString PlotRmsd::description() const
Expand Down
10 changes: 8 additions & 2 deletions avogadro/qtplugins/plotxrd/plotxrd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,14 @@ void PlotXrd::displayDialog()
const char* yTitle = "Intensity";
const char* windowName = "Theoretical XRD Pattern";

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
m_plot.reset(new VTK::VtkPlot());
m_plot->setData(data);
m_plot->setWindowName(windowName);
m_plot->setXTitle(xTitle);
m_plot->setYTitle(yTitle);
m_plot->setLineLabels(lineLabels);
m_plot->setLineColors(lineColors);
m_plot->show();
}

bool PlotXrd::generateXrdPattern(const QtGui::Molecule& mol, XrdData& results,
Expand Down
5 changes: 5 additions & 0 deletions avogadro/qtplugins/plotxrd/plotxrd.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
class QByteArray;
class QStringList;

namespace VTK {
class VtkPlot;
}

namespace Avogadro {
namespace QtPlugins {

Expand Down Expand Up @@ -86,6 +90,7 @@ private slots:

std::unique_ptr<XrdOptionsDialog> m_xrdOptionsDialog;
std::unique_ptr<QAction> m_displayDialogAction;
std::unique_ptr<VTK::VtkPlot> m_plot;
};

inline QString PlotXrd::description() const
Expand Down
126 changes: 68 additions & 58 deletions avogadro/vtk/vtkplot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,41 @@ using std::vector;
namespace Avogadro {
namespace VTK {

void VtkPlot::generatePlot(const vector<vector<double>>& data,
const vector<string>& lineLabels,
const vector<array<double, 4>>& lineColors,
const char* xTitle, const char* yTitle,
const char* windowName)
VtkPlot::VtkPlot() : m_widget(new QVTKOpenGLWidget)
{
m_widget->SetRenderWindow(m_renderWindow);

// Set up the view
m_widget->setFormat(QVTKOpenGLWidget::defaultFormat());
m_view->SetRenderWindow(m_renderWindow);
m_view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
m_view->GetRenderWindow()->SetSize(600, 600);

// Add the chart
m_view->GetScene()->AddItem(m_chart);

vtkAxis* bottomAxis = m_chart->GetAxis(vtkAxis::BOTTOM);
vtkAxis* leftAxis = m_chart->GetAxis(vtkAxis::LEFT);

// Increase the title font sizes
bottomAxis->GetTitleProperties()->SetFontSize(20);
leftAxis->GetTitleProperties()->SetFontSize(20);

// Increase the tick font sizes
bottomAxis->GetLabelProperties()->SetFontSize(20);
leftAxis->GetLabelProperties()->SetFontSize(20);
}

VtkPlot::~VtkPlot() = default;

void VtkPlot::setData(const vector<vector<double>>& data)
{
if (data.size() < 2) {
std::cerr << "Error in " << __FUNCTION__
<< ": data must be of size 2 or greater!\n";
return;
}

// Create a table and add the data as columns
vtkNew<vtkTable> table;

for (size_t i = 0; i < data.size(); ++i) {
vtkNew<vtkFloatArray> array;
// Unique column names are necessary to prevent vtk from crashing.
array->SetName(("Column " + std::to_string(i)).c_str());
table->AddColumn(array);
}

// All of the rows must be equal in size currently. Otherwise, we get
// a garbage plot. We may be able to improve on this in the future.
size_t numRows = data[0].size();
Expand All @@ -76,70 +89,67 @@ void VtkPlot::generatePlot(const vector<vector<double>>& data,
}
}

// Erase the current table
while (m_table->GetNumberOfRows() > 0)
m_table->RemoveRow(0);

for (size_t i = 0; i < data.size(); ++i) {
vtkNew<vtkFloatArray> array;
// Unique column names are necessary to prevent vtk from crashing.
array->SetName(("Column " + std::to_string(i)).c_str());
m_table->AddColumn(array);
}

// Put the data in the table
table->SetNumberOfRows(numRows);
m_table->SetNumberOfRows(numRows);
for (size_t i = 0; i < data.size(); ++i) {
for (size_t j = 0; j < data[i].size(); ++j) {
table->SetValue(j, i, data[i][j]);
m_table->SetValue(j, i, data[i][j]);
}
}
}

// Set up the view
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
QVTKOpenGLWidget* widget = new QVTKOpenGLWidget();
widget->SetRenderWindow(renderWindow);
// Hackish, but at least it won't leak
widget->setAttribute(Qt::WA_DeleteOnClose);
widget->setFormat(QVTKOpenGLWidget::defaultFormat());
vtkNew<vtkContextView> view;
view->SetRenderWindow(renderWindow);
view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
view->GetRenderWindow()->SetSize(600, 600);
view->GetRenderWindow()->SetWindowName(windowName);

// Add the chart
vtkNew<vtkChartXY> chart;
view->GetScene()->AddItem(chart);

vtkAxis* bottomAxis = chart->GetAxis(vtkAxis::BOTTOM);
vtkAxis* leftAxis = chart->GetAxis(vtkAxis::LEFT);
void VtkPlot::setWindowName(const char* windowName)
{
m_view->GetRenderWindow()->SetWindowName(windowName);
}

// Set the axis titles
void VtkPlot::setXTitle(const char* xTitle)
{
vtkAxis* bottomAxis = m_chart->GetAxis(vtkAxis::BOTTOM);
bottomAxis->SetTitle(xTitle);
leftAxis->SetTitle(yTitle);

// Increase the title font sizes
bottomAxis->GetTitleProperties()->SetFontSize(20);
leftAxis->GetTitleProperties()->SetFontSize(20);
}

// Increase the tick font sizes
bottomAxis->GetLabelProperties()->SetFontSize(20);
leftAxis->GetLabelProperties()->SetFontSize(20);
void VtkPlot::setYTitle(const char* yTitle)
{
vtkAxis* leftAxis = m_chart->GetAxis(vtkAxis::LEFT);
leftAxis->SetTitle(yTitle);
}

// Adjust the range on the x axis
bottomAxis->SetBehavior(vtkAxis::FIXED);
bottomAxis->SetRange(data[0].front(), data[0].back());
void VtkPlot::show()
{
// First, clear all previous plots
m_chart->ClearPlots();

// Add the lines to the chart
for (size_t i = 1; i < data.size(); ++i) {
vtkPlot* line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table, 0, i);
for (size_t i = 1; i < m_table->GetNumberOfColumns(); ++i) {
vtkPlot* line = m_chart->AddPlot(vtkChart::LINE);
line->SetInputData(m_table, 0, i);

// If we have a label for this line, set it
if (i <= lineLabels.size())
line->SetLabel(lineLabels[i - 1]);
if (i <= m_lineLabels.size())
line->SetLabel(m_lineLabels[i - 1]);

// If we have a color for this line, set it (rgba)
if (i <= lineColors.size()) {
line->SetColor(lineColors[i - 1][0], lineColors[i - 1][1],
lineColors[i - 1][2], lineColors[i - 1][3]);
if (i <= m_lineColors.size()) {
line->SetColor(m_lineColors[i - 1][0], m_lineColors[i - 1][1],
m_lineColors[i - 1][2], m_lineColors[i - 1][3]);
}

line->SetWidth(2.0);
}

// Start the widget, we probably want to improve this in future.
widget->show();
m_widget->show();
}

} // namespace VTK
Expand Down
48 changes: 39 additions & 9 deletions avogadro/vtk/vtkplot.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@

#include "avogadrovtkexport.h"

#include <vtkNew.h>

#include <array>
#include <memory>
#include <string>
#include <vector>

class QVTKOpenGLWidget;
class vtkChartXY;
class vtkContextView;
class vtkGenericOpenGLRenderWindow;
class vtkTable;

namespace Avogadro {
namespace VTK {

Expand All @@ -32,15 +41,36 @@ namespace VTK {
class AVOGADROVTK_EXPORT VtkPlot
{
public:
// This function can generate multiple lines on the same chart.
// data[0] is the x data, and data[i] for i != 0 is the y data for line
// i - 1. 'lineLabels' and 'lineColors' should be equal to the number of
// lines (data.size() - 1) and ordered in the same way as they are in 'data'.
static void generatePlot(const std::vector<std::vector<double>>& data,
const std::vector<std::string>& lineLabels,
const std::vector<std::array<double, 4>>& lineColors,
const char* xTitle, const char* yTitle,
const char* windowName);
explicit VtkPlot();
~VtkPlot();

// data[0] is the x data, and data[i] for i != 0 is the y data for the
// line i != 0.
void setData(const std::vector<std::vector<double>>& data);
void setWindowName(const char* windowName);
void setXTitle(const char* xTitle);
void setYTitle(const char* yTitle);

// 'lineLabels' and 'lineColors' should be equal to the number of lines
// (data.size() - 1) and ordered in the same way as they are in 'data'.
void setLineLabels(const std::vector<std::string>& labels)
{
m_lineLabels = labels;
}
void setLineColors(const std::vector<std::array<double, 4>>& colors)
{
m_lineColors = colors;
}
void show();

private:
std::unique_ptr<QVTKOpenGLWidget> m_widget;
vtkNew<vtkTable> m_table;
vtkNew<vtkGenericOpenGLRenderWindow> m_renderWindow;
vtkNew<vtkContextView> m_view;
vtkNew<vtkChartXY> m_chart;
std::vector<std::string> m_lineLabels;
std::vector<std::array<double, 4>> m_lineColors;
};

} // namespace VTK
Expand Down