Skip to content

Commit

Permalink
Datafilter vectors - curve()
Browse files Browse the repository at this point in the history
.. 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.
  • Loading branch information
liversedge committed Mar 25, 2020
1 parent b24869e commit bda7286
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 6 deletions.
17 changes: 13 additions & 4 deletions src/Charts/UserChart.cpp
Expand Up @@ -133,24 +133,29 @@ UserChart::setRide(RideItem *item)
chart->initialiseChart(chartinfo.title, chartinfo.type, chartinfo.animate, chartinfo.legendpos, chartinfo.stack, chartinfo.orientation); chart->initialiseChart(chartinfo.title, chartinfo.type, chartinfo.animate, chartinfo.legendpos, chartinfo.stack, chartinfo.orientation);


// now generate the series data // now generate the series data
foreach (GenericSeriesInfo series, seriesinfo) { for (int ii=0; ii<seriesinfo.count(); ii++) {

// get a reference to it as we update it
GenericSeriesInfo &series = seriesinfo[ii];


// clear old annotations for this series // clear old annotations for this series
annotations.clear(); annotations.clear();


// create program // create program
if (series.user1 == NULL) { if (series.user1 == NULL) {


series.user1 = new UserChartData(context, series.string1); series.user1 = new UserChartData(context, this, series.string1);
connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotateLabel(QStringList&)), this, SLOT(annotateLabel(QStringList&))); connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotateLabel(QStringList&)), this, SLOT(annotateLabel(QStringList&)));
} }


// cast so we can work with it // cast so we can work with it
UserChartData *ucd = static_cast<UserChartData*>(series.user1); UserChartData *ucd = static_cast<UserChartData*>(series.user1);
ucd->compute(ride, Specification(), dr); ucd->compute(ride, Specification(), dr);
series.xseries = ucd->x.vector;
series.yseries = ucd->y.vector;


// data now generated so can add curve // data now generated so can add curve
chart->addCurve(series.name, ucd->x.vector, ucd->y.vector, series.xname, series.yname, chart->addCurve(series.name, series.xseries, series.yseries, series.xname, series.yname,
series.labels, series.colors, series.labels, series.colors,
series.line, series.symbol, series.size, series.color, series.opacity, series.opengl, series.legend, series.datalabels); series.line, series.symbol, series.size, series.color, series.opacity, series.opengl, series.legend, series.datalabels);


Expand Down Expand Up @@ -287,7 +292,11 @@ UserChart::applySettings(QString x)
chartinfo.stack = obj["stack"].toBool(); chartinfo.stack = obj["stack"].toBool();
chartinfo.orientation = obj["orientation"].toInt(); chartinfo.orientation = obj["orientation"].toInt();


// array of series // array of series, but userchartdata needs to be deleted
foreach(GenericSeriesInfo series, seriesinfo)
if (series.user1 != NULL)
delete static_cast<UserChartData*>(series.user1);

