From b46e55bc21b69e98bb436f38fffea88d6ee53674 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 30 Jun 2025 17:16:22 +0200 Subject: [PATCH] Histogram Plot: add P10, mean and P90. --- ...imEnsembleParameterHistogramDataSource.cpp | 40 +++++------- .../RimEnsembleParameterHistogramDataSource.h | 3 +- ...sembleSummaryVectorHistogramDataSource.cpp | 38 ++++-------- ...EnsembleSummaryVectorHistogramDataSource.h | 3 +- .../RimGridStatisticsHistogramDataSource.cpp | 24 ++++---- .../RimGridStatisticsHistogramDataSource.h | 3 +- .../Histogram/RimHistogramCurve.cpp | 61 ++++++++++++++++--- .../Histogram/RimHistogramCurve.h | 5 ++ .../Histogram/RimHistogramDataSource.h | 20 +++++- 9 files changed, 117 insertions(+), 80 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.cpp b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.cpp index 249f7ee434..6532de93e0 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.cpp +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.cpp @@ -143,28 +143,19 @@ std::string RimEnsembleParameterHistogramDataSource::unitNameX() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleParameterHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) const +RimHistogramDataSource::HistogramResult RimEnsembleParameterHistogramDataSource::compute( RimHistogramPlot::GraphType graphType, + RimHistogramPlot::FrequencyType frequencyType ) const { - if ( !m_ensemble ) return {}; + RimHistogramDataSource::HistogramResult result; + + if ( !m_ensemble ) return result; auto parameter = m_ensemble->ensembleParameter( m_parameter ); - if ( !parameter.isNumeric() || !parameter.isValid() ) return {}; + if ( !parameter.isNumeric() || !parameter.isValid() ) return result; - double min = parameter.minValue; - double max = parameter.maxValue; - return computeHistogramBins( min, max, m_numBins, graphType ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleParameterHistogramDataSource::valuesY( RimHistogramPlot::GraphType graphType, - RimHistogramPlot::FrequencyType frequencyType ) const -{ - if ( !m_ensemble ) return {}; - - auto parameter = m_ensemble->ensembleParameter( m_parameter ); - if ( !parameter.isNumeric() || !parameter.isValid() ) return {}; + double min = parameter.minValue; + double max = parameter.maxValue; + result.valuesX = computeHistogramBins( min, max, m_numBins, graphType ); std::vector values; for ( const QVariant& v : parameter.values ) @@ -172,20 +163,17 @@ std::vector RimEnsembleParameterHistogramDataSource::valuesY( RimHistogr values.push_back( v.toDouble() ); } - double min = parameter.minValue; - double max = parameter.maxValue; - std::vector histogram; RigHistogramCalculator histCalc( min, max, m_numBins, &histogram ); histCalc.addData( values ); - double p10 = histCalc.calculatePercentil( 0.1, RigStatisticsMath::PercentileStyle::REGULAR ); - double p50 = histCalc.calculatePercentil( 0.5, RigStatisticsMath::PercentileStyle::REGULAR ); - double p90 = histCalc.calculatePercentil( 0.9, RigStatisticsMath::PercentileStyle::REGULAR ); + result.valuesY = computeHistogramFrequencies( histogram, graphType, frequencyType ); - RiaLogging::info( QString( "%1: P10=%2 Mean=%3 P90=%4" ).arg( QString::fromStdString( name() ) ).arg( p10 ).arg( p50 ).arg( p90 ) ); + result.p10 = histCalc.calculatePercentil( 0.1, RigStatisticsMath::PercentileStyle::SWITCHED ); + result.mean = histCalc.calculatePercentil( 0.5, RigStatisticsMath::PercentileStyle::SWITCHED ); + result.p90 = histCalc.calculatePercentil( 0.9, RigStatisticsMath::PercentileStyle::SWITCHED ); - return computeHistogramFrequencies( histogram, graphType, frequencyType ); + return result; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.h b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.h index 835610310e..3d418b48ee 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.h +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleParameterHistogramDataSource.h @@ -43,8 +43,7 @@ public: std::string unitNameX() const override; std::string unitNameY() const override; - std::vector valuesX( RimHistogramPlot::GraphType graphType ) const override; - std::vector valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; + HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; std::string name() const override; diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.cpp b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.cpp index d8ebb5c73f..d77dfa98aa 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.cpp +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.cpp @@ -229,43 +229,31 @@ std::vector RimEnsembleSummaryVectorHistogramDataSource::extractValuesFr //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleSummaryVectorHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) const +RimHistogramDataSource::HistogramResult RimEnsembleSummaryVectorHistogramDataSource::compute( RimHistogramPlot::GraphType graphType, + RimHistogramPlot::FrequencyType frequencyType ) const { + RimHistogramDataSource::HistogramResult result; + std::vector values = extractValuesFromEnsemble(); - if ( values.empty() ) return {}; + if ( values.empty() ) return result; auto [min_it, max_it] = std::minmax_element( values.begin(), values.end() ); - double min = *min_it; - double max = *max_it; - return computeHistogramBins( min, max, m_numBins, graphType ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleSummaryVectorHistogramDataSource::valuesY( RimHistogramPlot::GraphType graphType, - RimHistogramPlot::FrequencyType frequencyType ) const -{ - std::vector values = extractValuesFromEnsemble(); - if ( values.empty() ) return {}; - - auto [min_it, max_it] = std::minmax_element( values.begin(), values.end() ); - - double min = *min_it; - double max = *max_it; + double min = *min_it; + double max = *max_it; + result.valuesX = computeHistogramBins( min, max, m_numBins, graphType ); std::vector histogram; RigHistogramCalculator histCalc( min, max, m_numBins, &histogram ); histCalc.addData( values ); - double p10 = histCalc.calculatePercentil( 0.1, RigStatisticsMath::PercentileStyle::REGULAR ); - double p50 = histCalc.calculatePercentil( 0.5, RigStatisticsMath::PercentileStyle::REGULAR ); - double p90 = histCalc.calculatePercentil( 0.9, RigStatisticsMath::PercentileStyle::REGULAR ); + result.valuesY = computeHistogramFrequencies( histogram, graphType, frequencyType ); - RiaLogging::info( QString( "%1: P10=%2 Mean=%3 P90=%4" ).arg( QString::fromStdString( name() ) ).arg( p10 ).arg( p50 ).arg( p90 ) ); + result.p10 = histCalc.calculatePercentil( 0.1, RigStatisticsMath::PercentileStyle::SWITCHED ); + result.mean = histCalc.calculatePercentil( 0.5, RigStatisticsMath::PercentileStyle::SWITCHED ); + result.p90 = histCalc.calculatePercentil( 0.9, RigStatisticsMath::PercentileStyle::SWITCHED ); - return computeHistogramFrequencies( histogram, graphType, frequencyType ); + return result; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.h b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.h index 2233a17580..47b881cce3 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.h +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimEnsembleSummaryVectorHistogramDataSource.h @@ -48,8 +48,7 @@ public: std::string unitNameX() const override; std::string unitNameY() const override; - std::vector valuesX( RimHistogramPlot::GraphType graphType ) const override; - std::vector valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; + HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; std::string name() const override; diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.cpp b/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.cpp index 04e95aff53..8e94b7d235 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.cpp +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.cpp @@ -156,27 +156,25 @@ std::string RimGridStatisticsHistogramDataSource::unitNameX() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimGridStatisticsHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) const +RimHistogramDataSource::HistogramResult RimGridStatisticsHistogramDataSource::compute( RimHistogramPlot::GraphType graphType, + RimHistogramPlot::FrequencyType frequencyType ) const { + RimHistogramDataSource::HistogramResult result; + RigHistogramData histogramData = createStatisticsData(); - if ( !histogramData.isHistogramVectorValid() ) return {}; + if ( !histogramData.isHistogramVectorValid() ) return result; double min = histogramData.min; double max = histogramData.max; - return computeHistogramBins( min, max, m_numBins, graphType ); -} + result.valuesX = computeHistogramBins( min, max, m_numBins, graphType ); + result.valuesY = computeHistogramFrequencies( histogramData.histogram, graphType, frequencyType ); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimGridStatisticsHistogramDataSource::valuesY( RimHistogramPlot::GraphType graphType, - RimHistogramPlot::FrequencyType frequencyType ) const -{ - RigHistogramData histogramData = createStatisticsData(); - if ( !histogramData.isHistogramVectorValid() ) return {}; + result.p10 = histogramData.p10; + result.mean = histogramData.mean; + result.p90 = histogramData.p90; - return computeHistogramFrequencies( histogramData.histogram, graphType, frequencyType ); + return result; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.h b/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.h index a154ed44a9..2717f1bd5f 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.h +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimGridStatisticsHistogramDataSource.h @@ -44,8 +44,7 @@ public: std::string unitNameX() const override; std::string unitNameY() const override; - std::vector valuesX( RimHistogramPlot::GraphType graphType ) const override; - std::vector valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; + HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override; std::string name() const override; diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.cpp b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.cpp index 3865b164ab..8f3acd71c0 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.cpp +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.cpp @@ -18,6 +18,7 @@ #include "RimHistogramCurve.h" +#include "RiaColorTools.h" #include "RiaGuiApplication.h" #include "RiaPlotDefines.h" @@ -28,13 +29,17 @@ #include "RimProject.h" #include "RimTools.h" +#include "RiuPlotAnnotationTool.h" #include "RiuPlotAxis.h" #include "RiuPlotCurve.h" #include "RiuPlotMainWindow.h" +#include "RiuQwtPlotWidget.h" #include "cafAssert.h" #include "cafPdmUiTreeOrdering.h" +#include + CAF_PDM_SOURCE_INIT( RimHistogramCurve, "HistogramCurve" ); //-------------------------------------------------------------------------------------------------- @@ -49,10 +54,14 @@ RimHistogramCurve::RimHistogramCurve() CAF_PDM_InitFieldNoDefault( &m_dataSource, "DataSource", "Data Source" ); m_dataSource.uiCapability()->setUiTreeHidden( true ); + CAF_PDM_InitField( &m_showPercentiles, "ShowPercentiles", true, "Show P10, Mean, and P90" ); + setSymbolSkipDistance( 10.0f ); setLineThickness( 2 ); setDeletable( true ); + + m_annotationTool = std::make_unique(); } //-------------------------------------------------------------------------------------------------- @@ -128,7 +137,7 @@ std::vector RimHistogramCurve::valuesY() const if ( m_dataSource ) { RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted(); - return m_dataSource()->valuesY( plot->graphType(), plot->frequencyType() ); + return m_dataSource()->compute( plot->graphType(), plot->frequencyType() ).valuesY; } else return {}; @@ -142,7 +151,7 @@ std::vector RimHistogramCurve::valuesX() const if ( m_dataSource ) { RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted(); - return m_dataSource()->valuesX( plot->graphType() ); + return m_dataSource()->compute( plot->graphType(), plot->frequencyType() ).valuesX; } else return {}; @@ -238,15 +247,45 @@ void RimHistogramCurve::onLoadDataAndUpdate( bool updateParentPlot ) updateConnectedEditors(); - if ( isChecked() ) - { - std::vector curveValuesX = valuesX(); - std::vector curveValuesY = valuesY(); + m_annotationTool->detachAllAnnotations(); + + if ( isChecked() && m_dataSource() ) + { + RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted(); + + auto result = m_dataSource->compute( plot->graphType(), plot->frequencyType() ); - auto plot = firstAncestorOrThisOfTypeAsserted(); bool useLogarithmicScale = plot->isLogarithmicScaleEnabled( axisY() ); - setSamplesFromXYValues( curveValuesX, curveValuesY, useLogarithmicScale ); + QColor color = RiaColorTools::toQColor( m_curveAppearance->color() ); + if ( plot->plotWidget() ) + { + if ( m_showPercentiles() ) + { + QwtPlot* qwtPlot = dynamic_cast( plot->plotWidget() )->qwtPlot(); + + QString autoName = createCurveAutoName(); + std::map percentiles = { { QString( "P10: %1" ).arg( autoName ), result.p10 }, + { QString( "Mean: %1" ).arg( autoName ), result.mean }, + { QString( "P90: %1" ).arg( autoName ), result.p90 } }; + + for ( const auto& [name, value] : percentiles ) + { + if ( !std::isinf( value ) ) + { + m_annotationTool->attachAnnotationLine( qwtPlot, + color, + name, + Qt::PenStyle::DashDotDotLine, + value, + RiaDefines::Orientation::VERTICAL, + Qt::AlignmentFlag::AlignCenter ); + } + } + } + } + + setSamplesFromXYValues( result.valuesX, result.valuesY, useLogarithmicScale ); } if ( updateParentPlot && hasParentPlot() ) @@ -306,6 +345,8 @@ void RimHistogramCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrderi nameGroup->add( &m_showLegend ); RimPlotCurve::curveNameUiOrdering( *nameGroup ); + uiOrdering.add( &m_showPercentiles ); + uiOrdering.skipRemainingFields(); } @@ -345,6 +386,10 @@ void RimHistogramCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedFiel plot->updateAxes(); dataChanged.send(); } + else if ( changedField == &m_showPercentiles ) + { + loadAndUpdate = true; + } if ( loadAndUpdate ) { diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.h b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.h index a5724f73e4..fc2423b0be 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.h +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramCurve.h @@ -18,6 +18,7 @@ #pragma once +#include "RiuPlotAnnotationTool.h" #include "cafPdmChildField.h" #include "cafPdmField.h" #include "cafPdmObject.h" @@ -86,4 +87,8 @@ private: caf::PdmPtrField m_xPlotAxisProperties; caf::PdmChildField m_dataSource; + + caf::PdmField m_showPercentiles; + + std::unique_ptr m_annotationTool; }; diff --git a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramDataSource.h b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramDataSource.h index 4a6881973f..b40771c3ca 100644 --- a/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramDataSource.h +++ b/ApplicationLibCode/ProjectDataModel/Histogram/RimHistogramDataSource.h @@ -22,6 +22,7 @@ #include "cafPdmObject.h" #include "cafSignal.h" +#include //================================================================================================== /// @@ -32,6 +33,22 @@ class RimHistogramDataSource : public caf::PdmObject CAF_PDM_HEADER_INIT; public: + struct HistogramResult + { + HistogramResult() + : p10( std::numeric_limits::infinity() ) + , p90( std::numeric_limits::infinity() ) + , mean( std::numeric_limits::infinity() ) + { + } + + std::vector valuesX; + std::vector valuesY; + double p10; + double p90; + double mean; + }; + RimHistogramDataSource(); ~RimHistogramDataSource() override; @@ -40,8 +57,7 @@ public: virtual std::string unitNameX() const = 0; virtual std::string unitNameY() const = 0; - virtual std::vector valuesX( RimHistogramPlot::GraphType graphType ) const = 0; - virtual std::vector valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const = 0; + virtual HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const = 0; virtual std::string name() const = 0;