From cf445e87bdb2c35fc20dedceebbcf59e9739fd31 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Fri, 20 Jun 2014 11:19:55 +0100 Subject: [PATCH] Metric Aggregation ::aggregateZero() method .. when aggregating metrics across rides we were being inconsistent with regards how we handled zero values; we sometimes included them and sometimes didn't. .. now added a metric method bool aggregateZero() that returns true if aggregates need to include zero values .. this has been implemented where averages are aggregated. --- src/LTMPlot.cpp | 14 +++++++++++--- src/LTMWindow.cpp | 9 +++++++-- src/RideMetric.h | 3 +++ src/SummaryMetrics.cpp | 9 ++++----- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/LTMPlot.cpp b/src/LTMPlot.cpp index 38b36f4a4..1f978f85e 100644 --- a/src/LTMPlot.cpp +++ b/src/LTMPlot.cpp @@ -2259,6 +2259,7 @@ LTMPlot::createTODCurveData(Context *context, LTMSettings *settings, MetricDetai int array = rideMetrics.getRideDate().time().hour(); int type = metricDetail.metric ? metricDetail.metric->type() : RideMetric::Average; + bool aggZero = metricDetail.metric ? metricDetail.metric->aggregateZero() : false; if (metricDetail.uunits == "Ramp" || metricDetail.uunits == tr("Ramp")) type = RideMetric::Total; @@ -2272,7 +2273,8 @@ LTMPlot::createTODCurveData(Context *context, LTMSettings *settings, MetricDetai // average should be calculated taking into account // the duration of the ride, otherwise high value but // short rides will skew the overall average - y[array] = value; //XXX average is broken + if (value || aggZero) + y[array] = value; //XXX average is broken break; } case RideMetric::Low: @@ -2297,6 +2299,9 @@ LTMPlot::createCurveData(Context *context, LTMSettings *settings, MetricDetail m x.resize(maxdays+3); // one for start from zero plus two for 0 value added at head and tail y.resize(maxdays+3); // one for start from zero plus two for 0 value added at head and tail + // do we aggregate ? + bool aggZero = metricDetail.metric ? metricDetail.metric->aggregateZero() : false; + // Get metric data, either from metricDB for RideFile metrics // or from StressCalculator for PM type metrics QList PMCdata; @@ -2371,7 +2376,10 @@ LTMPlot::createCurveData(Context *context, LTMSettings *settings, MetricDetail m y[n] = value; x[n] = currentDay - groupForDate(settings->start.date(), settings->groupBy); - secondsPerGroupBy = seconds; // reset for new group + + // only increment counter if nonzero or we aggregate zeroes + if (value || aggZero) secondsPerGroupBy = seconds; + } else { // sum totals, average averages and choose best for Peaks int type = metricDetail.metric ? metricDetail.metric->type() : RideMetric::Average; @@ -2393,7 +2401,7 @@ LTMPlot::createCurveData(Context *context, LTMSettings *settings, MetricDetail m // average should be calculated taking into account // the duration of the ride, otherwise high value but // short rides will skew the overall average - y[n] = ((y[n]*secondsPerGroupBy)+(seconds*value)) / (secondsPerGroupBy+seconds); + if (value || aggZero) y[n] = ((y[n]*secondsPerGroupBy)+(seconds*value)) / (secondsPerGroupBy+seconds); break; } case RideMetric::Low: diff --git a/src/LTMWindow.cpp b/src/LTMWindow.cpp index 0bc1dfd7f..cee4be851 100644 --- a/src/LTMWindow.cpp +++ b/src/LTMWindow.cpp @@ -945,6 +945,9 @@ LTMWindow::refreshDataTable() // ignore estimates for now XXX just to stop it crashing if (metricDetail.type == METRIC_ESTIMATE) continue; + // do we aggregate zero values ? + bool aggZero = metricDetail.metric ? metricDetail.metric->aggregateZero() : false; + QList *data = NULL; // source data (metrics, bests etc) GroupedData a; // aggregated data @@ -1025,7 +1028,9 @@ LTMWindow::refreshDataTable() a.y[n] = value; a.x[n] = currentDay - groupForDate(settings.start.date()); - secondsPerGroupBy = seconds; // reset for new group + + if (value || aggZero) secondsPerGroupBy = seconds; // reset for new group + } else { // sum totals, average averages and choose best for Peaks int type = metricDetail.metric ? metricDetail.metric->type() : RideMetric::Average; @@ -1047,7 +1052,7 @@ LTMWindow::refreshDataTable() // average should be calculated taking into account // the duration of the ride, otherwise high value but // short rides will skew the overall average - a.y[n] = ((a.y[n]*secondsPerGroupBy)+(seconds*value)) / (secondsPerGroupBy+seconds); + if (value || aggZero) a.y[n] = ((a.y[n]*secondsPerGroupBy)+(seconds*value)) / (secondsPerGroupBy+seconds); break; } case RideMetric::Low: diff --git a/src/RideMetric.h b/src/RideMetric.h index 244c3b173..64d3a8ad9 100644 --- a/src/RideMetric.h +++ b/src/RideMetric.h @@ -92,6 +92,9 @@ public: // for averages the count of items included in the average virtual double count() const { return count_; } + // when aggregating averages, should we include zeroes ? no by default + virtual bool aggregateZero() const { return false; } + // Factor to multiple value to convert from metric to imperial virtual double conversion() const { return conversion_; } // And sum for example Fahrenheit from CentigradE diff --git a/src/SummaryMetrics.cpp b/src/SummaryMetrics.cpp index f4d24555f..69fc89cb3 100644 --- a/src/SummaryMetrics.cpp +++ b/src/SummaryMetrics.cpp @@ -136,9 +136,6 @@ QString SummaryMetrics::getAggregated(Context *context, QString name, const QLis double value = rideMetrics.getForSymbol(name); double count = rideMetrics.getForSymbol("workout_time"); // for averaging - // don't include zero values - if (value == 0.0f) continue; - // check values are bounded, just in case if (isnan(value) || isinf(value)) value = 0; @@ -157,8 +154,10 @@ QString SummaryMetrics::getAggregated(Context *context, QString name, const QLis // average should be calculated taking into account // the duration of the ride, otherwise high value but // short rides will skew the overall average - rvalue += value*count; - rcount += count; + if (value || metric->aggregateZero()) { + rvalue += value*count; + rcount += count; + } break; } case RideMetric::Low: