From c0f8c2dc0bd9a95bc011a958093838252adbf312 Mon Sep 17 00:00:00 2001 From: Simeon Duwel Date: Fri, 28 Apr 2023 18:50:03 +0200 Subject: [PATCH 1/5] some basic changed --- .vscode/settings.json | 80 +++++++++++++++++++ apps/shared/plot_view_plots.h | 5 +- apps/statistics/base.de.i18n | 2 + apps/statistics/base.en.i18n | 2 + apps/statistics/base.es.i18n | 2 + apps/statistics/base.fr.i18n | 2 + apps/statistics/base.it.i18n | 2 + apps/statistics/base.nl.i18n | 2 + apps/statistics/base.pt.i18n | 2 + .../graph/histogram_parameter_controller.cpp | 53 +++++++++--- .../graph/histogram_parameter_controller.h | 5 +- apps/statistics/graph/histogram_view.cpp | 20 +++++ apps/statistics/graph/histogram_view.h | 4 +- apps/statistics/store.h | 9 +++ apps/statistics/user_preferences.h | 15 +++- 15 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..9ff2c421d3a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,80 @@ +{ + "files.associations": { + "*.inc": "cpp", + "algorithm": "cpp", + "cmath": "cpp", + "complex": "cpp", + "type_traits": "cpp", + "initializer_list": "cpp", + "utility": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "hash_map": "cpp", + "strstream": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cfenv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "source_location": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "fstream": "cpp", + "future": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "semaphore": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp" + }, + "C_Cpp.errorSquiggles": "disabled" +} \ No newline at end of file diff --git a/apps/shared/plot_view_plots.h b/apps/shared/plot_view_plots.h index fd44827b369..13ba4fce298 100644 --- a/apps/shared/plot_view_plots.h +++ b/apps/shared/plot_view_plots.h @@ -134,9 +134,10 @@ class WithHistogram { KDColor m_highlightColor; KDColor m_borderColor; }; + }; + }; -} -} +}; #endif diff --git a/apps/statistics/base.de.i18n b/apps/statistics/base.de.i18n index 2817e30ff42..e531022190d 100644 --- a/apps/statistics/base.de.i18n +++ b/apps/statistics/base.de.i18n @@ -7,6 +7,8 @@ Frequency = "Häufigkeit" RelativeFrequency = "Relative" RectangleWidth = "Klassenbreite" RectangleWidthDescription = "" +DrawCurveOnHistogram = "Zeichne die Kurve" +DrawCurveOnHistogramDescription = "zeichnet eine Kurve über das Histogramm" BarStart = "Klassengrenz" BarStartDescrition = "Erste untere Grenz" FirstQuartile = "Unteres Quartil" diff --git a/apps/statistics/base.en.i18n b/apps/statistics/base.en.i18n index c561948f8fd..92e6643ab0a 100644 --- a/apps/statistics/base.en.i18n +++ b/apps/statistics/base.en.i18n @@ -7,6 +7,8 @@ Frequency = "Frequency" RelativeFrequency = "Relative" RectangleWidth = "Bin width" RectangleWidthDescription = "" +DrawCurveOnHistogram = "Draw curve" +DrawCurveOnHistogramDescription = "Draws a curve over the histogram" BarStart = "X start" BarStartDescrition = "" FirstQuartile = "First quartile" diff --git a/apps/statistics/base.es.i18n b/apps/statistics/base.es.i18n index a5422abe7f7..eb1b21fde16 100644 --- a/apps/statistics/base.es.i18n +++ b/apps/statistics/base.es.i18n @@ -9,6 +9,8 @@ RectangleWidth = "X inicio" RectangleWidthDescription = "" BarStart = "Principio" BarStartDescrition = "" +DrawCurveOnHistogram = "Dibujar curva" +DrawCurveOnHistogramDescription = "Dibuja una curva sobre el histograma" FirstQuartile = "Primer cuartil" MedianSymbol = "Med" ThirdQuartile = "Tercer cuartil" diff --git a/apps/statistics/base.fr.i18n b/apps/statistics/base.fr.i18n index a28a8914716..784a57838f7 100644 --- a/apps/statistics/base.fr.i18n +++ b/apps/statistics/base.fr.i18n @@ -9,6 +9,8 @@ RectangleWidth = "Largeur barre" RectangleWidthDescription = "" BarStart = "X début" BarStartDescrition = "" +DrawCurveOnHistogram = "Dessiner curve" +DrawCurveOnHistogramDescription = "Dessine une curve sous l'histogramme" FirstQuartile = "Premier quartile" MedianSymbol = "Med" ThirdQuartile = "Troisième quartile" diff --git a/apps/statistics/base.it.i18n b/apps/statistics/base.it.i18n index a4a47945309..acf61655fd1 100644 --- a/apps/statistics/base.it.i18n +++ b/apps/statistics/base.it.i18n @@ -9,6 +9,8 @@ RectangleWidth = "Intervallo" RectangleWidthDescription = "" BarStart = "Inizio serie" BarStartDescrition = "" +DrawCurveOnHistogram = "Disegnare curva" +DrawCurveOnHistogramDescription = "Disegna una curva sull'istogramma" FirstQuartile = "Primo quartile" MedianSymbol = "Med" ThirdQuartile = "Terzo quartile" diff --git a/apps/statistics/base.nl.i18n b/apps/statistics/base.nl.i18n index f9158fbac0a..dce675a8f23 100644 --- a/apps/statistics/base.nl.i18n +++ b/apps/statistics/base.nl.i18n @@ -9,6 +9,8 @@ RectangleWidth = "Interval" RectangleWidthDescription = "Klassenbreedte" BarStart = "Startwaarde" BarStartDescrition = "" +DrawCurveOnHistogram = "Teken curve" +DrawCurveOnHistogramDescription = "Tekent een curve over het histogram" FirstQuartile = "Eerste kwartiel" MedianSymbol = "Med" ThirdQuartile = "Derde kwartiel" diff --git a/apps/statistics/base.pt.i18n b/apps/statistics/base.pt.i18n index 4406b038f02..eb2900e5fcc 100644 --- a/apps/statistics/base.pt.i18n +++ b/apps/statistics/base.pt.i18n @@ -9,6 +9,8 @@ RectangleWidth = "Intervalo" RectangleWidthDescription = "Largura das classes" BarStart = "X início" BarStartDescrition = "" +DrawCurveOnHistogram = "Desenhar curva" +DrawCurveOnHistogramDescription = "Desenha uma curva sobre o histograma" FirstQuartile = "Primeiro quartil" MedianSymbol = "Me" ThirdQuartile = "Terceiro quartil" diff --git a/apps/statistics/graph/histogram_parameter_controller.cpp b/apps/statistics/graph/histogram_parameter_controller.cpp index 1707ac49d2f..e073a44399e 100644 --- a/apps/statistics/graph/histogram_parameter_controller.cpp +++ b/apps/statistics/graph/histogram_parameter_controller.cpp @@ -27,7 +27,8 @@ void HistogramParameterController::viewWillAppear() { // Initialize temporary parameters to the extracted value. m_tempBarWidth = extractParameterAtIndex(0); m_tempFirstDrawnBarAbscissa = extractParameterAtIndex(1); - assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa)); + m_tempDrawCurve = extractParameterAtIndex(2); + assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve)); FloatParameterController::viewWillAppear(); } @@ -40,15 +41,15 @@ void HistogramParameterController::willDisplayCellForIndex(HighlightCell * cell, return; } MessageTableCellWithEditableTextWithMessage * myCell = static_cast(cell); - I18n::Message labels[k_numberOfCells] = {I18n::Message::RectangleWidth, I18n::Message::BarStart}; - I18n::Message sublabels[k_numberOfCells] = {I18n::Message::RectangleWidthDescription, I18n::Message::BarStartDescrition}; + I18n::Message labels[k_numberOfCells] = {I18n::Message::RectangleWidth, I18n::Message::BarStart, I18n::Message::DrawCurveOnHistogram}; + I18n::Message sublabels[k_numberOfCells] = {I18n::Message::RectangleWidthDescription, I18n::Message::BarStartDescrition, I18n::Message::DrawCurveOnHistogramDescription}; myCell->setMessage(labels[index]); myCell->setSubLabelMessage(sublabels[index]); FloatParameterController::willDisplayCellForIndex(cell, index); } bool HistogramParameterController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Back && (extractParameterAtIndex(0) != parameterAtIndex(0) || extractParameterAtIndex(1) != parameterAtIndex(1))) { + if (event == Ion::Events::Back && (extractParameterAtIndex(0) != parameterAtIndex(0) || extractParameterAtIndex(1) != parameterAtIndex(1) || extractParameterAtIndex(2) != parameterAtIndex(2))) { // Temporary values are different, open pop-up to confirm discarding values m_confirmPopUpController.presentModally(); return true; @@ -58,26 +59,47 @@ bool HistogramParameterController::handleEvent(Ion::Events::Event event) { double HistogramParameterController::extractParameterAtIndex(int index) { assert(index >= 0 && index < k_numberOfCells); - return index == 0 ? m_store->barWidth() : m_store->firstDrawnBarAbscissa(); + switch (index) + { + case 0: + return m_store->barWidth(); + case 1: + return m_store->firstDrawnBarAbscissa(); + case 2: + return m_store->drawCurveOverHistogram() ? 1.0 : 0.0; + } } double HistogramParameterController::parameterAtIndex(int index) { assert(index >= 0 && index < k_numberOfCells); - return index == 0 ? m_tempBarWidth : m_tempFirstDrawnBarAbscissa; + switch (index) + { + case 0: + return m_tempBarWidth; + case 1: + return m_tempFirstDrawnBarAbscissa; + case 2: + return m_tempDrawCurve; + } } bool HistogramParameterController::setParameterAtIndex(int parameterIndex, double value) { - assert(parameterIndex == 0 || parameterIndex == 1); + assert(parameterIndex == 0 || parameterIndex == 1 || parameterIndex == 2); const double nextBarWidth = parameterIndex == 0 ? value : m_tempBarWidth; - const double nextFirstDrawnBarAbscissa = parameterIndex == 0 ? m_tempFirstDrawnBarAbscissa : value; - if (!authorizedParameters(nextBarWidth, nextFirstDrawnBarAbscissa)) { + const double nextFirstDrawnBarAbscissa = parameterIndex == 1 ? value: m_tempFirstDrawnBarAbscissa; + const double nextDrawCurve = parameterIndex == 2 ? value: m_tempDrawCurve; + + + if (!authorizedParameters(nextBarWidth, nextFirstDrawnBarAbscissa, nextDrawCurve)) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } if (parameterIndex == 0) { m_tempBarWidth = value; - } else { + } else if (parameterIndex == 1) { m_tempFirstDrawnBarAbscissa = value; + } else if (parameterIndex == 2) { + m_tempDrawCurve = value; } return true; } @@ -89,17 +111,24 @@ HighlightCell * HistogramParameterController::reusableParameterCell(int index, i void HistogramParameterController::buttonAction() { // Update parameters values and proceed. - assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa)); + assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve)); m_store->setBarWidth(m_tempBarWidth); m_store->setFirstDrawnBarAbscissa(m_tempFirstDrawnBarAbscissa); + m_store->setDrawCurveOverHistogram(m_tempDrawCurve == 1.0); FloatParameterController::buttonAction(); } -bool HistogramParameterController::authorizedParameters(double barWidth, double firstDrawnBarAbscissa) { +bool HistogramParameterController::authorizedParameters(double barWidth, double firstDrawnBarAbscissa, double drawCurve) { if (barWidth < 0.0) { // The bar width cannot be negative return false; } + + if (drawCurve != 0.0 && drawCurve != 1.0) { + // temporary hack: this should be a boolean + return false; + } + assert(DoublePairStore::k_numberOfSeries > 0); for (int i = 0; i < DoublePairStore::k_numberOfSeries; i++) { if (!Shared::DoublePairStore::DefaultValidSeries(m_store, i)) { diff --git a/apps/statistics/graph/histogram_parameter_controller.h b/apps/statistics/graph/histogram_parameter_controller.h index b83a7f0a77d..5efecab3e29 100644 --- a/apps/statistics/graph/histogram_parameter_controller.h +++ b/apps/statistics/graph/histogram_parameter_controller.h @@ -16,7 +16,7 @@ class HistogramParameterController : public Shared::FloatParameterController #include +using namespace Poincare; using namespace Shared; namespace Statistics { @@ -41,6 +42,25 @@ void HistogramPlotPolicy::drawPlot(const Shared::AbstractPlotView * plotView, KD HistogramDrawing histogram(histogramLevels, m_store, context, highlights, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, true, color, k_selectedBarColor, borderColor); histogram.draw(plotView, ctx, rect); + + if (m_store->drawCurveOverHistogram()) { + // We want to overlay a function plot over the histogram + // this code is taken from apps/graph/graph/graph_view.cpp + + // TODO: find a way to fit a normal distribution into a Curve2DEvaluation so that the curve itself can be drawn + + double µ = m_store->normalCurveOverHistogramMu(); + double σ = m_store->normalCurveOverHistogramSigma(); + double one_on_sigma_sqrt_tau = 1.0/(σ * 2.506628274631000502415765284811); + Curve2DEvaluation normalCurve = [µ, σ, one_on_sigma_sqrt_tau](float t, void *, void *) { + double exponent = (t - µ) / σ; + double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); + return Coordinate2D(t, output); + }; + + CurveDrawing curve(Curve2D(normalCurve), context, 0.0, 10.0, 0.1, KDColorBlue, true, false); + curve.draw(plotView, ctx, rect); + } } // HistogramView diff --git a/apps/statistics/graph/histogram_view.h b/apps/statistics/graph/histogram_view.h index 61402f7fc00..da27c753874 100644 --- a/apps/statistics/graph/histogram_view.h +++ b/apps/statistics/graph/histogram_view.h @@ -4,11 +4,11 @@ #include #include "../store.h" #include - #include +#include namespace Statistics { -class HistogramPlotPolicy : public Shared::PlotPolicy::WithHistogram { +class HistogramPlotPolicy : public Shared::PlotPolicy::WithHistogram, public Shared::PlotPolicy::WithCurves { protected: constexpr static KDColor k_notSelectedHistogramColor = Escher::Palette::GrayWhite; constexpr static KDColor k_notSelectedHistogramBorderColor = Escher::Palette::GrayMiddle; diff --git a/apps/statistics/store.h b/apps/statistics/store.h index e017138a2e1..2395d33e087 100644 --- a/apps/statistics/store.h +++ b/apps/statistics/store.h @@ -46,6 +46,15 @@ friend class BoxRange; double startOfBarAtIndex(int series, int index) const; double endOfBarAtIndex(int series, int index) const; int numberOfBars(int series) const; + + // Histogram curve overlay drawing + bool drawCurveOverHistogram() const { return userPreferences()->drawCurveOverHistogram(); }; + void setDrawCurveOverHistogram(bool value) { userPreferences()->setCurveOverHistogram(value);} + double normalCurveOverHistogramMu() const { return userPreferences()->normalCurveOverHistogramMu(); }; + void setNormalCurveOverHistogramMu(double value) const { userPreferences()->setNormalCurveOverHistogramMu(value); }; + double normalCurveOverHistogramSigma() const { return userPreferences()->normalCurveOverHistogramSigma(); }; + void setNormalCurveOverHistogramSigma(double value) const { userPreferences()->setNormalCurveOverHistogramSigma(value); }; + // Box plot bool displayOutliers() const { return userPreferences()->displayOutliers(); } void setDisplayOutliers(bool displayOutliers) { userPreferences()->setDisplayOutliers(displayOutliers); } diff --git a/apps/statistics/user_preferences.h b/apps/statistics/user_preferences.h index c9d4b4c1360..18e63a74781 100644 --- a/apps/statistics/user_preferences.h +++ b/apps/statistics/user_preferences.h @@ -15,7 +15,8 @@ class UserPreferences : public Shared::DoublePairStorePreferences { m_displayCumulatedFrequencies{false, false, false}, m_barWidth(1.0), m_firstDrawnBarAbscissa(0.0), - m_displayOutliers(GlobalPreferences::sharedGlobalPreferences()->outliersStatus() == CountryPreferences::OutlierDefaultVisibility::Displayed) + m_displayOutliers(GlobalPreferences::sharedGlobalPreferences()->outliersStatus() == CountryPreferences::OutlierDefaultVisibility::Displayed), + m_curveDrawnOver(false) {} bool displayCumulatedFrequencies(int series) { return m_displayCumulatedFrequencies[series]; } @@ -30,6 +31,15 @@ class UserPreferences : public Shared::DoublePairStorePreferences { bool displayOutliers() { return m_displayOutliers; } void setDisplayOutliers(bool value) { m_displayOutliers = value; } + bool drawCurveOverHistogram() { return m_curveDrawnOver; } + void setCurveOverHistogram(bool value) { m_curveDrawnOver = value; } + + double normalCurveOverHistogramMu() { return m_curveMu; } + void setNormalCurveOverHistogramMu(double value) { m_curveMu = value; } + + double normalCurveOverHistogramSigma() { return m_curveSigma; } + void setNormalCurveOverHistogramSigma(double value) { m_curveSigma = value; } + private: // Cumulated frequencies column display bool m_displayCumulatedFrequencies[Shared::DoublePairStore::k_numberOfSeries]; @@ -37,6 +47,9 @@ class UserPreferences : public Shared::DoublePairStorePreferences { double m_barWidth; double m_firstDrawnBarAbscissa; bool m_displayOutliers; + bool m_curveDrawnOver; + double m_curveMu; + double m_curveSigma; }; } From b92342ef70dd14b68b6ce52e9fcf70c05a302cd4 Mon Sep 17 00:00:00 2001 From: Simeon Duwel Date: Sat, 29 Apr 2023 15:50:46 +0200 Subject: [PATCH 2/5] curve gets drawn --- .vscode/settings.json | 1 - apps/statistics/graph/histogram_view.cpp | 38 ++++++++++++++++++++---- apps/statistics/user_preferences.h | 4 ++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ff2c421d3a..2f680120346 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -76,5 +76,4 @@ "valarray": "cpp", "variant": "cpp" }, - "C_Cpp.errorSquiggles": "disabled" } \ No newline at end of file diff --git a/apps/statistics/graph/histogram_view.cpp b/apps/statistics/graph/histogram_view.cpp index 977975caff0..f6a69e41513 100644 --- a/apps/statistics/graph/histogram_view.cpp +++ b/apps/statistics/graph/histogram_view.cpp @@ -49,17 +49,43 @@ void HistogramPlotPolicy::drawPlot(const Shared::AbstractPlotView * plotView, KD // TODO: find a way to fit a normal distribution into a Curve2DEvaluation so that the curve itself can be drawn - double µ = m_store->normalCurveOverHistogramMu(); - double σ = m_store->normalCurveOverHistogramSigma(); - double one_on_sigma_sqrt_tau = 1.0/(σ * 2.506628274631000502415765284811); - Curve2DEvaluation normalCurve = [µ, σ, one_on_sigma_sqrt_tau](float t, void *, void *) { + + + // auto lambda = [µ, σ, one_on_sigma_sqrt_tau](float t, void * model, void *) { + // double exponent = (t - µ) / σ; + // double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); + // return Coordinate2D(t, output); + // }; + + // Curve2DEvaluation normalCurve = (lambda, nullptr); + + // CurveDrawing curve(Curve2D(normalCurve), context, 0.0, 10.0, 0.1, KDColorBlue, true, false); + // curve.setPrecisionOptions(false, nullptr, NoDiscontinuity); + // curve.draw(plotView, ctx, rect); + + constexpr float segmentLength = 2.f; + float radiusInPixel = std::max(100 / plotView->pixelWidth(), 200 / plotView->pixelHeight()); + float angleStep = segmentLength / radiusInPixel; + float parameters[] = { 200, 200, 100, 200 }; + Curve2DEvaluation arc = [](float t, void * model, void *) { + // Store* s = reinterpret_cast(model); + // assert(s); + // double µ = s->normalCurveOverHistogramMu(); + // double σ = s->normalCurveOverHistogramSigma(); + double µ = 0.0; + double σ = 1.0; + double one_on_sigma_sqrt_tau = 1.0/(σ * 2.506628274631000502415765284811); double exponent = (t - µ) / σ; double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); return Coordinate2D(t, output); }; - CurveDrawing curve(Curve2D(normalCurve), context, 0.0, 10.0, 0.1, KDColorBlue, true, false); - curve.draw(plotView, ctx, rect); + float axisMin = plotView->rangeMin(AbstractPlotView::Axis::Horizontal); + float axisMax = plotView->rangeMax(AbstractPlotView::Axis::Horizontal); + + CurveDrawing plot(Curve2D(arc, parameters), context, axisMin, axisMax, angleStep, KDColorBlack, false); + plot.setPrecisionOptions(false, nullptr, NoDiscontinuity); + plot.draw(plotView, ctx, rect); } } diff --git a/apps/statistics/user_preferences.h b/apps/statistics/user_preferences.h index 18e63a74781..b052dce5a9e 100644 --- a/apps/statistics/user_preferences.h +++ b/apps/statistics/user_preferences.h @@ -16,7 +16,9 @@ class UserPreferences : public Shared::DoublePairStorePreferences { m_barWidth(1.0), m_firstDrawnBarAbscissa(0.0), m_displayOutliers(GlobalPreferences::sharedGlobalPreferences()->outliersStatus() == CountryPreferences::OutlierDefaultVisibility::Displayed), - m_curveDrawnOver(false) + m_curveDrawnOver(false), + m_curveMu(3.0), + m_curveSigma(1.0) {} bool displayCumulatedFrequencies(int series) { return m_displayCumulatedFrequencies[series]; } From 894c43b723ae456956c862020308f3bc8fc8d9dd Mon Sep 17 00:00:00 2001 From: Simeon Duwel Date: Sun, 30 Apr 2023 00:23:33 +0200 Subject: [PATCH 3/5] Curve gets drawn properly. TODO: make UI pretty, scale curve according to data (absolute height vs relative height) --- apps/statistics/base.de.i18n | 6 +- apps/statistics/base.en.i18n | 6 +- apps/statistics/base.es.i18n | 6 +- apps/statistics/base.fr.i18n | 6 +- apps/statistics/base.it.i18n | 6 +- apps/statistics/base.nl.i18n | 6 +- apps/statistics/base.pt.i18n | 6 +- .../graph/histogram_parameter_controller.cpp | 58 ++++++++++++++++--- .../graph/histogram_parameter_controller.h | 6 +- apps/statistics/graph/histogram_view.cpp | 18 +++--- 10 files changed, 97 insertions(+), 27 deletions(-) diff --git a/apps/statistics/base.de.i18n b/apps/statistics/base.de.i18n index e531022190d..f6eac998769 100644 --- a/apps/statistics/base.de.i18n +++ b/apps/statistics/base.de.i18n @@ -9,8 +9,12 @@ RectangleWidth = "Klassenbreite" RectangleWidthDescription = "" DrawCurveOnHistogram = "Zeichne die Kurve" DrawCurveOnHistogramDescription = "zeichnet eine Kurve über das Histogramm" +CurveMu = "Mittelwert der Normalvert." +CurveMuDescription = "Mu-Wert für die Gauss-Kurve" +CurveSigma = "Std.abweich. der Normalvert." +CurveSigmaDescription = "Sigma-Wert für die Gauss-Kurve" BarStart = "Klassengrenz" -BarStartDescrition = "Erste untere Grenz" +BarStartDescription = "Erste untere Grenz" FirstQuartile = "Unteres Quartil" MedianSymbol = "Med" ThirdQuartile = "Oberes Quartil" diff --git a/apps/statistics/base.en.i18n b/apps/statistics/base.en.i18n index 92e6643ab0a..63e9bc97677 100644 --- a/apps/statistics/base.en.i18n +++ b/apps/statistics/base.en.i18n @@ -9,8 +9,12 @@ RectangleWidth = "Bin width" RectangleWidthDescription = "" DrawCurveOnHistogram = "Draw curve" DrawCurveOnHistogramDescription = "Draws a curve over the histogram" +CurveMu = "Normal distr. mean" +CurveMuDescription = "Mu value for the normal distribution" +CurveSigma = "Normal distr. std. dev." +CurveSigmaDescription = "Sigma value for the normal distribution" BarStart = "X start" -BarStartDescrition = "" +BarStartDescription = "" FirstQuartile = "First quartile" MedianSymbol = "Med" ThirdQuartile = "Third quartile" diff --git a/apps/statistics/base.es.i18n b/apps/statistics/base.es.i18n index eb1b21fde16..77d8947b545 100644 --- a/apps/statistics/base.es.i18n +++ b/apps/statistics/base.es.i18n @@ -8,9 +8,13 @@ RelativeFrequency = "Relativa" RectangleWidth = "X inicio" RectangleWidthDescription = "" BarStart = "Principio" -BarStartDescrition = "" +BarStartDescription = "" DrawCurveOnHistogram = "Dibujar curva" DrawCurveOnHistogramDescription = "Dibuja una curva sobre el histograma" +CurveMu = "Media de la distr. normal" +CurveMuDescription = "Valor mu de la curva de gauss" +CurveSigma = "Desv. est. de la distr. normal" +CurveSigmaDescription = "Valor sigma de la curva de gauss" FirstQuartile = "Primer cuartil" MedianSymbol = "Med" ThirdQuartile = "Tercer cuartil" diff --git a/apps/statistics/base.fr.i18n b/apps/statistics/base.fr.i18n index 784a57838f7..15296499263 100644 --- a/apps/statistics/base.fr.i18n +++ b/apps/statistics/base.fr.i18n @@ -8,7 +8,11 @@ RelativeFrequency = "Fréquence" RectangleWidth = "Largeur barre" RectangleWidthDescription = "" BarStart = "X début" -BarStartDescrition = "" +BarStartDescription = "" +CurveMu = "Moyenne de la distr. normale" +CurveMuDescription = "Valeur mu pour la courbe de Gauss" +CurveSigma = "Écart-type de la distr. normale" +CurveSigmaDescription = "Valeur sigma pour la courbe de Gauss" DrawCurveOnHistogram = "Dessiner curve" DrawCurveOnHistogramDescription = "Dessine une curve sous l'histogramme" FirstQuartile = "Premier quartile" diff --git a/apps/statistics/base.it.i18n b/apps/statistics/base.it.i18n index acf61655fd1..f8459a23c48 100644 --- a/apps/statistics/base.it.i18n +++ b/apps/statistics/base.it.i18n @@ -8,7 +8,11 @@ RelativeFrequency = "Relativa" RectangleWidth = "Intervallo" RectangleWidthDescription = "" BarStart = "Inizio serie" -BarStartDescrition = "" +BarStartDescription = "" +CurveMu = "Media per la distr. norm." +CurveMuDescription = "Valore mu per la curva di Gauss" +CurveSigma = "Deviaz. std. per la distr. norm." +CurveSigmaDescription = "Valore sigma per la curva di Gauss" DrawCurveOnHistogram = "Disegnare curva" DrawCurveOnHistogramDescription = "Disegna una curva sull'istogramma" FirstQuartile = "Primo quartile" diff --git a/apps/statistics/base.nl.i18n b/apps/statistics/base.nl.i18n index dce675a8f23..f3f7ddcd123 100644 --- a/apps/statistics/base.nl.i18n +++ b/apps/statistics/base.nl.i18n @@ -8,7 +8,11 @@ RelativeFrequency = "Relatieve" RectangleWidth = "Interval" RectangleWidthDescription = "Klassenbreedte" BarStart = "Startwaarde" -BarStartDescrition = "" +BarStartDescription = "" +CurveMu = "Gemiddelde voor de norm. verd." +CurveMuDescription = "Mu-waarde voor de Gausskromme" +CurveSigma = "Stand.afw. voor de norm. verd." +CurveSigmaDescription = "Sigma-waarde voor de Gausskromme" DrawCurveOnHistogram = "Teken curve" DrawCurveOnHistogramDescription = "Tekent een curve over het histogram" FirstQuartile = "Eerste kwartiel" diff --git a/apps/statistics/base.pt.i18n b/apps/statistics/base.pt.i18n index eb2900e5fcc..fc5ee69fbb5 100644 --- a/apps/statistics/base.pt.i18n +++ b/apps/statistics/base.pt.i18n @@ -8,7 +8,11 @@ RelativeFrequency = "Relativa" RectangleWidth = "Intervalo" RectangleWidthDescription = "Largura das classes" BarStart = "X início" -BarStartDescrition = "" +BarStartDescription = "" +CurveMu = "Média distribuição normal" +CurveMuDescription = "Valor mu para a curva de Gauss" +CurveSigma = "Desvio padrão distr. normal" +CurveSigmaDescription = "Valor sigma para a curva de Gauss" DrawCurveOnHistogram = "Desenhar curva" DrawCurveOnHistogramDescription = "Desenha uma curva sobre o histograma" FirstQuartile = "Primeiro quartil" diff --git a/apps/statistics/graph/histogram_parameter_controller.cpp b/apps/statistics/graph/histogram_parameter_controller.cpp index e073a44399e..f675d9f9e20 100644 --- a/apps/statistics/graph/histogram_parameter_controller.cpp +++ b/apps/statistics/graph/histogram_parameter_controller.cpp @@ -28,7 +28,9 @@ void HistogramParameterController::viewWillAppear() { m_tempBarWidth = extractParameterAtIndex(0); m_tempFirstDrawnBarAbscissa = extractParameterAtIndex(1); m_tempDrawCurve = extractParameterAtIndex(2); - assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve)); + m_tempCurveMu = extractParameterAtIndex(3); + m_tempCurveSigma = extractParameterAtIndex(4); + assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve, m_tempCurveMu, m_tempCurveSigma)); FloatParameterController::viewWillAppear(); } @@ -41,15 +43,36 @@ void HistogramParameterController::willDisplayCellForIndex(HighlightCell * cell, return; } MessageTableCellWithEditableTextWithMessage * myCell = static_cast(cell); - I18n::Message labels[k_numberOfCells] = {I18n::Message::RectangleWidth, I18n::Message::BarStart, I18n::Message::DrawCurveOnHistogram}; - I18n::Message sublabels[k_numberOfCells] = {I18n::Message::RectangleWidthDescription, I18n::Message::BarStartDescrition, I18n::Message::DrawCurveOnHistogramDescription}; + I18n::Message labels[k_numberOfCells] = { + I18n::Message::RectangleWidth, + I18n::Message::BarStart, + I18n::Message::DrawCurveOnHistogram, + I18n::Message::CurveMu, + I18n::Message::CurveSigma, + }; + I18n::Message sublabels[k_numberOfCells] = { + I18n::Message::RectangleWidthDescription, + I18n::Message::BarStartDescription, + I18n::Message::DrawCurveOnHistogramDescription, + I18n::Message::CurveMuDescription, + I18n::Message::CurveSigmaDescription, + }; myCell->setMessage(labels[index]); myCell->setSubLabelMessage(sublabels[index]); FloatParameterController::willDisplayCellForIndex(cell, index); } bool HistogramParameterController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Back && (extractParameterAtIndex(0) != parameterAtIndex(0) || extractParameterAtIndex(1) != parameterAtIndex(1) || extractParameterAtIndex(2) != parameterAtIndex(2))) { + bool all_parameters_match = true; + + for (int i = 0; i < k_numberOfCells; i++) { + if (extractParameterAtIndex(i) != parameterAtIndex(i)) { + all_parameters_match = false; + break; + }; + } + + if (event == Ion::Events::Back && all_parameters_match) { // Temporary values are different, open pop-up to confirm discarding values m_confirmPopUpController.presentModally(); return true; @@ -67,6 +90,10 @@ double HistogramParameterController::extractParameterAtIndex(int index) { return m_store->firstDrawnBarAbscissa(); case 2: return m_store->drawCurveOverHistogram() ? 1.0 : 0.0; + case 3: + return m_store->normalCurveOverHistogramMu(); + case 4: + return m_store->normalCurveOverHistogramSigma(); } } @@ -80,6 +107,10 @@ double HistogramParameterController::parameterAtIndex(int index) { return m_tempFirstDrawnBarAbscissa; case 2: return m_tempDrawCurve; + case 3: + return m_tempCurveMu; + case 4: + return m_tempCurveSigma; } } @@ -88,9 +119,11 @@ bool HistogramParameterController::setParameterAtIndex(int parameterIndex, doubl const double nextBarWidth = parameterIndex == 0 ? value : m_tempBarWidth; const double nextFirstDrawnBarAbscissa = parameterIndex == 1 ? value: m_tempFirstDrawnBarAbscissa; const double nextDrawCurve = parameterIndex == 2 ? value: m_tempDrawCurve; + const double nextCurveMu = parameterIndex == 3 ? value: m_tempCurveMu; + const double nextCurveSigma = parameterIndex == 4 ? value: m_tempCurveSigma; - if (!authorizedParameters(nextBarWidth, nextFirstDrawnBarAbscissa, nextDrawCurve)) { + if (!authorizedParameters(nextBarWidth, nextFirstDrawnBarAbscissa, nextDrawCurve, nextCurveMu, nextCurveSigma)) { Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue); return false; } @@ -100,6 +133,10 @@ bool HistogramParameterController::setParameterAtIndex(int parameterIndex, doubl m_tempFirstDrawnBarAbscissa = value; } else if (parameterIndex == 2) { m_tempDrawCurve = value; + } else if (parameterIndex == 3) { + m_tempCurveMu = value; + } else if (parameterIndex == 4) { + m_tempCurveSigma = value; } return true; } @@ -111,19 +148,26 @@ HighlightCell * HistogramParameterController::reusableParameterCell(int index, i void HistogramParameterController::buttonAction() { // Update parameters values and proceed. - assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve)); + assert(authorizedParameters(m_tempBarWidth, m_tempFirstDrawnBarAbscissa, m_tempDrawCurve, m_tempCurveMu, m_tempCurveSigma)); m_store->setBarWidth(m_tempBarWidth); m_store->setFirstDrawnBarAbscissa(m_tempFirstDrawnBarAbscissa); m_store->setDrawCurveOverHistogram(m_tempDrawCurve == 1.0); + m_store->setNormalCurveOverHistogramMu(m_tempCurveMu); + m_store->setNormalCurveOverHistogramSigma(m_tempCurveSigma); FloatParameterController::buttonAction(); } -bool HistogramParameterController::authorizedParameters(double barWidth, double firstDrawnBarAbscissa, double drawCurve) { +bool HistogramParameterController::authorizedParameters(double barWidth, double firstDrawnBarAbscissa, double drawCurve, double curveMu, double curveSigma) { if (barWidth < 0.0) { // The bar width cannot be negative return false; } + if (curveSigma <= 0.0) { + // standard deviation has to be positive + return false; + } + if (drawCurve != 0.0 && drawCurve != 1.0) { // temporary hack: this should be a boolean return false; diff --git a/apps/statistics/graph/histogram_parameter_controller.h b/apps/statistics/graph/histogram_parameter_controller.h index 5efecab3e29..74b63992ed1 100644 --- a/apps/statistics/graph/histogram_parameter_controller.h +++ b/apps/statistics/graph/histogram_parameter_controller.h @@ -16,7 +16,7 @@ class HistogramParameterController : public Shared::FloatParameterControllerpixelWidth(), 200 / plotView->pixelHeight()); - float angleStep = segmentLength / radiusInPixel; - float parameters[] = { 200, 200, 100, 200 }; - Curve2DEvaluation arc = [](float t, void * model, void *) { - // Store* s = reinterpret_cast(model); + Curve2DEvaluation gauss = [](float t, void * model, void *) { + Store* s = reinterpret_cast(model); // assert(s); - // double µ = s->normalCurveOverHistogramMu(); - // double σ = s->normalCurveOverHistogramSigma(); - double µ = 0.0; - double σ = 1.0; + double µ = s->normalCurveOverHistogramMu(); + double σ = s->normalCurveOverHistogramSigma(); + // double µ = 0.0; + // double σ = 1.0; double one_on_sigma_sqrt_tau = 1.0/(σ * 2.506628274631000502415765284811); double exponent = (t - µ) / σ; double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); @@ -83,7 +79,7 @@ void HistogramPlotPolicy::drawPlot(const Shared::AbstractPlotView * plotView, KD float axisMin = plotView->rangeMin(AbstractPlotView::Axis::Horizontal); float axisMax = plotView->rangeMax(AbstractPlotView::Axis::Horizontal); - CurveDrawing plot(Curve2D(arc, parameters), context, axisMin, axisMax, angleStep, KDColorBlack, false); + CurveDrawing plot(Curve2D(gauss, m_store), context, axisMin, axisMax, 0.01, KDColorBlack, false); plot.setPrecisionOptions(false, nullptr, NoDiscontinuity); plot.draw(plotView, ctx, rect); } From da4a7356c911a531d1888ede0794c63cce93fc8c Mon Sep 17 00:00:00 2001 From: Simeon Duwel Date: Mon, 1 May 2023 10:02:38 +0200 Subject: [PATCH 4/5] Removed unneccessary comments --- apps/statistics/graph/histogram_view.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/apps/statistics/graph/histogram_view.cpp b/apps/statistics/graph/histogram_view.cpp index db1b8538fc6..c3f39ac8f63 100644 --- a/apps/statistics/graph/histogram_view.cpp +++ b/apps/statistics/graph/histogram_view.cpp @@ -45,23 +45,6 @@ void HistogramPlotPolicy::drawPlot(const Shared::AbstractPlotView * plotView, KD if (m_store->drawCurveOverHistogram()) { // We want to overlay a function plot over the histogram - // this code is taken from apps/graph/graph/graph_view.cpp - - // TODO: find a way to fit a normal distribution into a Curve2DEvaluation so that the curve itself can be drawn - - - - // auto lambda = [µ, σ, one_on_sigma_sqrt_tau](float t, void * model, void *) { - // double exponent = (t - µ) / σ; - // double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); - // return Coordinate2D(t, output); - // }; - - // Curve2DEvaluation normalCurve = (lambda, nullptr); - - // CurveDrawing curve(Curve2D(normalCurve), context, 0.0, 10.0, 0.1, KDColorBlue, true, false); - // curve.setPrecisionOptions(false, nullptr, NoDiscontinuity); - // curve.draw(plotView, ctx, rect); Curve2DEvaluation gauss = [](float t, void * model, void *) { Store* s = reinterpret_cast(model); From 0e87efeb1dbc6c6c4a3faa925667700a4d7ce45d Mon Sep 17 00:00:00 2001 From: Simeon Duwel Date: Mon, 1 May 2023 12:29:18 +0200 Subject: [PATCH 5/5] Added proper rescaling of the curve (this has the added bonus of being a bit more efficient) --- apps/statistics/graph/histogram_view.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/statistics/graph/histogram_view.cpp b/apps/statistics/graph/histogram_view.cpp index c3f39ac8f63..185b451d1a0 100644 --- a/apps/statistics/graph/histogram_view.cpp +++ b/apps/statistics/graph/histogram_view.cpp @@ -45,18 +45,21 @@ void HistogramPlotPolicy::drawPlot(const Shared::AbstractPlotView * plotView, KD if (m_store->drawCurveOverHistogram()) { // We want to overlay a function plot over the histogram - Curve2DEvaluation gauss = [](float t, void * model, void *) { Store* s = reinterpret_cast(model); - // assert(s); + + double µ = s->normalCurveOverHistogramMu(); double σ = s->normalCurveOverHistogramSigma(); - // double µ = 0.0; - // double σ = 1.0; - double one_on_sigma_sqrt_tau = 1.0/(σ * 2.506628274631000502415765284811); + double exponent = (t - µ) / σ; - double output = one_on_sigma_sqrt_tau * std::exp(exponent * exponent * -0.5); - return Coordinate2D(t, output); + double gauss = std::exp(exponent * exponent * -0.5); + + // Normally, the Gauss curve includes the 1/σ√2π term. This is to rescale it. + // However, since the histogram is already drawn in such a way that the highest bar + // reaches one, this rescaling isn't necessary and would only make the curve too flat. + + return Coordinate2D(t, gauss); }; float axisMin = plotView->rangeMin(AbstractPlotView::Axis::Horizontal);