diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2021-01-20 14:36:59 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2021-02-13 13:02:54 -0800 |
commit | 18a5b5b5930247ed880cfbe8f94778b4c19b0bb2 (patch) | |
tree | cdaf28e252a7e512774379e2f12e981e1f68ccb3 /stats/statsvariables.cpp | |
parent | 622e9ba373f898a0d51fc009f3615d83ffd3a7fc (diff) | |
download | subsurface-18a5b5b5930247ed880cfbe8f94778b4c19b0bb2.tar.gz |
statistics: use dive instead of count bins
If we want to make bar charts selectable (when clicking on a
bar select the dives the bar represents), then we must store
the dives behind bars. Therefore, use dive-based bins instead
of count based bins in bar charts and pie charts. This gave
some churn because every structure where a count is stored
has to be changed to store a vector of dives. Try to use
move semantics where possible to avoid duplication of dive
lists.
On a positive note, the count_dives() function of the
binners can now be removed, since it is unused.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'stats/statsvariables.cpp')
-rw-r--r-- | stats/statsvariables.cpp | 50 |
1 files changed, 6 insertions, 44 deletions
diff --git a/stats/statsvariables.cpp b/stats/statsvariables.cpp index 8b2dc9bc3..498314ae7 100644 --- a/stats/statsvariables.cpp +++ b/stats/statsvariables.cpp @@ -434,15 +434,16 @@ StatsOperationResults StatsVariable::applyOperations(const std::vector<dive *> & std::vector<StatsValue> val = values(dives); double sumTime = 0.0; - res.count = (int)val.size(); + res.dives.reserve(val.size()); res.median = quartiles(val).q2; - if (res.count <= 0) + if (val.empty()) return res; res.min = std::numeric_limits<double>::max(); res.max = std::numeric_limits<double>::lowest(); for (auto [v, d]: val) { + res.dives.push_back(d); res.sum += v; res.mean += v; sumTime += d->duration.seconds; @@ -453,19 +454,19 @@ StatsOperationResults StatsVariable::applyOperations(const std::vector<dive *> & res.max = v; } - res.mean /= res.count; + res.mean /= val.size(); res.timeWeightedMean /= sumTime; return res; } StatsOperationResults::StatsOperationResults() : - count(0), median(0.0), mean(0.0), timeWeightedMean(0.0), sum(0.0), min(0.0), max(0.0) + median(0.0), mean(0.0), timeWeightedMean(0.0), sum(0.0), min(0.0), max(0.0) { } bool StatsOperationResults::isValid() const { - return count > 0; + return !dives.empty(); } double StatsOperationResults::get(StatsOperation op) const @@ -584,7 +585,6 @@ struct SimpleBinner : public StatsBinner { public: using Type = decltype(Bin::value); std::vector<StatsBinDives> bin_dives(const std::vector<dive *> &dives, bool fill_empty) const override; - std::vector<StatsBinCount> count_dives(const std::vector<dive *> &dives, bool fill_empty) const override; const Binner &derived() const { return static_cast<const Binner &>(*this); } @@ -664,24 +664,6 @@ std::vector<StatsBinDives> SimpleBinner<Binner, Bin>::bin_dives(const std::vecto return value_vector_to_bin_vector<Bin>(*this, value_bins, fill_empty); } -template<typename Binner, typename Bin> -std::vector<StatsBinCount> SimpleBinner<Binner, Bin>::count_dives(const std::vector<dive *> &dives, bool fill_empty) const -{ - // First, collect a value / counts vector and then produce the final vector - // out of that. I wonder if that is premature optimization? - using Pair = std::pair<Type, int>; - std::vector<Pair> value_bins; - for (const dive *d: dives) { - Type value = derived().to_bin_value(d); - if (is_invalid_value(value)) - continue; - register_bin_value(value_bins, value, [](int &i){ ++i; }); - } - - // Now, turn that into our result array with allocated bin objects. - return value_vector_to_bin_vector<Bin>(*this, value_bins, fill_empty); -} - // A simple binner (see above) that works on continuous (or numeric) variables // and can return bin-ranges. The binner must implement an inc() function // that turns a bin into the next-higher bin. @@ -778,7 +760,6 @@ struct MultiBinner : public StatsBinner { public: using Type = decltype(Bin::value); std::vector<StatsBinDives> bin_dives(const std::vector<dive *> &dives, bool fill_empty) const override; - std::vector<StatsBinCount> count_dives(const std::vector<dive *> &dives, bool fill_empty) const override; const Binner &derived() const { return static_cast<const Binner &>(*this); } @@ -807,25 +788,6 @@ std::vector<StatsBinDives> MultiBinner<Binner, Bin>::bin_dives(const std::vector return value_vector_to_bin_vector<Bin>(*this, value_bins, false); } -template<typename Binner, typename Bin> -std::vector<StatsBinCount> MultiBinner<Binner, Bin>::count_dives(const std::vector<dive *> &dives, bool) const -{ - // First, collect a value / counts vector and then produce the final vector - // out of that. I wonder if that is premature optimization? - using Pair = std::pair<Type, int>; - std::vector<Pair> value_bins; - for (const dive *d: dives) { - for (const Type &s: derived().to_bin_values(d)) { - if (is_invalid_value(s)) - continue; - register_bin_value(value_bins, s, [](int &i){ ++i; }); - } - } - - // Now, turn that into our result array with allocated bin objects. - return value_vector_to_bin_vector<Bin>(*this, value_bins, false); -} - // A binner that works on string-based bins whereby each dive can // produce multiple strings (e.g. dive buddies). The binner must // feature a to_bin_values() function that produces a vector of |