For completeness as requested in the users forum:
GC.deleteXDataSeries(xdata, series) to remove existing XData series
GC.deleteXData(xdata) to remove existing XData
They invoke the corresponding RideFileCommand methods.
All activity functions working with data series,
both standard and xdata, now include an optional
compareindex=-1 parameter.
When compare mode is enabled compareindex parameter
is used as an index to get data for the corresponding
compare item, be an activity or an interval.
Sample chart contributed by Marcen at the users forum
Fixes#4346
Data Processors running on import are applied before the activity
is added to RideCache and metrics are computed, this behavior is
by design, likely to optimize resource usage on bulk import.
So activityMetrics API is not available; a new getTag API was
added for this case and setTag/delTag/hasTag changed to work
in this context too.
When the Python fix is executed on activities already in the cache
either via Edit menu, Filters or other Python Fix changes are
notified via the corresponding RideItem.
Fixes#4095
[publish binaries]
R and Python API: add GC.intervalType(type=1) function to get the
localized interval description to be used as parameter for intervals.
Formulas: return the enumerator for intervals function while intervalstrings
continue to return localized type description.
Fixes#4114
For Metadata handling in Python Data Processors, similar to set/unset/isset
in formulas, but no metric overrides for now.
- setTag(name, value[, activity])
- delTag(name[, activity])
- hasTag(name[, activity])
All return boolean success indicator and activity is optional,
defaulting to current activity.
setTag and delTag are enabled only in Python Data Processors, mark
the activiy as modified and notify metadata has changed on success.
Fixes#3639
.. Enable click through from the data points on a generic chart
when on trends view.
.. This commit includes the 'addCurve' bindings to pass the
activity filenames from R, Python and the User Chart.
.. It also includes a new DataFilter function 'filename' to
get a vector of strings that are the filenames for the
activities in the selected date range (or the filename
for the currently selected activity).
.. The second commit will include the interaction code for
GenericPlot to click-thru a selection.
.. 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.
.. 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.
.. added GenericChart which manages a collection of plots, so
you can plot multiple series stacked (like in AllPlot).
.. additionally added option to set layout vertical or
horizontal, since its useful to layout scatter plots
horizontally where time series will be largely vertical.
.. at this point the code is slightly refactored to add
GenericChart between PythonChart and GenericPlots.
.. will shortly add code to support managing multiple plots
in layouts and adapting if settings change (.e.g the
python script is edited, settings are changed).
.. updated to support different linestyles and also legend can
now be placed above, below, left or right of the chart and
orientated to list series vertically or horizontally.
.. the vertical legend is a bit ugly as nothing lines up, will
fix up separately.
Basics now in place to plot line, scatter, pie and bar
charts. This commit finishes off the final bit of part
2, adding axes control.
A new GC api, GC.setAxis(..) has been added allowing
fine grained control on the axes added automatically.
They reference axes by name, based upon the xaxis and yaxis
parameters passed to the GC.setCurve(..) function.
GC.setAxis(..) should be called /after/ the curves are
added since it will not create axes in advance.
Added Pie and Bar charts with some rudimentary axes
being created automatically.
Need to follow up with mechanism to work with axes from
within the python script, likely needs a new binding.
Updating the python chart to render via a Qt Chart in addition
to the existing web page rendering.
Five aspects are planned:
1. Add QT chart option, basic rendering of Line+Scatter (this commit)
2. Add legend and axes, support for Pie and Bar charts
3. Add interactivity / hover etc
4. Add options for annotations and markers
5. Add more advanced charts and chart objects
There is an example in the tests folder, but at this point the
chart is very basic, but the main plumbing is in place.
* Initial implementation of Python data processors
* Add RideEditor to PyFIx script editor
* Enable write-access to activity data for python fixes
* Add GC.deleteActivitySample method
* Add GC.deleteSeries method
* Check for python fix for changes before close
* Build python fixes menu dynamically
* Make python fixes first class data processors
* Add GC.postProcess method
* Check GC_WANT_PYTHON and "Enable Python" setting for python fixes
* Add GC.createXDataSeries method
* Clean up ScriptContext ctor mess
* Support editing xdata series
* PDP: Implement xdata append/remove methods
xdataNames, xdataSeries and xdata refer to low level functions
activityXdata is a wrapper to obtain XData series by name without interpolation
activity includes all XData series interpolated
When name="" it returns XData names
When name is one of the names for the activity it returns valuenames
To dinamically obtain names/series for activityXdata and activityXdataSeries
.. renaming the 3 metrics they trademarked in 2013:
TSS => BikeStress
IF => BikeIntensity
NP => IsoPower
.. this will break data filters, user formula and
R and Python charts.
.. in the next commit will add user metrics to ensure
backward compatibility.
.. allow the user to embed a python script into a datafilter.
.. this is primarily to enable the use of python when writing
user metrics.
.. the syntax is basically "%%python script %%" and it is
evaluated as an expresssion so the results can be assigned
to a variable or returned as a value.
.. additionally GC.result(double) has been added to the python
API to enable a return value to be set by the script.
.. since Python is really sensitive about white space its going
to be best practice to embed python scripts without honoring
any of the data filter spacing, for example:
{
value {
t <-
%%python
GC.result(100)
%%;
}
}
.. is likely to be a sensible way to use this.
.. also notice how the ; is needed after the expression. This
is because %%python ... %% is a numeric expression with the
same semantics as "1 + 2"
Similar to series but used to retrieve an XData series, like the R
activity.xdata counterpart, for example: GC.xdataseries("SWIM", "STROKES")
NB: I reserved xdata(name) to retrive a whole group of series by name
with its own sampling, not implemented in this commit.
A more efficient way to obtain a metric series for a large number
of activities, it can be converted to numpy array without copy:
import numpy as np
nparray = np.asarray(GC.metrics("Average_Power", True, "isRun=0 && isSwim=0")
.. instead of an opengl canvas lets start with a Web canvas.
.. we might have options to use QtCharts or OpenGL later.
.. not working - committed to save WIP.
Adding __getitem__ makes it to behave like a sequence enabling indexing
and iteration,for example:
s = GC.series(6)
print(s[0], s[-1])
for v in s: print(s)
l = list(s)
print(l.count(0))
.. start of API to work with ride data, exposing the raw
sample data via the buffer protocol python api and SIP
.. adds utility functions that will ultimately be wrapped
inside a python class/function:
GC.series(n) - return series data as a python array
GC.seriesName(n) - return string describing series data
GC.seriesLast() - returns int for last series type
GC.seriesPresent(n) - returns True if series in ride
.. example of using these functions in python to create a
dict object collecting all available data:
activity = {}
for x in range(0, GC.seriesLast()):
if (GC.seriesPresent(x)):
activity[GC.seriesName(x)] = GC.series(x)
.. simple examples, lots of generated code changes which is
not very helpful.
.. but the only files that were edited by hand are goldencheetah.sip
Bindings.h and Bindings.cpp
Basic proof of concept for CPP binding using SIP but with
our own type conversion (to avoid overhead of SIP lib/deploy).
Its far from perfect but will serve as a starting point.
.. needed to fixup type conversion in goldencheetah.sip to
convert returning QString as PyUnicode
.. needed to fixup passing context when multi-threaded
.. needed to fixup Bindings.h/cpp to offer new API
.. Using SIP thats used in PyQt et al we have a module
called `goldencheetah' which includes bindings.
Currently there is only a single method `getValue()'
that returns 1. It's to get the basic plumbing in place.
src/Python/SIP contains all the files related to the
module. The cpp files are generated by the `sip' utility
which will need to be available if you want to work on the
bindings. Run make -f Makefile.hack to regenerate the cpp
files if you edit them.
I prefer to distribute the generated files at this point
whilst development occurs. We may change that at a later
date.
.. Please note that the gcconfig.pri.in file has changed as
we now include the python include path rather than set a
macro for the include directive (See PYTHONINCLUDES in
gcconfig.pri.in)
.. lastly, to test this is working in a python chart console:
> print(GC.getValue())
1
>