Skip to content

Commit

Permalink
Merge pull request #379 from psavery/make-vtkplot-more-object-oriented
Browse files Browse the repository at this point in the history
Make VtkPlot more object-oriented
  • Loading branch information
ghutchis authored May 25, 2021
2 parents d1fe85e + c69831e commit ce4856d
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 73 deletions.
12 changes: 10 additions & 2 deletions avogadro/qtplugins/plotpdf/plotpdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,16 @@ void PlotPdf::displayDialog()
const char* yTitle = "g(r)";
const char* windowName = "Pair Distribution Function";

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
if (!m_plot)
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
12 changes: 10 additions & 2 deletions avogadro/qtplugins/plotrmsd/plotrmsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,16 @@ void PlotRmsd::displayDialog()
const char* yTitle = "RMSD (Angstrom)";
const char* windowName = "RMSD Curve";

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
if (!m_plot)
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;
QScopedPointer<VTK::VtkPlot> m_plot;
};

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

VTK::VtkPlot::generatePlot(data, lineLabels, lineColors, xTitle, yTitle,
windowName);
if (!m_plot)
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;
QScopedPointer<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

0 comments on commit ce4856d

Please sign in to comment.