From 0ff5553653bbfd0e773970b78bee356543c2bf74 Mon Sep 17 00:00:00 2001 From: Samuel Fadel Date: Thu, 24 Sep 2015 14:47:51 -0300 Subject: Updated selection handling code; implemented option to save subsample plot. --- main_view.qml | 38 ++++++++++++++++---------- scatterplot.cpp | 76 ++++++++++++++++++++++++++-------------------------- scatterplot.h | 16 ++++++----- selectionhandler.cpp | 8 +++--- selectionhandler.h | 5 ++-- 5 files changed, 78 insertions(+), 65 deletions(-) diff --git a/main_view.qml b/main_view.qml index 19b4efc..c84aa6c 100644 --- a/main_view.qml +++ b/main_view.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 import QtQuick.Controls 1.3 import QtQuick.Dialogs 1.2 +import QtQuick.Extras 1.4 import PM 1.0 ApplicationWindow { @@ -14,7 +15,6 @@ ApplicationWindow { title: "File" MenuItem { action: openAction } MenuItem { action: savePlotAction } - MenuItem { action: saveDataAction } MenuItem { action: quitAction } } @@ -78,10 +78,24 @@ ApplicationWindow { } FileDialog { - id: fileDialog - title: "Choose a file..." + id: fileOpenDialog + title: "Choose a data set to load..." + selectMultiple: false + selectExisting: true + onAccepted: { - // datasetLoader.load(fileDialog.fileUrls) + console.log("Loading data set: " + this.fileUrl) + } + } + + FileDialog { + id: fileSaveDialog + title: "Save subsample mapping..." + selectMultiple: false + selectExisting: false + + onAccepted: { + subsamplePlot.saveToFile(this.fileUrl) } } @@ -96,21 +110,17 @@ ApplicationWindow { id: openAction text: "&Open..." shortcut: "Ctrl+O" - onTriggered: fileDialog.open() + onTriggered: fileOpenDialog.open() } Action { id: savePlotAction - text: "Save &plot" + text: "&Save subsample" shortcut: "Ctrl+S" - onTriggered: console.log("Save plot") - } - - Action { - id: saveDataAction - text: "Save &data" - shortcut: "Ctrl+D" - onTriggered: console.log("Save data") + onTriggered: { + console.log("Saving subsample mapping...") + fileSaveDialog.open() + } } ExclusiveGroup { diff --git a/scatterplot.cpp b/scatterplot.cpp index 69f459c..a546980 100644 --- a/scatterplot.cpp +++ b/scatterplot.cpp @@ -34,6 +34,20 @@ void Scatterplot::setColorScale(ColorScale *colorScale) } } +arma::mat Scatterplot::XY() const +{ + return m_xy; +} + +bool Scatterplot::saveToFile(const QUrl &url) +{ + if (!url.isLocalFile()) { + return false; + } + + return m_xy.save(url.path().toStdString(), arma::raw_ascii); +} + void Scatterplot::setXY(const arma::mat &xy) { if (xy.n_cols != 2) { @@ -79,7 +93,7 @@ void Scatterplot::updateMaterials() update(); } -int calculateCircleVertexCount(qreal radius) +static int calculateCircleVertexCount(qreal radius) { // 10 * sqrt(r) \approx 2*pi / acos(1 - 1 / (4*r)) return (int) (10.0 * sqrt(radius)); @@ -105,14 +119,14 @@ void updateCircleGeometry(QSGGeometry *geometry, float size, float cx, float cy) } } -inline float Scatterplot::fromDataXToScreenX(float x) +inline float Scatterplot::fromDataXToScreenX(float x) const { return PADDING + (x - m_xmin) / (m_xmax - m_xmin) * (width() - 2*PADDING); } -inline float Scatterplot::fromDataYToScreenY(float y) +inline float Scatterplot::fromDataYToScreenY(float y) const { - return PADDING + (y - m_ymin) / (m_ymax - m_ymin) * (height() - 2*PADDING); + return PADDING + (1 - (y - m_ymin) / (m_ymax - m_ymin)) * (height() - 2*PADDING); } QSGNode *Scatterplot::createGlyphNodeTree() @@ -287,18 +301,13 @@ void Scatterplot::mouseMoveEvent(QMouseEvent *event) void Scatterplot::mouseReleaseEvent(QMouseEvent *event) { - bool mergeSelection; - arma::uvec selection; - switch (m_currentInteractionState) { case INTERACTION_SELECTING: - mergeSelection = (event->modifiers() == Qt::ControlModifier); - selection = findSelection(mergeSelection); - if (selection.n_elem > 0) { - setSelection(selection); - m_currentInteractionState = INTERACTION_SELECTED; - } else { - m_currentInteractionState = INTERACTION_NONE; + { + bool mergeSelection = (event->modifiers() == Qt::ControlModifier); + m_currentInteractionState = + updateSelection(mergeSelection) ? INTERACTION_SELECTED + : INTERACTION_NONE; } break; @@ -313,44 +322,35 @@ void Scatterplot::mouseReleaseEvent(QMouseEvent *event) } } -arma::uvec Scatterplot::findSelection(bool mergeSelection) +bool Scatterplot::updateSelection(bool mergeSelection) { - QSet selectedGlyphs(m_selectedGlyphs); - if (!mergeSelection) { - selectedGlyphs.clear(); + QSet selection; + if (mergeSelection) { + selection.unite(m_selectedGlyphs); } - QPointF dragOrigin(m_dragOriginPos.x() / width() * (m_xmax - m_xmin) + m_xmin, - m_dragOriginPos.y() / height() * (m_ymax - m_ymin) + m_ymin); - QPointF dragCurrent(m_dragCurrentPos.x() / width() * (m_xmax - m_xmin) + m_xmin, - m_dragCurrentPos.y() / height() * (m_ymax - m_ymin) + m_ymin); - QRectF selectionRect(dragOrigin, dragCurrent); + qreal originX = m_dragOriginPos.x() / width() * (m_xmax - m_xmin) + m_xmin; + qreal originY = (1 - m_dragOriginPos.y() / height()) * (m_ymax - m_ymin) + m_ymin; + qreal currentX = m_dragCurrentPos.x() / width() * (m_xmax - m_xmin) + m_xmin; + qreal currentY = (1 - m_dragCurrentPos.y() / height()) * (m_ymax - m_ymin) + m_ymin; + + QRectF selectionRect(QPointF(originX, originY), QPointF(currentX, currentY)); for (arma::uword i = 0; i < m_xy.n_rows; i++) { arma::rowvec row = m_xy.row(i); if (selectionRect.contains(row[0], row[1])) { - selectedGlyphs.insert(i); + selection.insert(i); } } - arma::uvec selection(selectedGlyphs.size()); - int i = 0; - for (auto it = selectedGlyphs.cbegin(); it != selectedGlyphs.cend(); it++, i++) { - selection[i] = *it; - } - - return selection; + setSelection(selection); + return !selection.isEmpty(); } -void Scatterplot::setSelection(const arma::uvec &selection) +void Scatterplot::setSelection(const QSet &selection) { - m_selectedGlyphs.clear(); - - for (auto it = selection.cbegin(); it != selection.cend(); it++) { - m_selectedGlyphs.insert(*it); - } - + m_selectedGlyphs = selection; update(); emit selectionChanged(selection); diff --git a/scatterplot.h b/scatterplot.h index f4fd238..3d7fa36 100644 --- a/scatterplot.h +++ b/scatterplot.h @@ -13,17 +13,19 @@ class Scatterplot : public QQuickItem public: Scatterplot(QQuickItem *parent = 0); + arma::mat XY() const; void setColorScale(ColorScale *colorScale); + Q_INVOKABLE bool saveToFile(const QUrl &url); signals: - void xyChanged(const arma::mat &XY); - void colorDataChanged(const arma::vec &colorData); - void selectionChanged(const arma::uvec &selection); + void xyChanged(const arma::mat &XY) const; + void colorDataChanged(const arma::vec &colorData) const; + void selectionChanged(const QSet &selection) const; public slots: void setXY(const arma::mat &xy); void setColorData(const arma::vec &colorData); - void setSelection(const arma::uvec &selection); + void setSelection(const QSet &selection); protected: QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); @@ -33,10 +35,10 @@ protected: private: QSGNode *createGlyphNodeTree(); - arma::uvec findSelection(bool mergeSelection); + bool updateSelection(bool mergeSelection); - float fromDataXToScreenX(float x); - float fromDataYToScreenY(float y); + float fromDataXToScreenX(float x) const; + float fromDataYToScreenY(float y) const; void applyManipulation(); diff --git a/selectionhandler.cpp b/selectionhandler.cpp index 4c488a0..44eef28 100644 --- a/selectionhandler.cpp +++ b/selectionhandler.cpp @@ -5,14 +5,14 @@ SelectionHandler::SelectionHandler(const arma::uvec &sampleIndices) { } -void SelectionHandler::setSelection(const arma::uvec &selection) +void SelectionHandler::setSelection(const QSet &selection) { - arma::uvec newSelection(selection); + QSet newSelection; // The selecion happens over the sample indices. We use the original dataset // indices in sampleIndices to translate indices. - for (auto it = newSelection.begin(); it != newSelection.end(); it++) { - *it = m_sampleIndices[*it]; + for (auto it = selection.begin(); it != selection.end(); it++) { + newSelection.insert(m_sampleIndices[*it]); } emit selectionChanged(newSelection); diff --git a/selectionhandler.h b/selectionhandler.h index 4c4a2ca..e5b9686 100644 --- a/selectionhandler.h +++ b/selectionhandler.h @@ -2,6 +2,7 @@ #define SELECTIONHANDLER_H #include +#include #include class SelectionHandler : public QObject @@ -11,10 +12,10 @@ public: SelectionHandler(const arma::uvec &sampleIndices); signals: - void selectionChanged(const arma::uvec &selection); + void selectionChanged(const QSet &selection); public slots: - void setSelection(const arma::uvec &selection); + void setSelection(const QSet &selection); private: arma::uvec m_sampleIndices; -- cgit v1.2.3