mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
bbdd34d069
When calculating the quartiles, we need the count of dives anyway, which makes it trivial to export this value to the frontend. Fixes an erroneous "mean", which should be "median". Suggested-by: Peter Zaal <peter.zaal@gmail.com> Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
154 lines
5.9 KiB
C++
154 lines
5.9 KiB
C++
// 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,
|
|
Min,
|
|
Max,
|
|
Invalid
|
|
};
|
|
|
|
// Results of the above operations
|
|
struct StatsOperationResults {
|
|
int count;
|
|
double median;
|
|
double mean;
|
|
double timeWeightedMean;
|
|
double sum;
|
|
double min;
|
|
double max;
|
|
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;
|
|
int count;
|
|
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
|