diff options
Diffstat (limited to 'stats/barseries.h')
-rw-r--r-- | stats/barseries.h | 140 |
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 |