seriesinfo.clear(); seriesinfo.clear();
foreach(QJsonValue it, obj["SERIES"].toArray()) { foreach(QJsonValue it, obj["SERIES"].toArray()) {


Expand Down
3 changes: 3 additions & 0 deletions src/Charts/UserChart.h
Expand Up @@ -31,6 +31,7 @@
#include "GenericChart.h" #include "GenericChart.h"
#include "GenericPlot.h" #include "GenericPlot.h"
#include "ColorButton.h" #include "ColorButton.h"
#include "DataFilter.h"


// the chart // the chart
class UserChartSettings; class UserChartSettings;
Expand All @@ -43,6 +44,8 @@ class UserChart : public GcChartWindow {
// we can rely on JSON support since we also need Qt Charts which is qt5 also // we can rely on JSON support since we also need Qt Charts which is qt5 also
Q_PROPERTY(QString settings READ settings WRITE applySettings USER true) Q_PROPERTY(QString settings READ settings WRITE applySettings USER true)


friend class ::Leaf; // data filter eval accessing our curve data

public: public:


UserChart(Context *context, bool rangemode); UserChart(Context *context, bool rangemode);
Expand Down
3 changes: 2 additions & 1 deletion src/Charts/UserChartData.cpp
Expand Up @@ -20,12 +20,13 @@
#include "UserChartData.h" #include "UserChartData.h"
#include "DataFilter.h" #include "DataFilter.h"


UserChartData::UserChartData(Context *context, QString script) : context(context), script(script) UserChartData::UserChartData(Context *context, UserChart *parent, QString script) : context(context), script(script)
{ {
// compile the program - built in a context that can close. // compile the program - built in a context that can close.
program = new DataFilter(NULL, context, script); program = new DataFilter(NULL, context, script);
root = program->root(); root = program->root();
rt = &program->rt; rt = &program->rt;
rt->chart = parent;


// lookup functions we need // lookup functions we need
finit = rt->functions.contains("init") ? rt->functions.value("init") : NULL; finit = rt->functions.contains("init") ? rt->functions.value("init") : NULL;
Expand Down
6 changes: 5 additions & 1 deletion src/Charts/UserChartData.h
Expand Up @@ -23,14 +23,15 @@
#include "DataFilter.h" #include "DataFilter.h"
#include "Specification.h" #include "Specification.h"


class UserChart;
class UserChartData : public QObject { class UserChartData : public QObject {


Q_OBJECT Q_OBJECT


public: public:


// new program // new program
UserChartData(Context *context, QString script); UserChartData(Context *context, UserChart *parent, QString script);
~UserChartData(); ~UserChartData();


// Compute from samples // Compute from samples
Expand All @@ -52,6 +53,9 @@ class UserChartData : public QObject {
// our runtime // our runtime
DataFilterRuntime *rt; DataFilterRuntime *rt;


// our owner
UserChart *parent;

}; };


#endif // _GC_UserChartData_h #endif // _GC_UserChartData_h
Expand Down
54 changes: 54 additions & 0 deletions src/Core/DataFilter.cpp
Expand Up @@ -44,6 +44,7 @@ QMutex pythonMutex;
#include "Zones.h" #include "Zones.h"
#include "PaceZones.h" #include "PaceZones.h"
#include "HrZones.h" #include "HrZones.h"
#include "UserChart.h"


#include "DataFilter_yacc.h" #include "DataFilter_yacc.h"


Expand Down Expand Up @@ -204,6 +205,10 @@ static struct {
{ "variance", 1 }, // variance(v) - calculates the variance for the elements in the vector. { "variance", 1 }, // variance(v) - calculates the variance for the elements in the vector.
{ "stddev", 1 }, // stddev(v) - calculates the standard deviation for elements in the vector. { "stddev", 1 }, // stddev(v) - calculates the standard deviation for elements in the vector.


{ "curve", 2 }, // curve(series, x|y|z|d|t) - fetch the computed values for another curve
// will need to be on a user chart, and the series will need to have already
// been computed.



// add new ones above this line // add new ones above this line
{ "", -1 } { "", -1 }
Expand Down Expand Up @@ -344,6 +349,14 @@ DataFilter::builtins()


returning << "arguniq(list)"; returning << "arguniq(list)";


} else if (i == 68) {

returning << "uniq(list [,list n])";

} else if (i == 71) {

returning << "curve(series, x|y|z|d|t)";

} else { } else {


QString function; QString function;
Expand Down Expand Up @@ -1319,6 +1332,7 @@ void Leaf::validateFilter(Context *context, DataFilterRuntime *df, Leaf *leaf)
QRegExp pmcValidSymbols("^(stress|lts|sts|sb|rr|date)$", Qt::CaseInsensitive); QRegExp pmcValidSymbols("^(stress|lts|sts|sb|rr|date)$", Qt::CaseInsensitive);
QRegExp smoothAlgos("^(sma|ewma)$", Qt::CaseInsensitive); QRegExp smoothAlgos("^(sma|ewma)$", Qt::CaseInsensitive);
QRegExp annotateTypes("^(label)$", Qt::CaseInsensitive); QRegExp annotateTypes("^(label)$", Qt::CaseInsensitive);
QRegExp curveData("^(x|y|z|d|t)$", Qt::CaseInsensitive);


if (leaf->series) { // old way of hand crafting each function in the lexer including support for literal parameter e.g. (power, 1) if (leaf->series) { // old way of hand crafting each function in the lexer including support for literal parameter e.g. (power, 1)


Expand Down Expand Up @@ -1590,6 +1604,22 @@ void Leaf::validateFilter(Context *context, DataFilterRuntime *df, Leaf *leaf)
} }
} }


} else if (leaf->function == "curve") {

// on a user chart we can access computed values
// for other series, reduces overhead etc
if (leaf->fparms.count() != 2 || leaf->fparms[0]->type != Leaf::Symbol || leaf->fparms[1]->type != Leaf::Symbol) {
leaf->inerror = true;
DataFiltererrors << QString(tr("curve(seriesname, x|y|z|d|t), need to specify series name and data."));
} else {
// check series data
QString symbol = *(leaf->fparms[1]->lvalue.n);
if (!curveData.exactMatch(symbol)) {
DataFiltererrors << QString(tr("'%1' is not a valid, x, y, z, d or t expected").arg(symbol));
leaf->inerror = true;
}
}

} else if (leaf->function == "meanmax") { } else if (leaf->function == "meanmax") {


// is the param 1 a valid data series? // is the param 1 a valid data series?
Expand Down Expand Up @@ -2083,6 +2113,7 @@ DataFilter::DataFilter(QObject *parent, Context *context) : QObject(parent), con
{ {
// let folks know who owns this rumtime for signalling // let folks know who owns this rumtime for signalling
rt.owner = this; rt.owner = this;
rt.chart = NULL;


// be sure not to enable this by accident! // be sure not to enable this by accident!
rt.isdynamic = false; rt.isdynamic = false;
Expand All @@ -2103,6 +2134,7 @@ DataFilter::DataFilter(QObject *parent, Context *context, QString formula) : QOb
{ {
// let folks know who owns this rumtime for signalling // let folks know who owns this rumtime for signalling
rt.owner = this; rt.owner = this;
rt.chart = NULL;


// be sure not to enable this by accident! // be sure not to enable this by accident!
rt.isdynamic = false; rt.isdynamic = false;
Expand Down Expand Up @@ -3016,6 +3048,28 @@ Result Leaf::eval(DataFilterRuntime *df, Leaf *leaf, float x, long it, RideItem
return Result(count); return Result(count);
} }


// access user chart curve data, if it's there
if (leaf->function == "curve") {

// not on a chart m8
if (df->chart == NULL) return Result(0);

Result returning(0);

// lets see if we can find the series
QString symbol = *(leaf->fparms[0]->lvalue.n);
for(int i=0; i<df->chart->seriesinfo.count(); i++) {
if (df->chart->seriesinfo[i].name == symbol) {
// woop!
QString data=*(leaf->fparms[1]->lvalue.n);
if (data == "x") returning.vector = df->chart->seriesinfo[i].xseries;
if (data == "y") returning.vector = df->chart->seriesinfo[i].yseries;
// z d t still todo XXX
}
}
return returning;
}

// sort // sort
if (leaf->function == "sort") { if (leaf->function == "sort") {


Expand Down
5 changes: 5 additions & 0 deletions src/Core/DataFilter.h
Expand Up @@ -112,6 +112,7 @@ class Leaf {
RideFile::XDataJoin xjoin; // how to join xdata with main RideFile::XDataJoin xjoin; // how to join xdata with main
}; };


class UserChart;
class DataFilterRuntime { class DataFilterRuntime {


// allocated for each thread to avoid race // allocated for each thread to avoid race
Expand All @@ -126,6 +127,10 @@ class DataFilterRuntime {
// needs to be reapplied as the ride selection changes // needs to be reapplied as the ride selection changes
bool isdynamic; bool isdynamic;


// the user chart if were used for that
// enables use of cache() command
UserChart *chart;

// Lookup tables // Lookup tables
QMap<QString,QString> lookupMap; QMap<QString,QString> lookupMap;
QMap<QString,bool> lookupType; // true if a number, false if a string QMap<QString,bool> lookupType; // true if a number, false if a string
Expand Down

0 comments on commit bda7286

Please sign in to comment.