Skip to content

Commit

Permalink
Merge pull request #52 from gicmo/imshow
Browse files Browse the repository at this point in the history
Plot 2d-image like data as heatmap
  • Loading branch information
jgrewe committed Apr 13, 2016
2 parents 253b254 + c2d0ae6 commit ea37d5b
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ NixView.pro.user.18
NixView.pro.user.3.2-pre1
NixView.pro.user.5e84e8a
*~
.idea/
141 changes: 141 additions & 0 deletions plotter/imageplotter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "imageplotter.h"
#include "ui_imageplotter.h"
#include <QMenu>


ImagePlotter::ImagePlotter(QWidget *parent) :
QWidget(parent), ui(new Ui::ImagePlotter), cmap() {
ui->setupUi(this);

}

ImagePlotter::~ImagePlotter() {
delete ui;
}

QCustomPlot *ImagePlotter::get_plot() {
return ui->plot;
}

struct DimInfo {
bool valid;
QString unit;
QString label;

QVector<double> ticks;
QCPRange range;
};

static DimInfo get_dim_info(const nix::DataArray &array, nix::ndsize_t dim_index) {
nix::Dimension d = array.getDimension(dim_index);
DimInfo info;
info.valid = false;

nix::NDSize shape = array.dataExtent();

if (d.dimensionType() == nix::DimensionType::Sample) {
nix::SampledDimension dim = d.asSampledDimension();
info.valid = true;
info.label = dim.label().get_value_or("").c_str();
info.unit = dim.unit().get_value_or("").c_str();
info.ticks = QVector<double>::fromStdVector(dim.axis(shape[dim_index-1]));

} else if (d.dimensionType() == nix::DimensionType::Range) {
nix::RangeDimension dim = d.asRangeDimension();
info.valid = true;
info.label = dim.label().get_value_or("").c_str();
info.unit = dim.unit().get_value_or("").c_str();

info.ticks = QVector<double>::fromStdVector(dim.ticks());
}

const int size = info.ticks.size();
if (size > 0) {
info.range.lower = info.ticks[0];
info.range.upper = info.ticks[size - 1];
}

return info;
}

void ImagePlotter::draw(const nix::DataArray &array) {
if (array.dimensionCount() != 2) {
std::cerr << "ImagePlotter::draw can only draw 2D!" << std::endl;
return;
}

DimInfo yi = get_dim_info(array, 1); // rows == y
DimInfo xi = get_dim_info(array, 2); // cols == x

if (!(yi.valid && xi.valid)) {
std::cerr << "ImagePlotter::invalid dimensions found in array!" << std::endl;
return;
}

QCustomPlot *plot = get_plot();

plot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom); // this will also allow rescaling the color scale by dragging/zooming
plot->axisRect()->setupFullAxesBox(true);
plot->xAxis->setLabel(xi.label + " " + xi.unit);
plot->yAxis->setLabel(yi.label + " " + yi.unit);

QCPColorMap *colorMap = new QCPColorMap(plot->xAxis, plot->yAxis);
plot->addPlottable(colorMap);

int nx = xi.ticks.size();
int ny = yi.ticks.size();

colorMap->data()->setSize(nx, ny);
colorMap->data()->setRange(xi.range, yi.range);
colorMap->setInterpolate(false);

for (int xidx = 0; xidx < nx; xidx++) {
std::vector<double> data(static_cast<size_t>(nx));
//lets fetch a whole row (should be fast if data is
// row-major, like hdf5)
//ny, the number of rows in data-array
//xidx, the current column the fetch
// -> fetch all rows at column [xidx]
// count offset
array.getData(data, {ny, 1}, {0, xidx});
for (int yidx = 0; yidx < ny; yidx++) {
// data[ydix], the data point of the row[yidx], col[xidx]
colorMap->data()->setCell(xidx, yidx, data[yidx]);
}
}

