Histogram Chart - Add Show Zone Limits option for Power/HR/Pace

This is part 1 of #3911, part 2 will be WBal zones and part 3 Polarized Zones.
This commit is contained in:
Alejandro Martinez
2021-07-22 21:14:45 -03:00
parent a52a07de7a
commit 59a2f3841f
5 changed files with 62 additions and 28 deletions

View File

@@ -264,6 +264,10 @@ HistogramWindow::HistogramWindow(Context *context, bool rangemode) : GcChartWind
showInCPZones->setText(tr("Use polarised zones"));
cl->addRow(blankLabel7 = new QLabel(""), showInCPZones);
showZoneLimits = new QCheckBox;
showZoneLimits->setText(tr("Show Zone limits"));
cl->addRow(blankLabel8 = new QLabel(""), showZoneLimits);
// bin width
QHBoxLayout *binWidthLayout = new QHBoxLayout;
QLabel *binWidthLabel = new QLabel(tr("Bin width"), this);
@@ -347,6 +351,8 @@ HistogramWindow::HistogramWindow(Context *context, bool rangemode) : GcChartWind
connect(showInCPZones, SIGNAL(stateChanged(int)), this, SLOT(forceReplot()));
connect(showInZones, SIGNAL(stateChanged(int)), this, SLOT(setZoned(int)));
connect(showInZones, SIGNAL(stateChanged(int)), this, SLOT(forceReplot()));
connect(showZoneLimits, SIGNAL(stateChanged(int)), this, SLOT(setZoneLimited(int)));
connect(showZoneLimits, SIGNAL(stateChanged(int)), this, SLOT(forceReplot()));
connect(shadeZones, SIGNAL(stateChanged(int)), this, SLOT(setShade(int)));
connect(shadeZones, SIGNAL(stateChanged(int)), this, SLOT(forceReplot()));
connect(showSumY, SIGNAL(currentIndexChanged(int)), this, SLOT(forceReplot()));
@@ -416,6 +422,7 @@ HistogramWindow::compareChanged()
powerHist->setShading(shadeZones->isChecked() ? true : false);
powerHist->setZoned(showInZones->isChecked() ? true : false);
powerHist->setCPZoned(showInCPZones->isChecked() ? true : false);
powerHist->setZoneLimited(showZoneLimits->isChecked() ? true : false);
powerHist->setlnY(showLnY->isChecked() ? true : false);
powerHist->setWithZeros(showZeroes->isChecked() ? true : false);
powerHist->setSumY(showSumY->currentIndex()== 0 ? true : false);
@@ -637,6 +644,7 @@ HistogramWindow::switchMode()
shadeZones->show();
showInZones->show();
showInCPZones->show();
showZoneLimits->show();
// select the series..
seriesChanged();
@@ -658,6 +666,7 @@ HistogramWindow::switchMode()
shadeZones->hide();
showInZones->hide();
showInCPZones->hide();
showZoneLimits->hide();
// show all the metric controls
blankLabel1->show();
@@ -931,6 +940,12 @@ HistogramWindow::setZoned(int x)
}
void
HistogramWindow::setZoneLimited(int x)
{
showZoneLimits->setCheckState((Qt::CheckState)x);
}
void
HistogramWindow::setShade(int x)
{
@@ -1032,6 +1047,7 @@ HistogramWindow::updateChart()
powerHist->setShading(shadeZones->isChecked() ? true : false);
powerHist->setZoned(showInZones->isChecked() ? true : false);
powerHist->setCPZoned(showInCPZones->isChecked() ? true : false);
powerHist->setZoneLimited(showZoneLimits->isChecked() ? true : false);
powerHist->setlnY(showLnY->isChecked() ? true : false);
powerHist->setWithZeros(showZeroes->isChecked() ? true : false);
powerHist->setSumY(showSumY->currentIndex()== 0 ? true : false);
@@ -1073,6 +1089,7 @@ HistogramWindow::updateChart()
powerHist->setShading(shadeZones->isChecked() ? true : false);
powerHist->setZoned(showInZones->isChecked() ? true : false);
powerHist->setCPZoned(showInCPZones->isChecked() ? true : false);
powerHist->setZoneLimited(showZoneLimits->isChecked() ? true : false);
powerHist->setlnY(showLnY->isChecked() ? true : false);
powerHist->setWithZeros(showZeroes->isChecked() ? true : false);
powerHist->setSumY(showSumY->currentIndex()== 0 ? true : false);

View File

@@ -67,6 +67,7 @@ class HistogramWindow : public GcChartWindow
Q_PROPERTY(bool shade READ shade WRITE setShade USER true)
Q_PROPERTY(bool zoned READ zoned WRITE setZoned USER true)
Q_PROPERTY(bool cpZoned READ cpZoned WRITE setCPZoned USER true)
Q_PROPERTY(bool zoneLimited READ zoneLimited WRITE setZoneLimited USER true)
Q_PROPERTY(QString filter READ filter WRITE setFilter USER true)
Q_PROPERTY(QDate fromDate READ fromDate WRITE setFromDate USER true)
Q_PROPERTY(QDate toDate READ toDate WRITE setToDate USER true)
@@ -105,6 +106,8 @@ class HistogramWindow : public GcChartWindow
void setCPZoned(bool x) { return showInCPZones->setChecked(x); }
bool zoned() const { return showInZones->isChecked(); }
void setZoned(bool x) { return showInZones->setChecked(x); }
bool zoneLimited() const { return showZoneLimits->isChecked(); }
void setZoneLimited(bool x) { return showZoneLimits->setChecked(x); }
bool isFiltered() const { if (rangemode) return (isfiltered || context->ishomefiltered || context->isfiltered);
else return false; }
QString filter() const { return searchBox->filter(); }
@@ -172,6 +175,7 @@ class HistogramWindow : public GcChartWindow
void setZoned(int);
void setCPZoned(int);
void setZoneLimited(int);
void setShade(int);
// comparing things
@@ -204,6 +208,7 @@ class HistogramWindow : public GcChartWindow
QCheckBox *shadeZones; // Shade zone background
QCheckBox *showInZones; // Plot by Zone
QCheckBox *showInCPZones; // Plot by CP domain Moderate/Heavy/Severe Zone
QCheckBox *showZoneLimits; // Show Zone limits in labels
QComboBox *seriesCombo; // Which data series to plot
// reveal controls
@@ -242,7 +247,7 @@ class HistogramWindow : public GcChartWindow
QLabel *comboLabel, *metricLabel1, *metricLabel2, *showLabel,
*blankLabel1, *blankLabel2,
*blankLabel3, *blankLabel4, *blankLabel5, *blankLabel6,
*blankLabel7, *colorLabel;
*blankLabel7, *blankLabel8, *colorLabel;
// in range mode we can also plot a distribution chart
// based upon metrics and not just data series

View File

@@ -695,7 +695,7 @@ PowerHist::recalcCompare()
}
if (zones && zone_range != -1) {
if ((series == RideFile::watts || series == RideFile::wattsKg)) {
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(zones, zone_range));
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(zones, zone_range, zoneLimited));
setAxisScale(QwtPlot::xBottom, -0.99, zones->numZones(zone_range), 1);
}
}
@@ -718,7 +718,7 @@ PowerHist::recalcCompare()
}
if (hrzones && hrzone_range != -1) {
if (series == RideFile::hr) {
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(hrzones, hrzone_range));
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(hrzones, hrzone_range, zoneLimited));
setAxisScale(QwtPlot::xBottom, -0.99, hrzones->numZones(hrzone_range), 1);
}
}
@@ -741,7 +741,7 @@ PowerHist::recalcCompare()
}
if (pacezones && pacezone_range != -1) {
if (series == RideFile::kph) {
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(pacezones, pacezone_range));
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(pacezones, pacezone_range, zoneLimited));
setAxisScale(QwtPlot::xBottom, -0.99, pacezones->numZones(pacezone_range), 1);
}
}
@@ -796,6 +796,7 @@ PowerHist::recalc(bool force)
LASTlny == lny &&
LASTzoned == zoned &&
LASTcpzoned == cpzoned &&
LASTzoneLimited == zoneLimited &&
LASTbinw == binw &&
LASTwithz == withz &&
LASTdt == dt &&
@@ -814,12 +815,14 @@ PowerHist::recalc(bool force)
LASTlny = lny;
LASTzoned = zoned;
LASTcpzoned = cpzoned;
LASTzoneLimited = zoneLimited;
LASTbinw = binw;
LASTwithz = withz;
LASTdt = dt;
LASTabsolutetime = absolutetime;
}
setParameterAxisTitle();
if (source == Ride && !rideItem) {
return;
@@ -918,7 +921,7 @@ PowerHist::recalc(bool force)
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
int zone_range = context->athlete->zones(rideItem->sport)->whichRange(rideItem->dateTime.date());
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(rideItem->sport), zone_range));
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(rideItem->sport), zone_range, zoneLimited));
if (zone_range >= 0)
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones(rideItem->sport)->numZones(zone_range), 1);
else
@@ -935,7 +938,7 @@ PowerHist::recalc(bool force)
setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw());
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones(rideItem->sport), hrRange));
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones(rideItem->sport), hrRange, zoneLimited));
if (hrRange >= 0)
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->hrZones(rideItem->sport)->numZones(hrRange), 1);
else
@@ -953,7 +956,7 @@ PowerHist::recalc(bool force)
setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw());
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(context->athlete->paceZones(rideItem->isSwim), paceRange));
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(context->athlete->paceZones(rideItem->isSwim), paceRange, zoneLimited));
if (paceRange >= 0)
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->paceZones(rideItem->isSwim)->numZones(paceRange), 1);
@@ -968,7 +971,7 @@ PowerHist::recalc(bool force)
setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw());
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones("Bike"), 0));
setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones("Bike"), 0, zoneLimited));
if (context->athlete->zones("Bike")->getRangeSize())
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones("Bike")->numZones(0), 1); // use zones from first defined range
}
@@ -980,7 +983,7 @@ PowerHist::recalc(bool force)
setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw());
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones("Bike"), 0));
setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones("Bike"), 0, zoneLimited));
if (context->athlete->hrZones("Bike")->getRangeSize())
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->hrZones("Bike")->numZones(0), 1); // use zones from first defined range
}
@@ -992,7 +995,7 @@ PowerHist::recalc(bool force)
setAxisScaleDraw(QwtPlot::xBottom, new PolarisedZoneScaleDraw());
setAxisScale(QwtPlot::xBottom, -0.99, 3, 1);
} else {
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(context->athlete->paceZones(false), 0));
setAxisScaleDraw(QwtPlot::xBottom, new PaceZoneScaleDraw(context->athlete->paceZones(false), 0, zoneLimited));
if (context->athlete->paceZones(false)->getRangeSize())
setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->paceZones(false)->numZones(0), 1); // use zones from first defined range
}
@@ -2273,6 +2276,13 @@ PowerHist::setZoned(bool value)
setComparePens();
}
void
PowerHist::setZoneLimited(bool value)
{
zoneLimited = value;
setComparePens();
}
void
PowerHist::setWithZeros(bool value)
{

View File

@@ -171,6 +171,7 @@ class PowerHist : public QwtPlot
void setWithZeros(bool value);
void setZoned(bool value);
void setCPZoned(bool value);
void setZoneLimited(bool value);
void setSumY(bool value);
void configChanged(qint32);
void setAxisTitle(int axis, QString label);
@@ -226,6 +227,7 @@ class PowerHist : public QwtPlot
bool shade;
bool zoned; // show in zones
bool cpzoned; // show in cp zones
bool zoneLimited; // show zone limits
double binw;
bool withz; // whether zeros are included in histogram
double dt; // length of sample
@@ -280,6 +282,7 @@ class PowerHist : public QwtPlot
bool LASTlny;
bool LASTzoned; // show in zones
bool LASTcpzoned; // show in zones
bool LASTzoneLimited; // show zone limits
double LASTbinw;
bool LASTwithz; // whether zeros are included in histogram
double LASTdt; // length of sample

View File

@@ -28,7 +28,7 @@
class ZoneScaleDraw: public QwtScaleDraw
{
public:
ZoneScaleDraw(const Zones *zones, int range=-1) : zones(zones) {
ZoneScaleDraw(const Zones *zones, int range=-1, bool zoneLimited=false) : zones(zones), zoneLimited(zoneLimited) {
setRange(range);
setTickLength(QwtScaleDiv::MajorTick, 3);
}
@@ -59,18 +59,17 @@ class ZoneScaleDraw: public QwtScaleDraw
virtual QwtText label(double v) const
{
if (v <0 || v > (names.count()-1) || range < 0) return QString("");
else if (!zoneLimited) return names[v];
else {
return names[v];
#if 0
if (v == names.count()-1) return QString("%1\n%2w+").arg(names[v]).arg(from[v]);
else return QString("%1\n%2-%3w").arg(names[v]).arg(from[v]).arg(to[v]);
#endif
if (v == names.count()-1) return QString("%1 (%2+ %3)").arg(names[v]).arg(from[v]).arg(RideFile::unitName(RideFile::watts, nullptr));
else return QString("%1 (%2-%3)").arg(names[v]).arg(from[v]).arg(to[v]);
}
}
private:
const Zones *zones;
int range;
bool zoneLimited;
QList<QString> names;
QList <int> from, to;
};
@@ -125,7 +124,7 @@ class WbalZoneScaleDraw: public QwtScaleDraw
class HrZoneScaleDraw: public QwtScaleDraw
{
public:
HrZoneScaleDraw(const HrZones *zones, int range=-1) : zones(zones) {
HrZoneScaleDraw(const HrZones *zones, int range=-1, bool zoneLimited=false) : zones(zones), zoneLimited(zoneLimited) {
setRange(range);
setTickLength(QwtScaleDiv::MajorTick, 3);
}
@@ -156,18 +155,17 @@ class HrZoneScaleDraw: public QwtScaleDraw
virtual QwtText label(double v) const
{
if (v < 0 || v > (names.count()-1) || range < 0) return QString("");
else if (!zoneLimited) return names[v];
else {
return names[v];
#if 0
if (v == names.count()-1) return QString("%1\n%2bpm+").arg(names[v]).arg(from[v]);
else return QString("%1\n%2-%3bpm").arg(names[v]).arg(from[v]).arg(to[v]);
#endif
if (v == names.count()-1) return QString("%1 (%2+ %3)").arg(names[v]).arg(from[v]).arg(RideFile::unitName(RideFile::hr, nullptr));
else return QString("%1 (%2-%3)").arg(names[v]).arg(from[v]).arg(to[v]);
}
}
private:
const HrZones *zones;
int range;
bool zoneLimited;
QList<QString> names;
QList <int> from, to;
@@ -176,7 +174,7 @@ class HrZoneScaleDraw: public QwtScaleDraw
class PaceZoneScaleDraw: public QwtScaleDraw
{
public:
PaceZoneScaleDraw(const PaceZones *zones, int range=-1) : zones(zones) {
PaceZoneScaleDraw(const PaceZones *zones, int range=-1, bool zoneLimited=false) : zones(zones), zoneLimited(zoneLimited) {
setRange(range);
setTickLength(QwtScaleDiv::MajorTick, 3);
}
@@ -201,26 +199,27 @@ class PaceZoneScaleDraw: public QwtScaleDraw
from.clear();
to.clear();
}
metricPace = appsettings->value(nullptr, zones->paceSetting(), GlobalContext::context()->useMetricUnits).toBool();
}
// return label
virtual QwtText label(double v) const
{
if (v < 0 || v > (names.count()-1) || range < 0) return QString("");
else if (!zoneLimited) return names[v];
else {
return names[v];
#if 0
if (v == names.count()-1) return QString("%1\n%2kph+").arg(names[v]).arg(from[v]);
else return QString("%1\n%2-%3kph").arg(names[v]).arg(from[v]).arg(to[v]);
#endif
if (v == names.count()-1) return QString("%1 (%2+ %3)").arg(names[v]).arg(zones->kphToPaceString(from[v], metricPace)).arg(zones->paceUnits(metricPace));
else return QString("%1 (%2-%3)").arg(names[v]).arg(zones->kphToPaceString(from[v], metricPace)).arg(zones->kphToPaceString(to[v], metricPace));
}
}
private:
const PaceZones *zones;
int range;
bool zoneLimited;
QList<QString> names;
QList <double> from, to;
bool metricPace;
};
#endif