subsurface/stats/statsview.h
Berthold Stoeger 1a869833d8 statistics: implement moving of legend
Catch mouse move events and move the legend accordingly.
Currently, this is the only item that can be dragged and
therefore there is no need of doing some kind of fancy
interface. Simply keep a pointer to the legend if it is
dragged.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 08:47:18 +01:00

183 lines
6.8 KiB
C++

// SPDX-License-Identifier: GPL-2.0
#ifndef STATS_VIEW_H
#define STATS_VIEW_H
#include "statsstate.h"
#include <memory>
#include <QFont>
#include <QGraphicsScene>
#include <QImage>
#include <QPainter>
#include <QQuickItem>
#include <QGraphicsPolygonItem>
struct dive;
struct StatsBinner;
struct StatsBin;
struct StatsState;
struct StatsVariable;
class QGraphicsLineItem;
class QGraphicsSimpleTextItem;
class QSGImageNode;
class StatsSeries;
class CategoryAxis;
class ChartItem;
class CountAxis;
class HistogramAxis;
class StatsAxis;
class StatsGrid;
class Legend;
class QSGTexture;
enum class ChartSubType : int;
enum class StatsOperation : int;
struct regression_data {
double a,b;
double res2, r2, sx2, xavg;
int n;
};
class StatsView : public QQuickItem {
Q_OBJECT
public:
StatsView();
StatsView(QQuickItem *parent);
~StatsView();
void plot(const StatsState &state);
QQuickWindow *w() const; // Make window available to items
QSizeF size() const;
void addQSGNode(QSGNode *node, int z); // Must only be called in render thread!
void unregisterChartItem(const ChartItem *item);
private slots:
void replotIfVisible();
private:
// QtQuick related things
QRectF plotRect;
QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
std::unique_ptr<QImage> img;
std::unique_ptr<QPainter> painter;
QGraphicsScene scene;
std::unique_ptr<QSGTexture> texture;
void plotAreaChanged(const QSizeF &size);
void reset(); // clears all series and axes
void setAxes(StatsAxis *x, StatsAxis *y);
void plotBarChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
const StatsVariable *valueVariable, const StatsBinner *valueBinner, bool labels, bool legend);
void plotValueChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
const StatsVariable *valueVariable, StatsOperation valueAxisOperation, bool labels);
void plotDiscreteCountChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, bool labels);
void plotPieChart(const std::vector<dive *> &dives,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, bool labels, bool legend);
void plotDiscreteBoxChart(const std::vector<dive *> &dives,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, const StatsVariable *valueVariable);
void plotDiscreteScatter(const std::vector<dive *> &dives,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
const StatsVariable *valueVariable, bool quartiles);
void plotHistogramCountChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
bool labels, bool showMedian, bool showMean);
void plotHistogramValueChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
const StatsVariable *valueVariable, StatsOperation valueAxisOperation, bool labels);
void plotHistogramStackedChart(const std::vector<dive *> &dives,
ChartSubType subType,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
const StatsVariable *valueVariable, const StatsBinner *valueBinner, bool labels, bool legend);
void plotHistogramBoxChart(const std::vector<dive *> &dives,
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, const StatsVariable *valueVariable);
void plotScatter(const std::vector<dive *> &dives, const StatsVariable *categoryVariable, const StatsVariable *valueVariable);
void setTitle(const QString &);
void updateTitlePos(); // After resizing, set title to correct position
void plotChart();
template <typename T, class... Args>
T *createSeries(Args&&... args);
template <typename T, class... Args>
T *createAxis(const QString &title, Args&&... args);
template <typename T, class... Args>
std::unique_ptr<T> createChartItem(Args&&... args);
template<typename T>
CategoryAxis *createCategoryAxis(const QString &title, const StatsBinner &binner,
const std::vector<T> &bins, bool isHorizontal);
template<typename T>
HistogramAxis *createHistogramAxis(const QString &title, const StatsBinner &binner,
const std::vector<T> &bins, bool isHorizontal);
CountAxis *createCountAxis(int maxVal, bool isHorizontal);
// Helper functions to add feature to the chart
void addLineMarker(double pos, double low, double high, const QPen &pen, bool isHorizontal);
// A short line used to mark quartiles
struct QuartileMarker {
std::unique_ptr<QGraphicsLineItem> item;
StatsAxis *xAxis, *yAxis;
double pos, value;
QuartileMarker(double pos, double value, QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis);
void updatePosition();
};
// A regression line
struct RegressionLine {
std::unique_ptr<QGraphicsPolygonItem> item;
std::unique_ptr<QGraphicsPolygonItem> central;
StatsAxis *xAxis, *yAxis;
const struct regression_data reg;
void updatePosition();
RegressionLine(const struct regression_data reg, QBrush brush, QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis);
};
// A line marking median or mean in histograms
struct HistogramMarker {
std::unique_ptr<QGraphicsLineItem> item;
StatsAxis *xAxis, *yAxis;
double val;
bool horizontal;
void updatePosition();
HistogramMarker(double val, bool horizontal, QPen pen, QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis);
};
void addLinearRegression(const struct regression_data reg, StatsAxis *xAxis, StatsAxis *yAxis);
void addHistogramMarker(double pos, const QPen &pen, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis);
StatsState state;
QFont titleFont;
std::vector<std::unique_ptr<StatsAxis>> axes;
std::unique_ptr<StatsGrid> grid;
std::vector<std::unique_ptr<StatsSeries>> series;
std::unique_ptr<Legend> legend;
std::vector<QuartileMarker> quartileMarkers;
std::vector<RegressionLine> regressionLines;
std::vector<HistogramMarker> histogramMarkers;
std::unique_ptr<QGraphicsSimpleTextItem> title;
std::vector<ChartItem *> items; // Attention: currently, items are not automatically removed on destruction!
StatsSeries *highlightedSeries;
StatsAxis *xAxis, *yAxis;
Legend *draggedItem;
QPointF dragStartMouse, dragStartItem;
void hoverEnterEvent(QHoverEvent *event) override;
void hoverMoveEvent(QHoverEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
QSGImageNode *rootNode;
};
#endif