151 changes: 92 additions & 59 deletions src/Charts/GenericPlot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item)
barseries=NULL;
stackbarseries=NULL;
percentbarseries=NULL;
voronoidiagram=NULL;
bottom=left=true;

mainLayout = new QVBoxLayout(this);
Expand Down Expand Up @@ -299,36 +298,6 @@ GenericPlot::setSeriesVisible(QString name, bool visible)

// annotations

// line by user
void
GenericPlot::addAnnotation(AnnotationType , QAbstractSeries*series, double value)
{
fprintf(stderr, "add annotation line: for %s at value %f\n", series->name().toStdString().c_str(), value);
fflush(stderr);
}

void
GenericPlot::addAnnotation(AnnotationType, QString string, QColor color)
{
QFont std;
std.setPointSizeF(std.pointSizeF() * scale_);
QFontMetrics fm(std);

QLabel *add = new QLabel(this);
add->setText(string);
add->setStyleSheet(QString("color: %1").arg(color.name()));
add->setFixedWidth(fm.boundingRect(string).width() + (25*dpiXFactor));
add->setAlignment(Qt::AlignCenter);
labels << add;
}

void
GenericPlot::addVoronoi(QString name, QVector<double>x, QVector<double>y)
{
vname = name;
vx = x;
vy = y;
}

void
GenericPlot::pieHover(QPieSlice *slice, bool state)
Expand Down Expand Up @@ -462,7 +431,7 @@ GenericPlot::plotAreaChanged()
bool
GenericPlot::initialiseChart(QString title, int type, bool animate, int legpos, double scale)
{
clearVoronoi();
clearAnnotations();

// if we changed the type, all series must go
if (charttype != type) {
Expand Down Expand Up @@ -547,7 +516,8 @@ GenericPlot::initialiseChart(QString title, int type, bool animate, int legpos,
bool
GenericPlot::addCurve(QString name, QVector<double> xseries, QVector<double> yseries, QVector<QString> fseries, QString xname, QString yname,
QStringList labels, QStringList colors,
int linestyle, int symbol, int size, QString color, int opacity, bool opengl, bool legend, bool datalabels, bool fill)
int linestyle, int symbol, int size, QString color, int opacity, bool opengl, bool legend, bool datalabels, bool fill,
QList<GenericAnnotationInfo> annotations)
{

// a curve can have a decoration associated with it
Expand Down Expand Up @@ -919,6 +889,18 @@ GenericPlot::addCurve(QString name, QVector<double> xseries, QVector<double> yse
break;

}

// add all the annotations via a genericseriesinfo structure, which is a bit crap since we get
// passed the individual parts from one of these, they we create one down here. Its because
// the R and Python charts don't have this and we want to isolate annotations right at the top
// in UserChart and then pass them all the way down to here
if (annotations.count()) {

// we keep a record of them, they get added in finalise (after the axes are all resolved)
annotationinfos << GenericSeriesInfo(name, xseries, yseries, fseries, xname, yname, labels, colors,
linestyle, symbol, size, color, opacity, opengl, legend, datalabels, fill, RideMetric::Average, annotations);
}

return true;
}

Expand All @@ -928,9 +910,6 @@ GenericPlot::finaliseChart()
{
if (!qchart) return;

// remove voronoix if present
clearVoronoi();

// clear ALL axes
foreach(QAbstractAxis *axis, qchart->axes(Qt::Vertical)) {
qchart->removeAxis(axis);
Expand Down Expand Up @@ -1255,11 +1234,8 @@ GenericPlot::finaliseChart()

}

// add labels after legend items
foreach(QLabel *label, labels) legend->addLabel(label);

// add voronoi if need to
plotVoronoi();
// now finally we can add annotations to the top
foreach(GenericSeriesInfo series, annotationinfos) plotAnnotations(series);

plotAreaChanged(); // make sure get updated before paint
}
Expand Down Expand Up @@ -1373,40 +1349,97 @@ GenericPlot::seriesColor(QAbstractSeries* series)
}
}

