summaryrefslogtreecommitdiffstats
path: root/stats/barseries.h
diff options
context:
space:
mode:
Diffstat (limited to 'stats/barseries.h')
-rw-r--r--stats/barseries.h140
1 files changed, 140 insertions, 0 deletions
diff --git a/stats/barseries.h b/stats/barseries.h
new file mode 100644
index 000000000..09d008094
--- /dev/null
+++ b/stats/barseries.h
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+// A small custom bar series, which displays information
+// when hovering over a bar. The QtCharts bar series were
+// too inflexible with respect to placement of the bars.
+#ifndef BAR_SERIES_H
+#define BAR_SERIES_H
+
+#include "statsseries.h"
+#include "statsvariables.h"
+
+#include <memory>
+#include <vector>
+#include <QGraphicsRectItem>
+
+namespace QtCharts {
+ class QAbstractAxis;
+}
+class InformationBox;
+class StatsVariable;
+
+class BarSeries : public StatsSeries {
+public:
+ // There are three versions of creating bar series: for value-based (mean, etc) charts, for counts
+ // based charts and for stacked bar charts with multiple items.
+ struct CountItem {
+ double lowerBound, upperBound;
+ int count;
+ std::vector<QString> label;
+ QString binName;
+ int total;
+ };
+ struct ValueItem {
+ double lowerBound, upperBound;
+ double value;
+ std::vector<QString> label;
+ QString binName;
+ StatsOperationResults res;
+ };
+ struct MultiItem {
+ double lowerBound, upperBound;
+ std::vector<std::pair<int, std::vector<QString>>> countLabels;
+ QString binName;
+ };
+
+ // If the horizontal flag is true, independent variable is plotted on the y-axis.
+ // A non-empty valueBinNames vector flags that this is a stacked bar chart.
+ // In that case, a valueVariable must also be provided.
+ // For count-based bar series in one variable, valueVariable is null.
+ // Note: this expects that all items are added with increasing pos
+ // and that no bar is inside another bar, i.e. lowerBound and upperBound
+ // are ordered identically.
+ BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
+ bool horizontal, const QString &categoryName,
+ const std::vector<CountItem> &items);
+ BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
+ bool horizontal, const QString &categoryName, const StatsVariable *valueVariable,
+ const std::vector<ValueItem> &items);
+ BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
+ bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
+ std::vector<QString> valueBinNames,
+ const std::vector<MultiItem> &items);
+ ~BarSeries();
+
+ void updatePositions() override;
+ bool hover(QPointF pos) override;
+ void unhighlight() override;
+private:
+ BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
+ bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
+ std::vector<QString> valueBinNames);
+
+ struct Index {
+ int bar;
+ int subitem;
+ Index();
+ Index(int bar, int subitem);
+ bool operator==(const Index &i2) const;
+ };
+
+ // Get item under mouse pointer, or -1 if none
+ Index getItemUnderMouse(const QPointF &f) const;
+
+ // A label that is composed of multiple lines
+ struct BarLabel {
+ std::vector<std::unique_ptr<QGraphicsSimpleTextItem>> items;
+ double totalWidth, totalHeight; // Size of the item
+ bool isOutside; // Is shown outside of bar
+ BarLabel(QtCharts::QChart *chart, const std::vector<QString> &labels, int bin_nr, int binCount);
+ void setVisible(bool visible);
+ void updatePosition(QtCharts::QChart *chart, QtCharts::QAbstractSeries *series,
+ bool horizontal, bool center, const QRectF &rect, int bin_nr, int binCount);
+ void highlight(bool highlight, int bin_nr, int binCount);
+ };
+
+ struct SubItem {
+ std::unique_ptr<QGraphicsRectItem> item;
+ std::unique_ptr<BarLabel> label;
+ double value_from;
+ double value_to;
+ int bin_nr;
+ void updatePosition(QtCharts::QChart *chart, BarSeries *series, bool horizontal, bool stacked,
+ double from, double to, int binCount);
+ void highlight(bool highlight, int binCount);
+ };
+
+ struct Item {
+ double lowerBound, upperBound;
+ std::vector<SubItem> subitems;
+ QRectF rect;
+ const QString binName;
+ StatsOperationResults res;
+ int total;
+ Item(QtCharts::QChart *chart, BarSeries *series, double lowerBound, double upperBound,
+ std::vector<SubItem> subitems,
+ const QString &binName, const StatsOperationResults &res, int total, bool horizontal,
+ bool stacked, int binCount);
+ void updatePosition(QtCharts::QChart *chart, BarSeries *series, bool horizontal, bool stacked, int binCount);
+ void highlight(int subitem, bool highlight, int binCount);
+ int getSubItemUnderMouse(const QPointF &f, bool horizontal, bool stacked) const;
+ };
+
+ std::unique_ptr<InformationBox> information;
+ std::vector<Item> items;
+ std::vector<BarLabel> barLabels;
+ bool horizontal;
+ bool stacked;
+ QString categoryName;
+ const StatsVariable *valueVariable; // null: this is count based
+ std::vector<QString> valueBinNames;
+ Index highlighted;
+ std::vector<SubItem> makeSubItems(double value, const std::vector<QString> &label) const;
+ std::vector<SubItem> makeSubItems(const std::vector<std::pair<double, std::vector<QString>>> &values) const;
+ void add_item(double lowerBound, double upperBound, std::vector<SubItem> subitems,
+ const QString &binName, const StatsOperationResults &res, int total, bool horizontal,
+ bool stacked);
+ std::vector<QString> makeInfo(const Item &item, int subitem) const;
+ int binCount() const;
+};
+
+#endif