Upload/Download are similar to Export/Import in User Metrics config dialog.
Admin interfaces are similar to CloudDB charts for both user (edit/delete)
and curator (set curated/edit/delete).
Name and Description are initialized to the corresponding items for the metric
but both can be edited to provide different/more complete information for the
CloudDB interfase.
Fixes#3361
.. when you change colors in preferences the user chart didn't honor
the new plot marker color and the generic legend did not update the
background color.
.. lowerbound(v, value) - returns the index into v for the first
element that does not evaluate to < value.
This is a binary search modelled after std::lower_bound (and
uses it in the implementation too)
.. need to refresh the user program when it is edited by the user.
the last commit fixed a memory leak in this code but broke it.
.. should think about changing this piece of code and allowing the
userchartdata to accept a new program to process (instead of
it being set in the constructor).
.. curve(series, x|y|z|d|t) - retrieve the data from another curve so
we don't have to recompute it when working with user charts.
if the datafilter is not on a user chart it will return 0. User
needs to ensure the series are ordered correctly for this to work.
.. you can now use algebraic operators with vectors. If a vector
is shorter it is repeated to match, e.g.
a<-c(1,2); b<-c(1,2,3,4,5); d<- a * b;
is calculated as;
d<- c(1,2,1,2,1) * c(1,2,3,4,5) and will yield: 1,4,3,8,5
.. arguniq(list) - returns an index into unique values in the list. the
list does not need to be sorted, the returned list index always
refers to the first item in a list (not the later duplicates).
.. uniq(list [,list n]) - will de-dupe the first list by removing
duplicates. All remaining lists will have the same items removed
by index, in the same way as sort/argsort.
.. meanmax(efforts) - runs the filtering scheme used on the cp plot to
filter out submaximal data; a mixture of comparison to a LR, maximal
from same date considered as an averaging tail and use of power
index.
.. it returns a vector of indexes into the meanmax data for power;
so meanmax(POWER)[meanmax(efforts)] can be used, but since the
index starts at 0, need to add 1 to get seconds.
.. show x-avg on select at the top of a line chart, stops it overwriting
the min/max values. Especially relevant when using a time/date axis
hence limiting to a line chart where this is most common.
.. not neccessary to get out a build just yet, but cycling on the
build number and version string for any development builds
users download from travis or build themselves.
.. allow data labels for points on the chart, added to User, R and
Python chart addCurve() etc.
.. NOTE: opengl painting ignores this setting so should be disabled
for data series that want labels. We do not do this
automatically, but might consider that later.
.. GC.annotate(type="label", series="Power", label="CP=222") added to
the python chart to add a label to the legend for displaying things
like parameter estimates.
.. it does feel like annotations will need to be thought thru and likely
result in a GenericAnnotation class. But lets cross that bridge
when we get there.
.. Label annotations are enough to get started and are now present in
User, R and Python charts.
.. GC.annotate(type="label", series="Power", c("cp", cp))
Provide call for adding label annotations from R to
match the recent update for the user chart.
.. add annotation labels from within a datafilter, ultimately
gets shown alongside the legend in generic plot.
.. this only works from a user chart, so need to add an equivalent
API to call from Python and R.
.. bool(expr) - returns 0 or 1 for the expression passed. This allows a
logical expression to be used in a formula (which is useful when
fitting models).
e.g a*(x>1) is invalid, whilst a*bool(x>1) is not.
.. when editing programs the syntax errors were not being
shared with the user, just a wavy red line.
.. this commit adds the errors to the two main dialogs for
editing user metrics and user charts.
.. in addition a completer was added to the user chart
series editor to help (it already existed on the metric
editor).
.. lm(formula, xlist, ylist) - fits a formula to the x,y data using
the levenberg-marquardt OLS algorithm.
the formula is expressed as any other expression and the starting
values must be set beforehand- this is also reinforced by the fact
the parameters must exist before the formula is declared.
the fit returns a vector [ success, RMSE, CV).
.. an example, to fit the morton 3p model to meanmax would be:
# fetch mmp data
mmp <- meanmax(POWER);
secs <- seq(1,length(mmp),1);
# set starting values, then fit Morton 3p to first 20 min data
cp <- 200; W<-11000; pmax <- 1000;
fit <- lm((W / (x - (W/(cp-pmax)))) + cp,
head(secs,1200),
head(mmp,1200));
.. along the way I needed to refactor the way lmfit is managed and
also corrected banister to avoid threading issues.
.. also snuck in a sqrt() function as needed for testing and was
rather an egregious oversight.
.. when adding symbols to lines or lines to a scatter we
need to show/hide the decoration with the main series.
.. in addition if the decoration is the only thing visible
e.g. symbols for line (with no line style) then still
need to show the hover on the symbols.
.. honour both the symbol and line style settigns for curves. This
means you can have a series on a line chart that is dots and a
series on a scatter that is a line.
.. need to think about best way to manage hover, but suspect it should
only apply when a line chart has a series with no line but has
symbols -- we should hover on them. Currently they are ignored.
.. increasing the precedence for the [ ] symbols resolved the
reduce/reduce issue introduced in commit 1231f59b1a
.. as a result the new rule added in that commit has been
removed.
.. thanks to Ale Martinez for the correct fix.
.. smooth(list, ewma, alpha) - smooth data using an exponentially
weighted moving average. alpha must be between 0 and 1, if not
0.3 is used as a fallback.
.. part of a few updates to add some smoothing algorithms to apply
to vector data, this first one is just a simple moving average.
.. smooth(list, sma, centered|forward|backward, window) will apply
smoothing to the list. Note that centered doesn't use multiple
windows when the window size is even, so recommend always using
an odd number for this parameter.
.. will add ewma and maybe some others over the next few commits.
.. you can now configure if a series is shown on the legend, this is
for lines or curves that are there for illustration but do not
need to be displayed in the legend / hovered.
.. they are rather anachronistic. use of vectors across the datafilter
and the metrics() function replaces them.
.. as a by-product nested indexing works without a syntax error (yes
you could add a space, but most folks would be lost).
e.g. a[b[1]] works as you would expect.
.. expressions like a+b*c[n] were being parsed as equivalent to
(a+b*c)[n] instead of a+b+(c[n]).
.. to resolve this symbol[index] is declared first in the grammar
and whilst it will introduce reduce/reduce warnings that is
actually what we want (we declare it early to override the
definition from expr below).
.. keener yacc wizards might have a more elegant solution for
this one....
.. lr(xdata,ydata) - perform a linear regression returning the results
in a vector of 4 values [ slope, intercept, r2, see ].
.. as a by-product the slope on generic plots now show r2 and see as
they are being calculated by GenericCalculator.
.. need to transform values from MS since Epoch back to seconds
when doing the LR- since we convert when setting up the chart
as Qt wants time based axes to use MS since Epoch (they do not
offer any transformations for the axis).
.. this means that the slope/intercept are now calculated correctly
on charts that use time based axes.
.. whilst its possible to assign to a selection of elements in a
vector e.g. v[c(3,5,7)] <- 99 to assign 99 to el 3,5 and 7
I forgot to update the code to /return/ a vector e.g.;
a <- v[c(3,5,7)]
was not handled at all. This commit fixes that. It means we
can select from a vector element-wise -or- via a logical
expression.
.. sapply(list, expr) - as in R sapply returns a vector of the results
of expression applied to every element in list. Values for x and i
are made available in the expression.
.. v[ lexpr ] - returns a subset of vector v where logical expression
lexpr returned non-zero.
lexpr is evaluated for every element in the vector and has two
variables to work with 'x' is the current element value and 'i'
is the index into the vector (starting from 0).
.. additionally, positional vectors can be used in assign statements
but we did not go so far as to allow selections to do the same in
this commit. that might be fixed later.
.. changed the indexing operators [ ] to work solely with vectors.
so it is now possible to reference an element in a vector:
a<-c(1,2,3,4);
b<-a[1]
will assign the value 2 to variable b.
.. additionally you can assign to an element of a vector, following
on from above:
a[0]<-99;
will mean a how has 4 elements: [99, 2, 3, 4]
.. lastly you can use [] with an expression, so:
c(1,2,3,4)[2]
evaluates as value 3.
.. banister(metric1, metric2, series) - get a vector of banister
data where stress metric1 and performance metric2 are used and
fetch the series which is one of nte,pte,perf,cp or date.
E.g. to get the predicted CP curve using PowerIndex you would
use: banister(BikeScore, Power_Index, cp)
.. pmc(expr, series) work with PMC, generating it from an expression
that is evaluated for every ride (as a stress metric). Returns a
vector of the series specified e.g. pmc(BikeScore, lts)
.. support for axes that are time based, assuming the user has
supplied in seconds starting from 0 (which is true for an
activity).
.. since QT charts requires times to be in MS since Epoch
and we don't know if we need to convert from seconds
until the axis is configured the series data is updated
just before charts are created in GenericChart.
This means that anyone using generic plot directly will
need to do this conversion. For this reason all integration
across the GC codebase should be via GenericChart.
R, Python and now User charts integrate via Generic Chart
so this should not really be an issue.
.. now works on trend view (in rangemode).
.. needed to add daterange to eval in datafilter to provide context
for operations; e.g. meanmax return for activity or daterange.
.. fixed up a few bugs along the way. But now need to resolve the
x-axis in generic plot when using dates and to auto set to some
kind of sensible default.
.. the way data is prepared in a user chart has been redesigned, it now
follows a similar pattern to the user metric program where a number
of functions can be written and will be called at different points.
.. init { .. } can be called to initialise variables
relevant { .. } can be called to shortcut computation
sample { .. } is called for every ride sample
activity { .. } is called for every activity
finalise { .. } is called once iteration completes
x { .. } is called to get the series x values vector
y { .. } is called to get the series y values vector
z { .. } is called to get the series z values vector
d { .. } is called to get the series d values vector (dates)
t { .. } is called to get the series t values vector (times)
.. at present z,d and t serve no real purpose but will be used to
augment data points and be shown on the legend when hovering.
This is a planned future development.