// when we plot annotations we need the curve context, so we get that as a genericseriesinfo...
void
GenericPlot::plotVoronoi()
GenericPlot::plotAnnotations(GenericSeriesInfo &seriesinfo)
{
// if there is one there already, lets remove it
clearVoronoi();

if (vx.count() < 2) return;
foreach(GenericAnnotationInfo annotation, seriesinfo.annotations) {

Voronoi v;
for(int i=0; i<vx.count(); i++) v.addSite(QPointF(vx[i],vy[i]));
v.run(QRectF());
switch(annotation.type) {

case GenericAnnotationInfo::Label:
{
QFont std;
std.setPointSizeF(std.pointSizeF() * scale_);
QFontMetrics fm(std);

QLabel *add = new QLabel(this);
QString string = annotation.labels.join(" ");
add->setText(string);
add->setStyleSheet(QString("color: %1").arg(seriesinfo.color));
add->setFixedWidth(fm.boundingRect(string).width() + (25*dpiXFactor));
add->setAlignment(Qt::AlignCenter);
legend->addLabel(add);
labels << add;
}
break;

case GenericAnnotationInfo::Voronoi:
{
if (annotation.vx.count() < 2) return;

Voronoi v;
for(int i=0; i<annotation.vx.count(); i++) {
QPointF point(annotation.vx[i],annotation.vy[i]);
v.addSite(point);
}
v.run(QRectF());
#if 0
// how many lines?
fprintf(stderr, "voronoi diagram curve '%s' has %d lines\n", vname.toStdString().c_str(),v.lines().count()); fflush(stderr);
fprintf(stderr, "voronoi diagram curve '%s' has %d lines\n", annotation.vname.toStdString().c_str(),v.lines().count()); fflush(stderr);

foreach(QLineF line, v.lines()) {
fprintf(stderr, "from %f,%f to %f,%f\n", line.p1().x(), line.p1().y(), line.p2().x(), line.p2().y());
}
#endif

// create a new diagram
voronoidiagram = new GenericLines(this->annotationController);
annotationController->addAnnotation(voronoidiagram);
voronoidiagram->setCurve(curves.value(vname,NULL));
voronoidiagram->setLines(v.lines());
// create a new diagram
GenericLines *voronoidiagram = new GenericLines(this->annotationController);
annotationController->addAnnotation(voronoidiagram);
voronoidiagram->setCurve(curves.value(seriesinfo.name,NULL));
voronoidiagram->setLines(v.lines());

annotations << voronoidiagram;
}
break;


case GenericAnnotationInfo::VLine:
case GenericAnnotationInfo::HLine:
{
StraightLine *line = new StraightLine(this->annotationController);
annotationController->addAnnotation(line);
line->setCurve(curves.value(seriesinfo.name,NULL));
line->setValue(annotation.value);
line->setText(annotation.text);
line->setOrientation(annotation.type == GenericAnnotationInfo::VLine ? Qt::Vertical : Qt::Horizontal);
line->setStyle(annotation.linestyle);

annotations << line;
}
break;
}
}
}

