aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Fadel <samuelfadel@gmail.com>2016-01-07 15:10:20 +0100
committerSamuel Fadel <samuelfadel@gmail.com>2016-01-07 15:10:20 +0100
commit7676a38ea8a06d3d31228cb7eb1be00f90de46d3 (patch)
tree3082a0a466938f1a78c8738e30a7f37731717e3f
parentd17979519423b8afb67d9178820a458bf6a5474a (diff)
Added a bar chart.
* HistoryGraph replaced by BarChart * HistoryGraph not removed from code, might be useful in the future
-rw-r--r--barchart.cpp123
-rw-r--r--barchart.h34
-rw-r--r--main.cpp18
-rw-r--r--main_view.qml12
-rw-r--r--pm.pro2
5 files changed, 179 insertions, 10 deletions
diff --git a/barchart.cpp b/barchart.cpp
new file mode 100644
index 0000000..02509ae
--- /dev/null
+++ b/barchart.cpp
@@ -0,0 +1,123 @@
+#include "barchart.h"
+
+#include <algorithm>
+
+#include "geometry.h"
+#include "scale.h"
+
+static const QColor OUTLINE_COLOR(0, 0, 0);
+static const QColor BAR_COLOR(128, 128, 128);
+static const float DEFAULT_OPACITY = 0.8f;
+
+BarChart::BarChart(QQuickItem *parent)
+ : QQuickItem(parent)
+ , m_shouldUpdateBars(false)
+{
+ setClip(true);
+ setFlag(QQuickItem::ItemHasContents);
+ // setAcceptedMouseButtons(Qt::LeftButton);
+ setAcceptHoverEvents(true);
+}
+
+BarChart::~BarChart()
+{
+}
+
+void BarChart::setValues(const arma::vec &values)
+{
+ m_values = values;
+ m_shouldUpdateBars = true;
+ emit valuesChanged(values);
+}
+
+QSGNode *BarChart::newBarNode()
+{
+ // A bar node is:
+ // opacityNode [outlineGeomNode barGeomNode]
+
+ QSGGeometryNode *outlineGeomNode = new QSGGeometryNode;
+ QSGGeometry *outlineGeometry =
+ new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);
+ outlineGeometry->setDrawingMode(GL_LINE_LOOP);
+ outlineGeomNode->setGeometry(outlineGeometry);
+ outlineGeomNode->setFlag(QSGNode::OwnsGeometry);
+ QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
+ material->setColor(OUTLINE_COLOR);
+ outlineGeomNode->setMaterial(material);
+ outlineGeomNode->setFlag(QSGNode::OwnsMaterial);
+
+ QSGGeometryNode *barGeomNode = new QSGGeometryNode;
+ QSGGeometry *barGeometry =
+ new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4);
+ barGeometry->setDrawingMode(GL_POLYGON);
+ barGeomNode->setGeometry(barGeometry);
+ barGeomNode->setFlag(QSGNode::OwnsGeometry);
+ material = new QSGFlatColorMaterial;
+ material->setColor(BAR_COLOR);
+ barGeomNode->setMaterial(material);
+ barGeomNode->setFlag(QSGNode::OwnsMaterial);
+
+ QSGOpacityNode *opacityNode = new QSGOpacityNode;
+ opacityNode->setOpacity(DEFAULT_OPACITY);
+ opacityNode->appendChildNode(barGeomNode);
+ opacityNode->appendChildNode(outlineGeomNode);
+
+ return opacityNode;
+}
+
+void BarChart::updateBarNodeGeom(QSGNode *barNode, float x, float barWidth, float barHeight)
+{
+ QSGGeometryNode *outlineGeomNode =
+ static_cast<QSGGeometryNode *>(barNode->firstChild());
+ QSGGeometryNode *barGeomNode =
+ static_cast<QSGGeometryNode *>(barNode->firstChild()->nextSibling());
+
+ float y = height() - barHeight;
+ updateRectGeometry(outlineGeomNode->geometry(), x, y, barWidth, barHeight);
+ updateRectGeometry(barGeomNode->geometry(), x, y, barWidth, barHeight);
+}
+
+void BarChart::updateBars(QSGNode *root)
+{
+ QSGNode *node = root->firstChild();
+ float x = 0;
+ float barWidth = width() / m_values.n_elem;
+ LinearScale<float> heightScale(m_values.min(), m_values.max(), 0, height());
+
+ for (auto it = m_values.cbegin(); it != m_values.cend(); it++) {
+ updateBarNodeGeom(node, x, barWidth, heightScale((float) *it));
+ x += barWidth;
+ node = node->nextSibling();
+ }
+}
+
+QSGNode *BarChart::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QSGNode *root = oldNode ? oldNode : new QSGNode;
+ if (m_shouldUpdateBars) {
+ // First, make sure we have the same number of values & bars
+ while (m_values.n_elem > root->childCount()) {
+ QSGNode *barNode = newBarNode();
+ root->appendChildNode(barNode);
+ }
+ while (m_values.n_elem < root->childCount()) {
+ // NOTE: as stated in docs, QSGNode's children are stored in a
+ // linked list. Hence, this operation should be as fast as expected
+ root->removeChildNode(root->firstChild());
+ }
+
+ // Then, update the geometry of bars to reflect the values
+ updateBars(root);
+ m_shouldUpdateBars = false;
+ }
+
+ return root;
+}
+
+void BarChart::hoverMoveEvent(QHoverEvent *event)
+{
+}
+
+void BarChart::mousePressEvent(QMouseEvent *event)
+{
+}
diff --git a/barchart.h b/barchart.h
new file mode 100644
index 0000000..ccbb13e
--- /dev/null
+++ b/barchart.h
@@ -0,0 +1,34 @@
+#ifndef BARCHART_H
+#define BARCHART_H
+
+#include <QtQuick>
+#include <armadillo>
+
+class BarChart : public QQuickItem
+{
+ Q_OBJECT
+public:
+ BarChart(QQuickItem *parent = 0);
+ ~BarChart();
+
+signals:
+ void valuesChanged(const arma::vec &values);
+
+public slots:
+ void setValues(const arma::vec &values);
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
+ void hoverMoveEvent(QHoverEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ QSGNode *newBarNode();
+ void updateBarNodeGeom(QSGNode *barNode, float x, float width, float height);
+ void updateBars(QSGNode *root);
+
+ arma::vec m_values;
+ bool m_shouldUpdateBars;
+};
+
+#endif // BARCHART_H
diff --git a/main.cpp b/main.cpp
index b9d7232..41d0ed0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,6 +14,7 @@
#include "scatterplot.h"
#include "voronoisplat.h"
#include "historygraph.h"
+#include "barchart.h"
#include "interactionhandler.h"
#include "selectionhandler.h"
#include "effectivenessobserver.h"
@@ -158,6 +159,7 @@ int main(int argc, char **argv)
qmlRegisterType<Scatterplot>("PM", 1, 0, "Scatterplot");
qmlRegisterType<HistoryGraph>("PM", 1, 0, "HistoryGraph");
+ qmlRegisterType<BarChart>("PM", 1, 0, "BarChart");
qmlRegisterType<InteractionHandler>("PM", 1, 0, "InteractionHandler");
qmlRegisterSingletonType<Main>("PM", 1, 0, "Main", mainProvider);
@@ -222,11 +224,14 @@ int main(int argc, char **argv)
plot, SLOT(setSelection(const QSet<int> &)));
// Connections between history graph and subsample plot
- HistoryGraph *history = engine.rootObjects()[0]->findChild<HistoryGraph *>("history");
- QObject::connect(subsamplePlot, SIGNAL(xyInteractivelyChanged(const arma::mat &)),
- history, SLOT(addHistoryItem(const arma::mat &)));
- QObject::connect(history, SIGNAL(currentItemChanged(const arma::mat &)),
- subsamplePlot, SLOT(setXY(const arma::mat &)));
+ //HistoryGraph *history = engine.rootObjects()[0]->findChild<HistoryGraph *>("history");
+ //QObject::connect(subsamplePlot, SIGNAL(xyInteractivelyChanged(const arma::mat &)),
+ // history, SLOT(addHistoryItem(const arma::mat &)));
+ //QObject::connect(history, SIGNAL(currentItemChanged(const arma::mat &)),
+ // subsamplePlot, SLOT(setXY(const arma::mat &)));
+
+ BarChart *barChart = engine.rootObjects()[0]->findChild<BarChart *>("barChart");
+ barChart->setValues(arma::randn<arma::vec>(100));
// Map distortion as the glyph color
//DistortionObserver distortionObs(X, sampleIndices);
@@ -245,8 +250,7 @@ int main(int argc, char **argv)
//QObject::connect(&enforcer, SIGNAL(effectivenessChanged(const arma::vec &)),
// subsamplePlot, SLOT(setColorData(const arma::vec &)));
-
- history->addHistoryItem(Ys);
+ //history->addHistoryItem(Ys);
subsamplePlot->setXY(Ys);
subsamplePlot->setColorData(labels(sampleIndices));
plot->setColorScale(&colorScale);
diff --git a/main_view.qml b/main_view.qml
index a9c1c18..1be06d0 100644
--- a/main_view.qml
+++ b/main_view.qml
@@ -107,11 +107,17 @@ ApplicationWindow {
border.width: 1
border.color: "#cccccc"
- HistoryGraph {
- id: history
- objectName: "history"
+ BarChart {
+ id: barChart
+ objectName: "barChart"
anchors.fill: parent
}
+
+ //HistoryGraph {
+ // id: history
+ // objectName: "history"
+ // anchors.fill: parent
+ //}
}
}
diff --git a/pm.pro b/pm.pro
index 0a76551..54476c8 100644
--- a/pm.pro
+++ b/pm.pro
@@ -12,6 +12,7 @@ HEADERS += main.h \
scatterplot.h \
voronoisplat.h \
historygraph.h \
+ barchart.h \
interactionhandler.h \
selectionhandler.h \
effectivenessobserver.h \
@@ -28,6 +29,7 @@ SOURCES += main.cpp \
scatterplot.cpp \
voronoisplat.cpp \
historygraph.cpp \
+ barchart.cpp \
interactionhandler.cpp \
selectionhandler.cpp \
effectivenessobserver.cpp \