diff options
Diffstat (limited to 'stats/statsvariables.h')
-rw-r--r-- | stats/statsvariables.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/stats/statsvariables.h b/stats/statsvariables.h new file mode 100644 index 000000000..06fb90f2a --- /dev/null +++ b/stats/statsvariables.h @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +// Variables displayed by the statistic widgets. There are three +// kinds of variables: +// 1) Discrete variables can only adopt discrete values. +// Examples are dive-type or dive buddy. +// Note that for example dive buddy means that a dive can have +// multiple values. +// 2) Continuous variables have a notion of a linear distance and can be +// plotted on a linear axis. +// An Example is the dive-date. +// 3) Numeric variables are continuous variables that support operations +// such as averaging. +#ifndef STATS_TYPES_H +#define STATS_TYPES_H + +#include <vector> +#include <memory> +#include <QString> +#include <QObject> + +struct dive; + +// Operations that can be performed on numeric variables +enum class StatsOperation : int { + Median = 0, + Mean, + TimeWeightedMean, + Sum, + Invalid +}; + +// Results of the above operations +struct StatsOperationResults { + int count; + double median; + double mean; + double timeWeightedMean; + double sum; + StatsOperationResults(); // Initialize to invalid (e.g. no dives) + bool isValid() const; + double get(StatsOperation op) const; +}; + +// For median and quartiles. +struct StatsQuartiles { + double min; + double q1, q2, q3; + double max; + bool isValid() const; +}; + +struct StatsBin { + virtual ~StatsBin(); + virtual bool operator<(StatsBin &) const = 0; + virtual bool operator==(StatsBin &) const = 0; + bool operator!=(StatsBin &b) const { return !(*this == b); } +}; + +using StatsBinPtr = std::unique_ptr<StatsBin>; + +// A value and a dive +struct StatsValue { + double v; + dive *d; +}; + +// A bin and an arbitrarily associated value, e.g. a count or a list of dives. +template<typename T> +struct StatsBinValue { + StatsBinPtr bin; + T value; +}; +using StatsBinDives = StatsBinValue<std::vector<dive *>>; +using StatsBinValues = StatsBinValue<std::vector<StatsValue>>; +using StatsBinCount = StatsBinValue<int>; +using StatsBinQuartiles = StatsBinValue<StatsQuartiles>; +using StatsBinOp = StatsBinValue<StatsOperationResults>; + +struct StatsBinner { + virtual ~StatsBinner(); + virtual QString name() const; // Only needed if there are multiple binners for a variable + virtual QString unitSymbol() const; // For numeric variables - by default returns empty string + + // The binning functions have a parameter "fill_empty". If true, missing + // bins in the range will be filled with empty bins. This only works for continuous variables. + virtual std::vector<StatsBinDives> bin_dives(const std::vector<dive *> &dives, bool fill_empty) const = 0; + virtual std::vector<StatsBinCount> count_dives(const std::vector<dive *> &dives, bool fill_empty) const = 0; + + // Note: these functions will crash with an exception if passed incompatible bins! + virtual QString format(const StatsBin &bin) const = 0; + QString formatWithUnit(const StatsBin &bin) const; + virtual QString formatLowerBound(const StatsBin &bin) const; // Only for continuous variables + virtual QString formatUpperBound(const StatsBin &bin) const; // Only for continuous variables + virtual double lowerBoundToFloat(const StatsBin &bin) const; // Only for continuous variables + virtual double upperBoundToFloat(const StatsBin &bin) const; // Only for continuous variables + virtual bool preferBin(const StatsBin &bin) const; // Prefer to show this bins tick if bins are omitted. Default to true. + + // Only for continuous and numeric variables + // Note: this will crash with an exception if passed incompatible bins! + virtual std::vector<StatsBinPtr> bins_between(const StatsBin &bin1, const StatsBin &bin2) const; +}; + +// A scatter item is two values and a dive +struct StatsScatterItem { + double x, y; + dive *d; +}; + +struct StatsVariable { + enum class Type { + Discrete, + Continuous, + Numeric + }; + + virtual ~StatsVariable(); + virtual Type type() const = 0; + virtual QString name() const = 0; + virtual QString unitSymbol() const; // For numeric variables - by default returns empty string + virtual int decimals() const; // For numeric variables: numbers of decimals to display on axes. Defaults to 0. + virtual std::vector<const StatsBinner *> binners() const = 0; // Note: may depend on current locale! + virtual QString diveCategories(const dive *d) const; // Only for discrete variables + std::vector<StatsBinQuartiles> bin_quartiles(const StatsBinner &binner, const std::vector<dive *> &dives, bool fill_empty) const; + std::vector<StatsBinOp> bin_operations(const StatsBinner &binner, const std::vector<dive *> &dives, bool fill_empty) const; + std::vector<StatsBinValues> bin_values(const StatsBinner &binner, const std::vector<dive *> &dives, bool fill_empty) const; + const StatsBinner *getBinner(int idx) const; // Handles out of bounds gracefully (returns first binner) + QString nameWithUnit() const; + QString nameWithBinnerUnit(const StatsBinner &) const; + virtual std::vector<StatsOperation> supportedOperations() const; // Only for numeric variables + QStringList supportedOperationNames() const; // Only for numeric variables + StatsOperation idxToOperation(int idx) const; + static QString operationName(StatsOperation); + double mean(const std::vector<dive *> &dives) const; // Returns NaN for empty list + static StatsQuartiles quartiles(const std::vector<StatsValue> &values); // Returns invalid quartiles for empty list + StatsQuartiles quartiles(const std::vector<dive *> &dives) const; // Only for numeric variables + std::vector<StatsValue> values(const std::vector<dive *> &dives) const; // Only for numeric variables + QString valueWithUnit(const dive *d) const; // Only for numeric variables + std::vector<StatsScatterItem> scatter(const StatsVariable &t2, const std::vector<dive *> &dives) const; +private: + virtual double toFloat(const struct dive *d) const; // For numeric variables - if dive doesn't have that value, returns NaN + StatsOperationResults applyOperations(const std::vector<dive *> &dives) const; +}; + +extern const std::vector<const StatsVariable *> stats_variables; + +// Helper function for date-based variables +extern double date_to_double(int year, int month, int day); + +#endif |