void
GenericPlot::clearVoronoi()
GenericPlot::clearAnnotations()
{
if (voronoidiagram) {
annotationController->removeAnnotation(voronoidiagram);
delete voronoidiagram;
voronoidiagram = NULL;
// labels are a form of annotation, but are placed in the
// legend not drawn on the plot
foreach(QLabel *label, labels) {
legend->removeLabel(label);
delete label;
}
labels.clear();

// annotations are painted onto the chart scene
// we zap all here
foreach(GenericAnnotation *annotation, annotations) {
annotationController->removeAnnotation(annotation);
delete annotation;
}
annotations.clear();
annotationinfos.clear();
}
24 changes: 10 additions & 14 deletions src/Charts/GenericPlot.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
class GenericPlot;
class GenericLegend;
class GenericSelectTool;
class GenericSeriesInfo;
class GenericAxisInfo;
class GenericAnnotationInfo;

Expand All @@ -76,6 +77,7 @@ class GenericPlot : public QWidget {
friend class GenericSelectTool;
friend class GenericAnnotationController;
friend class GenericLines;
friend class StraightLine;
friend class GenericLegend;

GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item);
Expand Down Expand Up @@ -106,12 +108,7 @@ class GenericPlot : public QWidget {
// add a curve, associating an axis
bool addCurve(QString name, QVector<double> xseries, QVector<double> yseries, QVector<QString> fseries, QString xname, QString yname,
QStringList labels, QStringList colors,
int line, int symbol, int size, QString color, int opacity, bool opengl, bool legend, bool datalabels, bool fill);

// adding annotations
void addAnnotation(AnnotationType, QAbstractSeries*, double yvalue); // LINE
void addAnnotation(AnnotationType, QString, QColor=QColor(Qt::gray)); // LABEL
void addVoronoi(QString name, QVector<double>, QVector<double>); // VORONOI
int line, int symbol, int size, QString color, int opacity, bool opengl, bool legend, bool datalabels, bool fill, QList<GenericAnnotationInfo>annotations);

// configure axis, after curves added
bool configureAxis(QString name, bool visible, int align, double min, double max,
Expand All @@ -120,13 +117,13 @@ class GenericPlot : public QWidget {
// post processing clean up / add decorations / helpers etc
void finaliseChart();

// add and remove annotations (annotations are always associated with a curve)
void clearAnnotations();
void plotAnnotations(GenericSeriesInfo &info);

// do we want to see this series?
void setSeriesVisible(QString name, bool visible);

// adding and clearing a voronoi diagram from the chart
void clearVoronoi();
void plotVoronoi();

// watching scene events and managing interaction
void seriesClicked(QAbstractSeries*series, GPointF point);
bool eventHandler(int eventsource, void *obj, QEvent *event);
Expand Down Expand Up @@ -165,11 +162,10 @@ class GenericPlot : public QWidget {
// annotations
GenericAnnotationController *annotationController;

// labels and other annotations
QList<QLabel *> labels;

QString vname;
QVector<double> vx, vy; //voronoi digram
GenericLines *voronoidiagram; // draws the lines on the chart
QList<GenericAnnotation*> annotations;
QList<GenericSeriesInfo> annotationinfos;

private:
Context *context;
Expand Down
3 changes: 2 additions & 1 deletion src/Charts/GenericSelectTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,8 @@ GenericSelectTool::released(QPointF pos)
QPointF v = host->qchart->mapToValue(pos,yseries);

// add to chart
host->addAnnotation(GenericPlot::LINE, yseries, v.y());
// not implemented yet, need to decide how they persist, will do in 3.7
// host->addAnnotation(GenericPlot::LINE, yseries, v.y());
}

return true; // don't drop through into selection logic
Expand Down
2 changes: 1 addition & 1 deletion src/Charts/PythonChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ PythonChart::setWeb(bool x)
plot, SLOT( addCurve(QString,QVector<double>,QVector<double>,QStringList,QString,QString,QStringList,QStringList,int,int,int,QString,int,bool,bool,bool,bool)));
connect(this, SIGNAL(emitAxis(QString,bool,int,double,double,int,QString,QString,bool,QStringList)),
plot, SLOT(configureAxis(QString,bool,int,double,double,int,QString,QString,bool,QStringList)));
connect(this,SIGNAL(emitAnnotation(QString,QStringList)), plot, SLOT(annotateLabel(QString,QStringList)));
//connect(this,SIGNAL(emitAnnotation(QString,QStringList)), plot, SLOT(annotateLabel(QString,QStringList))); // XXX fixme

}

Expand Down
26 changes: 5 additions & 21 deletions src/Charts/UserChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,17 +178,12 @@ UserChart::setRide(const RideItem *item)
GenericSeriesInfo &series = seriesinfo[ii];

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

// any old voronoi diagram centers
series.voronoix.clear();
series.voronoiy.clear();
series.annotations.clear();

// re-create program (may be edited)
if (series.user1 != NULL) delete static_cast<UserChartData*>(series.user1);
series.user1 = new UserChartData(context, this, series.string1, rangemode);
connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotateLabel(QStringList&)), this, SLOT(annotateLabel(QStringList&)));
connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotateVoronoi(QVector<double>,QVector<double>)), this, SLOT(annotateVoronoi(QVector<double>,QVector<double>)));
connect(static_cast<UserChartData*>(series.user1)->program, SIGNAL(annotate(GenericAnnotationInfo&)), this, SLOT(annotate(GenericAnnotationInfo&)));

// cast so we can work with it
UserChartData *ucd = static_cast<UserChartData*>(series.user1);
Expand Down Expand Up @@ -277,11 +272,7 @@ UserChart::setRide(const RideItem *item)
// data now generated so can add curve
chart->addCurve(series.name, series.xseries, series.yseries, series.fseries, series.xname, series.yname,
series.labels, series.colors, series.line, series.symbol, series.size, series.color, series.opacity,
series.opengl, series.legend, series.datalabels, series.fill);

// add series annotations
foreach(QStringList list, annotations) chart->annotateLabel(series.name, list);
chart->annotateVoronoi(series.name, series.voronoix, series.voronoiy);
series.opengl, series.legend, series.datalabels, series.fill, series.aggregateby, series.annotations);

}

Expand Down Expand Up @@ -523,22 +514,15 @@ UserChart::dateForGroup(int groupby, long group)
}

