statistics: clip regression line

A steep regression line would shoot out of the chart. Therefore,
clip to the y = minY and y = maxY lines.

QtGraphicsScene has its own clipping routines, but they are
very general, so let's do this trivial case by hand.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-03 18:57:43 +01:00 committed by Dirk Hohndel
parent 9beec46e22
commit bea289e314
2 changed files with 21 additions and 3 deletions

View file

@ -670,8 +670,25 @@ void StatsView::LineMarker::updatePosition()
chart->mapToPosition(to, series)));
}
void StatsView::addLinearRegression(double a, double b, double minX, double maxX, QtCharts::QAbstractSeries *series)
void StatsView::addLinearRegression(double a, double b, double minX, double maxX, double minY, double maxY, QtCharts::QAbstractSeries *series)
{
// Sanity check: line above or below chart
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 ((y1 < minY || y1 > maxY || y2 < minY || y2 > maxY) && fabs(a) > 0.0001) {
// Intersections with y = minY and y = maxY lines
double intersect_x1 = minY / a - b;
double intersect_x2 = maxY / a - b;
if (intersect_x1 < intersect_x2)
std::swap(intersect_x1, intersect_x2);
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), series);
}
@ -981,6 +998,7 @@ void StatsView::plotScatter(const std::vector<dive *> &dives, const StatsVariabl
auto [a, b] = linear_regression(points);
if (!std::isnan(a)) {
auto [minx, maxx] = axisX->minMax();
addLinearRegression(a, b, minx, maxx, series);
auto [miny, maxy] = axisY->minMax();
addLinearRegression(a, b, minx, maxx, miny, maxy, series);
}
}

View file

@ -110,7 +110,7 @@ private:
LineMarker(QPointF from, QPointF to, QPen pen, QtCharts::QAbstractSeries *series);
};
void addLinearRegression(double a, double b, double minX, double maxX, QtCharts::QAbstractSeries *series);
void addLinearRegression(double a, double b, double minX, double maxX, double minY, double maxY, QtCharts::QAbstractSeries *series);
void addHistogramMarker(double pos, double low, double high, const QPen &pen, bool isHorizontal, QtCharts::QAbstractSeries *series);
StatsState state;