From ba259fb1d66c242d9503ba9695ce55826370267e Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Tue, 19 Jan 2021 11:18:10 +0100 Subject: statistics: make confidence area and regression line opt-in This is not perfect - the polygon of the confidence area is calculated even if it is not shown. Oh well. Signed-off-by: Berthold Stoeger --- stats/regressionitem.cpp | 31 +++++++++++++++++++++++-------- stats/regressionitem.h | 2 ++ stats/statsstate.cpp | 38 +++++++++++++++++++++++++------------- stats/statsstate.h | 2 ++ stats/statsview.cpp | 5 +++++ 5 files changed, 57 insertions(+), 21 deletions(-) (limited to 'stats') diff --git a/stats/regressionitem.cpp b/stats/regressionitem.cpp index db02cf688..cd817c9eb 100644 --- a/stats/regressionitem.cpp +++ b/stats/regressionitem.cpp @@ -11,7 +11,8 @@ static const double regressionLineWidth = 2.0; RegressionItem::RegressionItem(StatsView &view, regression_data reg, StatsAxis *xAxis, StatsAxis *yAxis) : ChartPixmapItem(view, ChartZValue::ChartFeatures), - xAxis(xAxis), yAxis(yAxis), reg(reg) + xAxis(xAxis), yAxis(yAxis), reg(reg), + regression(true), confidence(true) { } @@ -19,6 +20,16 @@ RegressionItem::~RegressionItem() { } +void RegressionItem::setFeatures(bool regressionIn, bool confidenceIn) +{ + if (regressionIn == regression && confidenceIn == confidence) + return; + regression = regressionIn; + confidence = confidenceIn; + updatePosition(); +} + +// Note: this calculates the confidence area, even if it isn't shown. Might want to optimize this. void RegressionItem::updatePosition() { if (!xAxis || !yAxis) @@ -74,14 +85,18 @@ void RegressionItem::updatePosition() ChartPixmapItem::resize(QSizeF(screenMaxX - screenMinX, screenMaxY - screenMinY)); img->fill(Qt::transparent); - QColor col(regressionItemColor); - col.setAlphaF(reg.r2); - painter->setPen(Qt::NoPen); - painter->setBrush(QBrush(col)); - painter->drawPolygon(poly); + if (confidence) { + QColor col(regressionItemColor); + col.setAlphaF(reg.r2); + painter->setPen(Qt::NoPen); + painter->setBrush(QBrush(col)); + painter->drawPolygon(poly); + } - painter->setPen(QPen(regressionItemColor, regressionLineWidth)); - painter->drawLine(QPointF(linePolygon[0]), QPointF(linePolygon[1])); + if (regression) { + painter->setPen(QPen(regressionItemColor, regressionLineWidth)); + painter->drawLine(QPointF(linePolygon[0]), QPointF(linePolygon[1])); + } ChartPixmapItem::setPos(offset); } diff --git a/stats/regressionitem.h b/stats/regressionitem.h index 607317d08..24141122c 100644 --- a/stats/regressionitem.h +++ b/stats/regressionitem.h @@ -18,9 +18,11 @@ public: RegressionItem(StatsView &view, regression_data data, StatsAxis *xAxis, StatsAxis *yAxis); ~RegressionItem(); void updatePosition(); + void setFeatures(bool regression, bool confidence); private: StatsAxis *xAxis, *yAxis; regression_data reg; + bool regression, confidence; }; #endif diff --git a/stats/statsstate.cpp b/stats/statsstate.cpp index 130a0e5a8..65d5c8656 100644 --- a/stats/statsstate.cpp +++ b/stats/statsstate.cpp @@ -23,11 +23,13 @@ enum class SupportedVariable { Numeric }; -static const int ChartFeatureLabels = 1 << 0; -static const int ChartFeatureLegend = 1 << 1; -static const int ChartFeatureMedian = 1 << 2; -static const int ChartFeatureMean = 1 << 3; -static const int ChartFeatureQuartiles = 1 << 4; +static const int ChartFeatureLabels = 1 << 0; +static const int ChartFeatureLegend = 1 << 1; +static const int ChartFeatureMedian = 1 << 2; +static const int ChartFeatureMean = 1 << 3; +static const int ChartFeatureQuartiles = 1 << 4; +static const int ChartFeatureRegression = 1 << 5; +static const int ChartFeatureConfidence = 1 << 6; static const struct ChartTypeDesc { ChartType id; @@ -45,7 +47,7 @@ static const struct ChartTypeDesc { SupportedVariable::Numeric, false, false, false, { ChartSubType::Dots }, - 0 + ChartFeatureRegression | ChartFeatureConfidence }, { ChartType::HistogramCount, @@ -161,6 +163,8 @@ StatsState::StatsState() : median(false), mean(false), quartiles(true), + regression(true), + confidence(true), var1Binner(nullptr), var2Binner(nullptr), var2Operation(StatsOperation::Invalid) @@ -353,19 +357,23 @@ static StatsState::VariableList createOperationsList(const StatsVariable *var, S return res; } -static std::vector createFeaturesList(int chartFeatures, bool labels, bool legend, bool median, bool mean, bool quartiles) +static std::vector createFeaturesList(int chartFeatures, const StatsState &state) { std::vector res; if (chartFeatures & ChartFeatureLabels) - res.push_back({ StatsTranslations::tr("labels"), ChartFeatureLabels, labels }); + res.push_back({ StatsTranslations::tr("labels"), ChartFeatureLabels, state.labels }); if (chartFeatures & ChartFeatureLegend) - res.push_back({ StatsTranslations::tr("legend"), ChartFeatureLegend, legend }); + res.push_back({ StatsTranslations::tr("legend"), ChartFeatureLegend, state.legend }); if (chartFeatures & ChartFeatureMedian) - res.push_back({ StatsTranslations::tr("median"), ChartFeatureMedian, median }); + res.push_back({ StatsTranslations::tr("median"), ChartFeatureMedian, state.median }); if (chartFeatures & ChartFeatureMean) - res.push_back({ StatsTranslations::tr("mean"), ChartFeatureMean, mean }); + res.push_back({ StatsTranslations::tr("mean"), ChartFeatureMean, state.mean }); if (chartFeatures & ChartFeatureQuartiles) - res.push_back({ StatsTranslations::tr("quartiles"), ChartFeatureQuartiles, quartiles }); + res.push_back({ StatsTranslations::tr("quartiles"), ChartFeatureQuartiles, state.quartiles }); + if (chartFeatures & ChartFeatureRegression) + res.push_back({ StatsTranslations::tr("linear regression"), ChartFeatureRegression, state.regression }); + if (chartFeatures & ChartFeatureConfidence) + res.push_back({ StatsTranslations::tr("95% confidence area"), ChartFeatureConfidence, state.confidence }); return res; } @@ -381,7 +389,7 @@ StatsState::UIState StatsState::getUIState() const // Second variable can only be binned if first variable is binned. res.binners2 = createBinnerList(var2, var2Binner, var1Binner != nullptr, true); res.operations2 = createOperationsList(var2, var2Operation, var1Binner); - res.features = createFeaturesList(chartFeatures, labels, legend, median, mean, quartiles); + res.features = createFeaturesList(chartFeatures, *this); return res; } @@ -471,6 +479,10 @@ void StatsState::featureChanged(int id, bool state) mean = state; else if (id == ChartFeatureQuartiles) quartiles = state; + else if (id == ChartFeatureRegression) + regression = state; + else if (id == ChartFeatureConfidence) + confidence = state; } // Creates the new chart-type from the current chart-type and a list of possible chart types. diff --git a/stats/statsstate.h b/stats/statsstate.h index 1d8fe0b05..8fa6bb176 100644 --- a/stats/statsstate.h +++ b/stats/statsstate.h @@ -108,6 +108,8 @@ public: bool median; bool mean; bool quartiles; + bool regression; + bool confidence; const StatsBinner *var1Binner; // nullptr: undefined const StatsBinner *var2Binner; // nullptr: undefined StatsOperation var2Operation; diff --git a/stats/statsview.cpp b/stats/statsview.cpp index e5cd0f8be..714f3ee1a 100644 --- a/stats/statsview.cpp +++ b/stats/statsview.cpp @@ -460,6 +460,11 @@ void StatsView::updateFeatures() if (medianMarker) medianMarker->setVisible(state.median); + if (regressionItem) { + regressionItem->setVisible(state.regression || state.confidence); + if (state.regression || state.confidence) + regressionItem->setFeatures(state.regression, state.confidence); + } for (ChartItemPtr &marker: quartileMarkers) marker->setVisible(state.quartiles); } -- cgit v1.2.3-70-g09d2