void
UserChart::annotateLabel(QStringList &list)
{
annotations << list;
}

void
UserChart::annotateVoronoi(QVector<double>x, QVector<double>y)
UserChart::annotate(GenericAnnotationInfo &annotation)
{
QObject *from = sender();

for(int i=0; i<seriesinfo.count(); i++) {
if (seriesinfo[i].user1) {
UserChartData *ucd = static_cast<UserChartData*>(seriesinfo[i].user1);
if (ucd->program == from) {
seriesinfo[i].voronoix = x;
seriesinfo[i].voronoiy = y;
seriesinfo[i].annotations << annotation;
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/Charts/UserChart.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ class UserChart : public QWidget {
void chartConfigChanged();

// catch annotations from program
void annotateLabel(QStringList&);
void annotateVoronoi(QVector<double>,QVector<double>);
void annotate(GenericAnnotationInfo&);

protected:

Expand Down
23 changes: 18 additions & 5 deletions src/Core/DataFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6100,26 +6100,39 @@ Result Leaf::eval(DataFilterRuntime *df, Leaf *leaf, const Result &x, long it, R
}

// send the signal.
if (list.count()) df->owner->annotateLabel(list);
if (list.count()) {
GenericAnnotationInfo label(GenericAnnotationInfo::Label);
label.labels = list;
df->owner->annotate(label);
}
}

if (type == "voronoi") {
Result centers = eval(df,leaf->fparms[1],x, it, m, p, c, s, d);

if (centers.isVector() && centers.isNumber && centers.asNumeric().count() >=2 && centers.asNumeric().count()%2 == 0) {
QVector<double>x, y;

GenericAnnotationInfo voronoi(GenericAnnotationInfo::Voronoi);
int n=centers.asNumeric().count()/2;
for(int i=0; i<n; i++) {
x << centers.asNumeric()[i];
y << centers.asNumeric()[i+n];
voronoi.vx << centers.asNumeric()[i];
voronoi.vy << centers.asNumeric()[i+n];
}

// send signal
df->owner->annotateVoronoi(x,y);
df->owner->annotate(voronoi);
}
}

if (type == "hline" || type == "vline") {

GenericAnnotationInfo line(type == "vline" ? GenericAnnotationInfo::VLine : GenericAnnotationInfo::HLine);
line.text = eval(df,leaf->fparms[1],x, it, m, p, c, s, d).string();
line.linestyle = linestyle(*(leaf->fparms[2]->lvalue.n));
line.value = eval(df,leaf->fparms[3],x, it, m, p, c, s, d).number();

// send signal
df->owner->annotate(line);
}

}
Expand Down
4 changes: 2 additions & 2 deletions src/Core/DataFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class Leaf {
};

class UserChart;
class GenericAnnotationInfo;
class DataFilterRuntime {

// allocated for each thread to avoid race
Expand Down Expand Up @@ -262,8 +263,7 @@ class DataFilter : public QObject
void parseBad(QStringList erorrs);
void results(QStringList);

void annotateLabel(QStringList&);
void annotateVoronoi(QVector<double>,QVector<double>);
void annotate(GenericAnnotationInfo&);

private:
void setSignature(QString &query);
Expand Down
5 changes: 3 additions & 2 deletions src/R/RTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4177,7 +4177,8 @@ RTool::addCurve(SEXP name, SEXP xseries, SEXP yseries, SEXP fseries, SEXP xname,
info.fill = LOGICAL(fill)[0];

// add to chart
rtool->chart->chart->addCurve(info.name, info.xseries, info.yseries, info.fseries, info.xname, info.yname, info.labels, info.colors, info.line, info.symbol, info.size, info.color, info.opacity, info.opengl, info.legend, info.datalabels, info.fill);
rtool->chart->chart->addCurve(info.name, info.xseries, info.yseries, info.fseries, info.xname, info.yname, info.labels, info.colors, info.line,
info.symbol, info.size, info.color, info.opacity, info.opengl, info.legend, info.datalabels, info.fill, info.aggregateby, info.annotations);

// return 0
return Rf_allocVector(INTSXP,0);
Expand Down Expand Up @@ -4273,7 +4274,7 @@ RTool::annotate(SEXP type, SEXP p1, SEXP p2, SEXP p3)
}
UNPROTECT(1);

if (list.count() > 0) rtool->chart->chart->annotateLabel(series, list);
// XXX todo fix up or deprecate ???? if (list.count() > 0) rtool->chart->chart->annotateLabel(series, list);
}

// return 0
Expand Down