Histogram Plot: add P10, mean and P90.

This commit is contained in:
Kristian Bendiksen committed 2025-06-30 21:49:29 +02:00
1 parent 48f1597953
commit b46e55bc21
9 files changed
+117 -80

No files matched your search

@@ -143,28 +143,19 @@ std::string RimEnsembleParameterHistogramDataSource::unitNameX() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> 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<double> 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<double> values;
for ( const QVariant& v : parameter.values )
@@ -172,20 +163,17 @@ std::vector<double> RimEnsembleParameterHistogramDataSource::valuesY( RimHistogr
values.push_back( v.toDouble() );
}
double min = parameter.minValue;
double max = parameter.maxValue;
std::vector<size_t> 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;
}
//--------------------------------------------------------------------------------------------------
@@ -43,8 +43,7 @@ public:
std::string unitNameX() const override;
std::string unitNameY() const override;
std::vector<double> valuesX( RimHistogramPlot::GraphType graphType ) const override;
std::vector<double> valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
std::string name() const override;
@@ -229,43 +229,31 @@ std::vector<double> RimEnsembleSummaryVectorHistogramDataSource::extractValuesFr
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimEnsembleSummaryVectorHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) const
RimHistogramDataSource::HistogramResult RimEnsembleSummaryVectorHistogramDataSource::compute( RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType ) const
{
RimHistogramDataSource::HistogramResult result;
std::vector<double> 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<double> RimEnsembleSummaryVectorHistogramDataSource::valuesY( RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType ) const
{
std::vector<double> 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<size_t> 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;
}
//--------------------------------------------------------------------------------------------------
@@ -48,8 +48,7 @@ public:
std::string unitNameX() const override;
std::string unitNameY() const override;
std::vector<double> valuesX( RimHistogramPlot::GraphType graphType ) const override;
std::vector<double> valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
std::string name() const override;
@@ -156,27 +156,25 @@ std::string RimGridStatisticsHistogramDataSource::unitNameX() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> 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<double> 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;
}
//--------------------------------------------------------------------------------------------------
@@ -44,8 +44,7 @@ public:
std::string unitNameX() const override;
std::string unitNameY() const override;
std::vector<double> valuesX( RimHistogramPlot::GraphType graphType ) const override;
std::vector<double> valuesY( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
HistogramResult compute( RimHistogramPlot::GraphType graphType, RimHistogramPlot::FrequencyType frequencyType ) const override;
std::string name() const override;
@@ -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 <memory>
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<RiuPlotAnnotationTool>();
}
//--------------------------------------------------------------------------------------------------
@@ -128,7 +137,7 @@ std::vector<double> RimHistogramCurve::valuesY() const
if ( m_dataSource )
{
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
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<double> RimHistogramCurve::valuesX() const
if ( m_dataSource )
{
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
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<double> curveValuesX = valuesX();
std::vector<double> curveValuesY = valuesY();
m_annotationTool->detachAllAnnotations();
if ( isChecked() && m_dataSource() )
{
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
auto result = m_dataSource->compute( plot->graphType(), plot->frequencyType() );
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
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<RiuQwtPlotWidget*>( plot->plotWidget() )->qwtPlot();
QString autoName = createCurveAutoName();
std::map<QString, double> 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 )
{
@@ -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<RimPlotAxisPropertiesInterface*> m_xPlotAxisProperties;
caf::PdmChildField<RimHistogramDataSource*> m_dataSource;
caf::PdmField<bool> m_showPercentiles;
std::unique_ptr<RiuPlotAnnotationTool> m_annotationTool;
};
@@ -22,6 +22,7 @@
#include "cafPdmObject.h"
#include "cafSignal.h"
#include <limits>
//==================================================================================================
///
@@ -32,6 +33,22 @@ class RimHistogramDataSource : public caf::PdmObject
CAF_PDM_HEADER_INIT;
public:
struct HistogramResult
{
HistogramResult()
: p10( std::numeric_limits<double>::infinity() )
, p90( std::numeric_limits<double>::infinity() )
, mean( std::numeric_limits<double>::infinity() )
{
}
std::vector<double> valuesX;
std::vector<double> 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<double> valuesX( RimHistogramPlot::GraphType graphType ) const = 0;
virtual std::vector<double> 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;