QCPColorScale *colorScale = new QCPColorScale(plot);
plot->plotLayout()->addElement(0, 1, colorScale);
colorScale->setType(QCPAxis::atRight);
colorMap->setColorScale(colorScale);
if (array.label()) {
colorScale->axis()->setLabel(array.label().get().c_str());
}
colorMap->setGradient(QCPColorGradient::gpSpectrum);
colorMap->rescaleDataRange();

QCPMarginGroup *marginGroup = new QCPMarginGroup(plot);
plot->axisRect()->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup);
colorScale->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup);

plot->rescaleAxes();
}


void ImagePlotter::add_events(const QVector<double> &x_data, const QVector<double> &y_data, const QString &name,
bool y_scale) {

}

void ImagePlotter::add_segments(const QVector<double> &positions, const QVector<double> &extents, const QString &name) {

}

void ImagePlotter::set_label(const std::string &label) {

}

PlotterType ImagePlotter::plotter_type() const {
return PlotterType::Image;
}

41 changes: 41 additions & 0 deletions plotter/imageplotter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef IMAGEPLOTTER_H
#define IMAGEPLOTTER_H

#include <QWidget>
#include "plotter.h"
#include <nix.hpp>
#include "colormap.hpp"

namespace Ui {
class ImagePlotter;
}

class ImagePlotter : public QWidget, public Plotter {
Q_OBJECT
public:

virtual void add_events(const QVector<double> &x_data, const QVector<double> &y_data, const QString &name,
bool y_scale) override;

virtual void add_segments(const QVector<double> &positions, const QVector<double> &extents,
const QString &name) override;

virtual void set_label(const std::string &label) override;

virtual PlotterType plotter_type() const override;


public:
explicit ImagePlotter(QWidget *parent = 0);
~ImagePlotter();

void draw(const nix::DataArray &array);

private:
Ui::ImagePlotter *ui;
ColorMap cmap;

QCustomPlot* get_plot();
};

#endif //IMAGEPLOTTER_H
66 changes: 66 additions & 0 deletions plotter/imageplotter.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImagePlotter</class>
<widget class="QWidget" name="ImagePlotter">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCustomPlot" name="plot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
3 changes: 1 addition & 2 deletions plotter/plotter.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ class Plotter {
if (array.getDimension(2).dimensionType() == nix::DimensionType::Set) {
return PlotterType::Line;
} else {
// handle 2D image/heatmap plotting not supported, yet TODO
return PlotterType::Unsupported;
return PlotterType::Image;
}
} else {
if (array.getDimension(2).dimensionType() == nix::DimensionType::Sample ||
Expand Down
14 changes: 12 additions & 2 deletions plotwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "ui_plotwidget.h"
#include "plotter/lineplotter.h"
#include "plotter/categoryplotter.h"
#include "plotter/imageplotter.h"
#include "common/Common.hpp"

PlotWidget::PlotWidget(QWidget *parent) :
Expand Down Expand Up @@ -59,19 +60,28 @@ void PlotWidget::delete_widgets_from_layout() {


Plotter* PlotWidget::process(const nix::DataArray &array) {
if (Plotter::suggested_plotter(array) == PlotterType::Line) {
PlotterType suggestion = Plotter::suggested_plotter(array);

if (suggestion == PlotterType::Line) {
delete_widgets_from_layout();
LinePlotter *lp = new LinePlotter();
ui->scrollAreaWidgetContents->layout()->addWidget(lp);
lp->draw(array);
return lp;
} else if (Plotter::suggested_plotter(array) == PlotterType::Category) {
} else if (suggestion == PlotterType::Category) {
delete_widgets_from_layout();
CategoryPlotter *cp = new CategoryPlotter();
ui->scrollAreaWidgetContents->layout()->addWidget(cp);
cp->draw(array);
return cp;
} else if (suggestion == PlotterType::Image) {
delete_widgets_from_layout();
ImagePlotter *ip = new ImagePlotter();
ui->scrollAreaWidgetContents->layout()->addWidget(ip);
ip->draw(array);
return ip;
}

return nullptr;
}

Expand Down

0 comments on commit ea37d5b

Please sign in to comment.