summaryrefslogtreecommitdiffstats
path: root/stats
diff options
context:
space:
mode:
Diffstat (limited to 'stats')
-rw-r--r--stats/statsaxis.cpp6
-rw-r--r--stats/statsaxis.h1
-rw-r--r--stats/statsview.cpp74
-rw-r--r--stats/statsview.h23
4 files changed, 70 insertions, 34 deletions
diff --git a/stats/statsaxis.cpp b/stats/statsaxis.cpp
index 3bdb8e427..ebd41fb94 100644
--- a/stats/statsaxis.cpp
+++ b/stats/statsaxis.cpp
@@ -52,6 +52,12 @@ std::pair<double, double> StatsAxis::minMax() const
return { min, max };
}
+std::pair<double, double> StatsAxis::minMaxScreen() const
+{
+ return horizontal ? std::make_pair(zeroOnScreen, zeroOnScreen + size)
+ : std::make_pair(zeroOnScreen, zeroOnScreen - size);
+}
+
void StatsAxis::setRange(double minIn, double maxIn)
{
min = minIn;
diff --git a/stats/statsaxis.h b/stats/statsaxis.h
index 150deb087..d9fdd6b41 100644
--- a/stats/statsaxis.h
+++ b/stats/statsaxis.h
@@ -20,6 +20,7 @@ public:
virtual ~StatsAxis();
// Returns minimum and maximum of shown range, not of data points.
std::pair<double, double> minMax() const;
+ std::pair<double, double> minMaxScreen() const; // minimum and maximum in screen coordinates
double width() const; // Only supported by vertical axes. Only valid after setSize().
double height() const; // Only supported for horizontal axes. Always valid.
diff --git a/stats/statsview.cpp b/stats/statsview.cpp
index d6da093b3..f42296fc2 100644
--- a/stats/statsview.cpp
+++ b/stats/statsview.cpp
@@ -125,7 +125,9 @@ void StatsView::plotAreaChanged(const QRectF &r)
series->updatePositions();
for (QuartileMarker &marker: quartileMarkers)
marker.updatePosition();
- for (LineMarker &marker: lineMarkers)
+ for (RegressionLine &line: regressionLines)
+ line.updatePosition();
+ for (HistogramMarker &marker: histogramMarkers)
marker.updatePosition();
if (legend)
legend->resize();
@@ -211,7 +213,8 @@ void StatsView::reset()
legend.reset();
series.clear();
quartileMarkers.clear();
- lineMarkers.clear();
+ regressionLines.clear();
+ histogramMarkers.clear();
chart->removeAllSeries();
grid.reset();
axes.clear();
@@ -716,37 +719,25 @@ void StatsView::QuartileMarker::updatePosition()
x + quartileMarkerSize / 2.0, y);
}
-StatsView::LineMarker::LineMarker(QPointF from, QPointF to, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis) :
+StatsView::RegressionLine::RegressionLine(double a, double b, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis) :
item(new QGraphicsLineItem(chart)),
xAxis(xAxis), yAxis(yAxis),
- from(from), to(to)
+ a(a), b(b)
{
item->setZValue(ZValues::chartFeatures);
item->setPen(pen);
- updatePosition();
}
-void StatsView::LineMarker::updatePosition()
+void StatsView::RegressionLine::updatePosition()
{
if (!xAxis || !yAxis)
return;
- double x1 = xAxis->toScreen(from.x());
- double y1 = yAxis->toScreen(from.y());
- double x2 = xAxis->toScreen(to.x());
- double y2 = yAxis->toScreen(to.y());
- item->setLine(x1, y1, x2, y2);
-}
-
-void StatsView::addLinearRegression(double a, double b, double minX, double maxX, double minY, double maxY, StatsAxis *xAxis, StatsAxis *yAxis)
-{
- // Sanity check: line above or below chart
+ auto [minX, maxX] = xAxis->minMax();
+ auto [minY, maxY] = yAxis->minMax();
double y1 = a * minX + b;
double y2 = a * maxX + b;
- if ((y1 <= minY && y2 <= minY) || (y1 >= maxY && y2 >= maxY))
- return;
- // If not fully inside drawing region, do clipping. With the check above this guarantees that a != 0,
- // but owing to floating point imprecision, let's test again.
+ // If not fully inside drawing region, do clipping.
if ((y1 < minY || y1 > maxY || y2 < minY || y2 > maxY) && fabs(a) > 0.0001) {
// Intersections with y = minY and y = maxY lines
double intersect_x1 = (minY - b) / a;
@@ -756,14 +747,42 @@ void StatsView::addLinearRegression(double a, double b, double minX, double maxX
minX = std::max(minX, intersect_x1);
maxX = std::min(maxX, intersect_x2);
}
- lineMarkers.emplace_back(QPointF(minX, a * minX + b), QPointF(maxX, a * maxX + b), QPen(Qt::red), chart, xAxis, yAxis);
+ item->setLine(xAxis->toScreen(minX), yAxis->toScreen(a * minX + b),
+ xAxis->toScreen(maxX), yAxis->toScreen(a * maxX + b));
}
-void StatsView::addHistogramMarker(double pos, double low, double high, const QPen &pen, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis)
+StatsView::HistogramMarker::HistogramMarker(double val, bool horizontal, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis) :
+ item(new QGraphicsLineItem(chart)),
+ xAxis(xAxis), yAxis(yAxis),
+ val(val), horizontal(horizontal)
+{
+ item->setZValue(ZValues::chartFeatures);
+ item->setPen(pen);
+}
+
+void StatsView::HistogramMarker::updatePosition()
+{
+ if (!xAxis || !yAxis)
+ return;
+ if (horizontal) {
+ double y = yAxis->toScreen(val);
+ auto [x1, x2] = xAxis->minMaxScreen();
+ item->setLine(x1, y, x2, y);
+ } else {
+ double x = xAxis->toScreen(val);
+ auto [y1, y2] = yAxis->minMaxScreen();
+ item->setLine(x, y1, x, y2);
+ }
+}
+
+void StatsView::addHistogramMarker(double pos, const QPen &pen, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis)
+{
+ histogramMarkers.emplace_back(pos, isHorizontal, pen, chart, xAxis, yAxis);
+}
+
+void StatsView::addLinearRegression(double a, double b, double minX, double maxX, double minY, double maxY, StatsAxis *xAxis, StatsAxis *yAxis)
{
- QPointF from = isHorizontal ? QPointF(low, pos) : QPointF(pos, low);
- QPointF to = isHorizontal ? QPointF(high, pos) : QPointF(pos, high);
- lineMarkers.emplace_back(from, to, pen, chart, xAxis, yAxis);
+ regressionLines.emplace_back(a, b, QPen(Qt::red), chart, xAxis, yAxis);
}
// Yikes, we get our data in different kinds of (bin, value) pairs.
@@ -812,7 +831,6 @@ void StatsView::plotHistogramCountChart(const std::vector<dive *> &dives,
int total = getTotalCount(categoryBins);
StatsAxis *valAxis = createCountAxis(maxCategoryCount, isHorizontal);
- double chartHeight = valAxis->minMax().second;
if (isHorizontal)
setAxes(valAxis, catAxis);
@@ -840,14 +858,14 @@ void StatsView::plotHistogramCountChart(const std::vector<dive *> &dives,
QPen meanPen(Qt::green);
meanPen.setWidth(2);
if (!std::isnan(mean))
- addHistogramMarker(mean, 0.0, chartHeight, meanPen, isHorizontal, xAxis, yAxis);
+ addHistogramMarker(mean, meanPen, isHorizontal, xAxis, yAxis);
}
if (showMedian) {
double median = categoryVariable->quartiles(dives).q2;
QPen medianPen(Qt::red);
medianPen.setWidth(2);
if (!std::isnan(median))
- addHistogramMarker(median, 0.0, chartHeight, medianPen, isHorizontal, xAxis, yAxis);
+ addHistogramMarker(median, medianPen, isHorizontal, xAxis, yAxis);
}
}
}
diff --git a/stats/statsview.h b/stats/statsview.h
index 92dbedf03..fd8ec1e2c 100644
--- a/stats/statsview.h
+++ b/stats/statsview.h
@@ -106,17 +106,27 @@ private:
void updatePosition();
};
- // A general line marker
- struct LineMarker {
+ // A regression line
+ struct RegressionLine {
std::unique_ptr<QGraphicsLineItem> item;
StatsAxis *xAxis, *yAxis;
- QPointF from, to; // In local coordinates
+ double a, b; // y = ax + b
void updatePosition();
- LineMarker(QPointF from, QPointF to, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis);
+ RegressionLine(double a, double b, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis);
+ };
+
+ // A line marking median or mean in histograms
+ struct HistogramMarker {
+ std::unique_ptr<QGraphicsLineItem> item;
+ StatsAxis *xAxis, *yAxis;
+ double val;
+ bool horizontal;
+ void updatePosition();
+ HistogramMarker(double val, bool horizontal, QPen pen, QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis);
};
void addLinearRegression(double a, double b, double minX, double maxX, double minY, double maxY, StatsAxis *xAxis, StatsAxis *yAxis);
- void addHistogramMarker(double pos, double low, double high, const QPen &pen, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis);
+ void addHistogramMarker(double pos, const QPen &pen, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis);
StatsState state;
QtCharts::QChart *chart;
@@ -126,7 +136,8 @@ private:
std::vector<std::unique_ptr<StatsSeries>> series;
std::unique_ptr<Legend> legend;
std::vector<QuartileMarker> quartileMarkers;
- std::vector<LineMarker> lineMarkers;
+ std::vector<RegressionLine> regressionLines;
+ std::vector<HistogramMarker> histogramMarkers;
std::unique_ptr<QGraphicsSimpleTextItem> title;
StatsSeries *highlightedSeries;
StatsAxis *xAxis, *yAxis;