Add new and more general histogram plots.

This commit is contained in:
Kristian Bendiksen
2025-06-26 08:25:34 +02:00
parent b8dc8c0d14
commit 923a44d75e
45 changed files with 5232 additions and 9 deletions
+1
View File
@@ -134,6 +134,7 @@ list(
ProjectDataModelCommands/CommandRouter/CMakeLists_files.cmake
ProjectDataModel/VerticalFlowPerformance/CMakeLists_files.cmake
ProjectDataModel/QuickAccess/CMakeLists_files.cmake
ProjectDataModel/Histogram/CMakeLists_files.cmake
GeoMech/GeoMechVisualization/CMakeLists_files.cmake
ModelVisualization/CMakeLists_files.cmake
ModelVisualization/Faults/CMakeLists_files.cmake
@@ -63,6 +63,7 @@ set(COMMAND_REFERENCED_CMAKE_FILES
Sumo/CMakeLists_files.cmake
ToolCommands/CMakeLists_files.cmake
3dView/CMakeLists_files.cmake
Histogram/CMakeLists_files.cmake
)
# Include source file lists from *.cmake files
@@ -101,6 +101,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.h
${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateSummaryEnsembleFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicHistogramPlotTools.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -206,6 +207,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateSummaryEnsembleFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicHistogramPlotTools.cpp
)
if(RESINSIGHT_USE_QT_CHARTS)
@@ -4,6 +4,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationMatrixPlotFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewParameterResultCrossPlotFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleFromFilteredCasesFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateHistogramForEnsembleParameterFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateHistogramForSummaryVectorFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -12,6 +14,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewParameterResultCrossPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationReportPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleFromFilteredCasesFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateHistogramForEnsembleParameterFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateHistogramForSummaryVectorFeature.cpp
)
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
@@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateHistogramForEnsembleParameterFeature.h"
#include "RicHistogramPlotTools.h"
#include "Histogram/RimEnsembleParameterHistogramDataSource.h"
#include "RimCorrelationPlotCollection.h"
#include "RimCorrelationReportPlot.h"
#include "RimParameterResultCrossPlot.h"
#include "cafSelectionManagerTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCreateHistogramForEnsembleParameterFeature, "RicCreateHistogramForEnsembleParameterFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicCreateHistogramForEnsembleParameterFeature::isCommandEnabled() const
{
return selectedCrossPlot() != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateHistogramForEnsembleParameterFeature::onActionTriggered( bool isChecked )
{
if ( auto crossPlot = selectedCrossPlot() )
{
auto multiplot = RicHistogramPlotTools::addNewHistogramMultiplot();
auto histogramPlot = RicHistogramPlotTools::addNewHistogramPlot( multiplot );
QString ensembleParameter = crossPlot->ensembleParameter();
auto ensembles = crossPlot->ensembles();
for ( RimSummaryEnsemble* ensemble : ensembles )
{
auto dataSource = new RimEnsembleParameterHistogramDataSource();
dataSource->setEnsembleParameter( ensembleParameter );
dataSource->setEnsemble( ensemble );
RicHistogramPlotTools::createHistogramCurve( histogramPlot, dataSource );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateHistogramForEnsembleParameterFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/SummaryEnsemble.svg" ) );
actionToSetup->setText( "Create Histogram Plot For Ensemble Parameter" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimParameterResultCrossPlot* RicCreateHistogramForEnsembleParameterFeature::selectedCrossPlot()
{
auto selectedPlots = caf::selectedObjectsByTypeStrict<RimParameterResultCrossPlot*>();
if ( selectedPlots.size() == 1 ) return selectedPlots.front();
if ( auto reportPlot = caf::firstAncestorOfTypeFromSelectedObject<RimCorrelationReportPlot>() )
{
return reportPlot->crossPlot();
}
return nullptr;
}
@@ -0,0 +1,38 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
class RimParameterResultCrossPlot;
//==================================================================================================
///
//==================================================================================================
class RicCreateHistogramForEnsembleParameterFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
private:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
static RimParameterResultCrossPlot* selectedCrossPlot();
};
@@ -0,0 +1,93 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateHistogramForSummaryVectorFeature.h"
#include "Histogram/RimEnsembleSummaryVectorHistogramDataSource.h"
#include "RicHistogramPlotTools.h"
#include "Histogram/RimEnsembleParameterHistogramDataSource.h"
#include "RimCorrelationPlotCollection.h"
#include "RimCorrelationReportPlot.h"
#include "RimParameterResultCrossPlot.h"
#include "cafSelectionManagerTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCreateHistogramForSummaryVectorFeature, "RicCreateHistogramForSummaryVectorFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicCreateHistogramForSummaryVectorFeature::isCommandEnabled() const
{
return selectedCrossPlot() != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateHistogramForSummaryVectorFeature::onActionTriggered( bool isChecked )
{
if ( auto crossPlot = selectedCrossPlot() )
{
auto multiplot = RicHistogramPlotTools::addNewHistogramMultiplot();
auto histogramPlot = RicHistogramPlotTools::addNewHistogramPlot( multiplot );
auto ensembles = crossPlot->ensembles();
auto timeStep = crossPlot->timeStep();
auto addresses = crossPlot->addresses();
for ( RimSummaryEnsemble* ensemble : ensembles )
{
for ( auto address : addresses )
{
auto dataSource = new RimEnsembleSummaryVectorHistogramDataSource();
dataSource->setEnsemble( ensemble );
dataSource->setSummaryAddress( address );
dataSource->setTimeStep( timeStep );
RicHistogramPlotTools::createHistogramCurve( histogramPlot, dataSource );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateHistogramForSummaryVectorFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/SummaryEnsemble.svg" ) );
actionToSetup->setText( "Create Histogram Plot For Summary Vector" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimParameterResultCrossPlot* RicCreateHistogramForSummaryVectorFeature::selectedCrossPlot()
{
auto selectedPlots = caf::selectedObjectsByTypeStrict<RimParameterResultCrossPlot*>();
if ( selectedPlots.size() == 1 ) return selectedPlots.front();
if ( auto reportPlot = caf::firstAncestorOfTypeFromSelectedObject<RimCorrelationReportPlot>() )
{
return reportPlot->crossPlot();
}
return nullptr;
}
@@ -0,0 +1,38 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
class RimParameterResultCrossPlot;
//==================================================================================================
///
//==================================================================================================
class RicCreateHistogramForSummaryVectorFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
private:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
static RimParameterResultCrossPlot* selectedCrossPlot();
};
@@ -0,0 +1,14 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewDefaultHistogramPlotFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewHistogramCurveFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewHistogramMultiPlotFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewDefaultHistogramPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewHistogramCurveFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewHistogramMultiPlotFeature.cpp
)
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND COMMAND_CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewDefaultHistogramPlotFeature.h"
#include "Histogram/RimHistogramMultiPlot.h"
#include "Histogram/RimHistogramPlot.h"
#include "RicHistogramPlotTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewDefaultHistogramPlotFeature, "RicNewDefaultHistogramPlotFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewDefaultHistogramPlotFeature::isCommandEnabled() const
{
RimHistogramMultiPlot* multiPlot = dynamic_cast<RimHistogramMultiPlot*>( caf::SelectionManager::instance()->selectedItem() );
return multiPlot != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewDefaultHistogramPlotFeature::onActionTriggered( bool isChecked )
{
RimHistogramMultiPlot* multiPlot = dynamic_cast<RimHistogramMultiPlot*>( caf::SelectionManager::instance()->selectedItem() );
if ( multiPlot )
{
RicHistogramPlotTools::addNewHistogramPlot( multiPlot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewDefaultHistogramPlotFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Add Histogram Plot" );
actionToSetup->setIcon( QIcon( ":/SummaryPlotLight16x16.png" ) );
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicNewDefaultHistogramPlotFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -0,0 +1,94 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewHistogramCurveFeature.h"
#include "RiaGuiApplication.h"
#include "Histogram/RimEnsembleParameterHistogramDataSource.h"
#include "Histogram/RimEnsembleSummaryVectorHistogramDataSource.h"
#include "Histogram/RimGridStatisticsHistogramDataSource.h"
#include "Histogram/RimHistogramCurve.h"
#include "Histogram/RimHistogramCurveCollection.h"
#include "Histogram/RimHistogramPlot.h"
#include "RicHistogramPlotTools.h"
#include "RimProject.h"
#include "RiuPlotMainWindow.h"
#include "RiuPlotMainWindowTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewHistogramCurveFeature, "RicNewHistogramCurveFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewHistogramCurveFeature::isCommandEnabled() const
{
return selectedHistogramPlot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewHistogramCurveFeature::onActionTriggered( bool isChecked )
{
auto getDataSourceFromString = []( const QString& dataSourceType ) -> RimHistogramDataSource*
{
if ( dataSourceType == "Ensemble Parameter" )
return new RimEnsembleParameterHistogramDataSource();
else if ( dataSourceType == "Grid Statistics" )
return new RimGridStatisticsHistogramDataSource();
else if ( dataSourceType == "Summary Vector" )
return new RimEnsembleSummaryVectorHistogramDataSource();
return nullptr;
};
RimHistogramPlot* plot = selectedHistogramPlot();
if ( plot )
{
RimHistogramDataSource* dataSource = getDataSourceFromString( userData().toString() );
RicHistogramPlotTools::createHistogramCurve( plot, dataSource );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewHistogramCurveFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "New Histogram Curve" );
actionToSetup->setIcon( QIcon( ":/SummaryCurve16x16.png" ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramPlot* RicNewHistogramCurveFeature::selectedHistogramPlot() const
{
caf::PdmObject* selObj = dynamic_cast<caf::PdmObject*>( caf::SelectionManager::instance()->selectedItem() );
if ( selObj )
{
return selObj->firstAncestorOrThisOfType<RimHistogramPlot>();
}
return nullptr;
}
@@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
class RimHistogramPlot;
//==================================================================================================
///
//==================================================================================================
class RicNewHistogramCurveFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
private:
RimHistogramPlot* selectedHistogramPlot() const;
};
@@ -0,0 +1,64 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewHistogramMultiPlotFeature.h"
#include "Histogram/RimHistogramMultiPlotCollection.h"
#include "RicHistogramPlotTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewHistogramMultiPlotFeature, "RicNewHistogramMultiPlotFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewHistogramMultiPlotFeature::isCommandEnabled() const
{
std::vector<RimHistogramMultiPlotCollection*> selectedItems =
caf::SelectionManager::instance()->objectsByType<RimHistogramMultiPlotCollection>();
return ( selectedItems.size() == 1 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewHistogramMultiPlotFeature::onActionTriggered( bool isChecked )
{
std::vector<RimHistogramMultiPlotCollection*> selectedItems =
caf::SelectionManager::instance()->objectsByType<RimHistogramMultiPlotCollection>();
if ( selectedItems.size() != 1 ) return;
if ( RimHistogramMultiPlotCollection* coll = selectedItems[0] )
{
RicHistogramPlotTools::addNewHistogramMultiplot( coll );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewHistogramMultiPlotFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "New Histogram Plot" );
actionToSetup->setIcon( QIcon( ":/MultiPlot16x16.png" ) );
}
@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
class RimSummaryCase;
class RimSummaryEnsemble;
//==================================================================================================
///
//==================================================================================================
class RicNewHistogramMultiPlotFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -0,0 +1,105 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicHistogramPlotTools.h"
#include "Histogram/RimHistogramCurve.h"
#include "Histogram/RimHistogramDataSource.h"
#include "Histogram/RimHistogramMultiPlot.h"
#include "Histogram/RimHistogramMultiPlotCollection.h"
#include "Histogram/RimHistogramPlot.h"
#include "RimMainPlotCollection.h"
#include "RimProject.h"
#include "RiaColorTables.h"
#include "RiaGuiApplication.h"
#include "RiuPlotMainWindow.h"
#include "RiuPlotMainWindowTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicHistogramPlotTools::createHistogramCurve( RimHistogramPlot* plot, RimHistogramDataSource* dataSource )
{
RiaGuiApplication* app = RiaGuiApplication::instance();
RimProject* project = app->project();
CAF_ASSERT( project );
RimHistogramCurve* newCurve = new RimHistogramCurve();
newCurve->setDataSource( dataSource );
cvf::Color3f curveColor = RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f( plot->curveCount() );
newCurve->setColor( curveColor );
newCurve->setIsStacked( true );
newCurve->setFillColor( curveColor );
plot->addCurveNoUpdate( newCurve );
plot->loadDataAndUpdate();
plot->updateConnectedEditors();
RiuPlotMainWindow* mainPlotWindow = app->mainPlotWindow();
mainPlotWindow->updateMultiPlotToolBar();
RiuPlotMainWindowTools::onObjectAppended( newCurve, plot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlot* RicHistogramPlotTools::addNewHistogramMultiplot()
{
auto collection = RimMainPlotCollection::current()->histogramMultiPlotCollection();
if ( !collection ) return nullptr;
return addNewHistogramMultiplot( collection );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlot* RicHistogramPlotTools::addNewHistogramMultiplot( RimHistogramMultiPlotCollection* collection )
{
CAF_ASSERT( collection );
RimHistogramMultiPlot* multiplot = collection->appendHistogramMultiPlot();
multiplot->setAsPlotMdiWindow();
multiplot->setShowWindow( true );
multiplot->loadDataAndUpdate();
collection->updateConnectedEditors();
RiuPlotMainWindowTools::onObjectAppended( multiplot, collection );
return multiplot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramPlot* RicHistogramPlotTools::addNewHistogramPlot( RimHistogramMultiPlot* histogramMultiPlot )
{
RimHistogramPlot* plot = new RimHistogramPlot();
plot->enableAutoPlotTitle( true );
histogramMultiPlot->addPlot( plot );
RiuPlotMainWindowTools::onObjectAppended( plot, histogramMultiPlot );
return plot;
}
@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
class RimHistogramDataSource;
class RimHistogramPlot;
class RimHistogramMultiPlot;
class RimHistogramMultiPlotCollection;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class RicHistogramPlotTools
{
public:
static void createHistogramCurve( RimHistogramPlot* plot, RimHistogramDataSource* dataSource );
static RimHistogramMultiPlot* addNewHistogramMultiplot();
static RimHistogramMultiPlot* addNewHistogramMultiplot( RimHistogramMultiPlotCollection* collection );
static RimHistogramPlot* addNewHistogramPlot( RimHistogramMultiPlot* histogramMultiPlot );
};
@@ -513,7 +513,7 @@ std::set<RigEnsembleParameter> RimAbstractCorrelationPlot::variationSortedEnsemb
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigEnsembleParameter RimAbstractCorrelationPlot::ensembleParameter( const QString& ensembleParameterName ) const
RigEnsembleParameter RimAbstractCorrelationPlot::ensembleParameterByName( const QString& ensembleParameterName ) const
{
std::set<RigEnsembleParameter> ensembleParms = ensembleParameters();
for ( const RigEnsembleParameter& eParam : ensembleParms )
@@ -574,7 +574,10 @@ RiuPlotWidget* RimAbstractCorrelationPlot::doCreatePlotViewWidget( QWidget* main
m_plotWidget = new RiuQwtPlotWidget( this, mainWindowParent );
updatePlotTitle();
new RiuContextMenuLauncher( m_plotWidget, { "RicShowPlotDataFeature" } );
new RiuContextMenuLauncher( m_plotWidget,
{ "RicShowPlotDataFeature",
"RicCreateHistogramForEnsembleParameterFeature",
"RicCreateHistogramForSummaryVectorFeature" } );
}
return m_plotWidget;
@@ -79,6 +79,8 @@ public:
void setAxisValueFontSize( caf::FontTools::RelativeSize fontSize );
std::set<time_t> allAvailableTimeSteps();
std::set<RifEclipseSummaryAddress> addresses() const;
protected:
// Overridden PDM methods
@@ -88,10 +90,9 @@ protected:
caf::PdmFieldHandle* userDescriptionField() override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
std::set<RifEclipseSummaryAddress> addresses() const;
std::set<RigEnsembleParameter> ensembleParameters() const;
std::set<RigEnsembleParameter> variationSortedEnsembleParameters();
RigEnsembleParameter ensembleParameter( const QString& ensembleParameterName ) const;
std::set<RigEnsembleParameter> ensembleParameters() const;
std::set<RigEnsembleParameter> variationSortedEnsembleParameters();
RigEnsembleParameter ensembleParameterByName( const QString& ensembleParameterName ) const;
// RimViewWindow overrides
QWidget* viewWidget() override;
@@ -110,6 +110,14 @@ void RimParameterResultCrossPlot::setEnsembleParameter( const QString& ensembleP
updateFilterRanges();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimParameterResultCrossPlot::ensembleParameter() const
{
return m_ensembleParameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -465,7 +473,7 @@ void RimParameterResultCrossPlot::detachAllCurves()
//--------------------------------------------------------------------------------------------------
std::vector<RimParameterResultCrossPlot::CaseData> RimParameterResultCrossPlot::createCaseData() const
{
RigEnsembleParameter parameter = ensembleParameter( m_ensembleParameter );
RigEnsembleParameter parameter = ensembleParameterByName( m_ensembleParameter );
if ( !( parameter.isNumeric() && parameter.isValid() ) ) return {};
std::vector<RimParameterResultCrossPlot::CaseData> caseData;
@@ -600,7 +608,10 @@ RiuPlotWidget* RimParameterResultCrossPlot::doCreatePlotViewWidget( QWidget* mai
m_plotWidget = new RiuQwtPlotWidget( this, mainWindowParent );
updatePlotTitle();
new RiuContextMenuLauncher( m_plotWidget, { "RicShowPlotDataFeature", "RicCreateEnsembleFromFilteredCasesFeature" } );
new RiuContextMenuLauncher( m_plotWidget,
{ "RicShowPlotDataFeature",
"RicCreateEnsembleFromFilteredCasesFeature",
"RicCreateHistogramForEnsembleParameterFeature" } );
}
if ( m_plotWidget )
@@ -36,7 +36,8 @@ class RimParameterResultCrossPlot : public RimAbstractCorrelationPlot
public:
RimParameterResultCrossPlot();
~RimParameterResultCrossPlot() override;
void setEnsembleParameter( const QString& ensembleParameter );
void setEnsembleParameter( const QString& ensembleParameter );
QString ensembleParameter() const;
std::vector<RimSummaryCase*> summaryCasesExcludedByFilter() const;
void appendFilterFields( caf::PdmUiOrdering& uiOrdering );
@@ -0,0 +1,26 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleParameterHistogramDataSource.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleSummaryVectorHistogramDataSource.h
${CMAKE_CURRENT_LIST_DIR}/RimGridStatisticsHistogramDataSource.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramCurve.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramCurveCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramDataSource.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramMultiPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramMultiPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimHistogramPlot.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleParameterHistogramDataSource.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleSummaryVectorHistogramDataSource.cpp
${CMAKE_CURRENT_LIST_DIR}/RimGridStatisticsHistogramDataSource.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramCurveCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramDataSource.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramMultiPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramMultiPlotCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimHistogramPlot.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,217 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleParameterHistogramDataSource.h"
#include "RiaLogging.h"
#include "Histogram/RimHistogramPlot.h"
#include "RimProject.h"
#include "RimSummaryEnsemble.h"
#include "RigStatisticsMath.h"
CAF_PDM_XML_SOURCE_INIT( RimEnsembleParameterHistogramDataSource, "EnsembleParameterHistogramDataSource" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleParameterHistogramDataSource::RimEnsembleParameterHistogramDataSource()
{
CAF_PDM_InitObject( "Ensemble Parameter Histogram Data Source", );
CAF_PDM_InitFieldNoDefault( &m_ensemble, "Ensemble", "Ensemble" );
CAF_PDM_InitFieldNoDefault( &m_parameter, "Parameter", "Parameter" );
CAF_PDM_InitField( &m_numBins, "NumBins", 15, "Number of Bins" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleParameterHistogramDataSource::~RimEnsembleParameterHistogramDataSource()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimEnsembleParameterHistogramDataSource::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_ensemble )
{
RimProject* proj = RimProject::current();
for ( RimSummaryEnsemble* ensemble : proj->summaryEnsembles() )
{
if ( ensemble->isEnsemble() ) options.push_back( caf::PdmOptionItemInfo( ensemble->name(), ensemble ) );
}
}
else if ( fieldNeedingOptions == &m_parameter )
{
if ( m_ensemble )
{
for ( const RigEnsembleParameter& p : m_ensemble->variationSortedEnsembleParameters() )
{
if ( p.isNumeric() )
{
options.push_back( caf::PdmOptionItemInfo( p.name, p.name ) );
}
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleParameterHistogramDataSource ::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_ensemble );
uiOrdering.add( &m_parameter );
uiOrdering.add( &m_numBins );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleParameterHistogramDataSource::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
if ( changedField == &m_ensemble )
{
if ( m_ensemble )
{
// Try to find a new parameter if the current parameter is empty or not available
// when changing ensemble.
auto parameter = m_ensemble->ensembleParameter( m_parameter );
if ( !parameter.isNumeric() || !parameter.isValid() )
{
// Find first valid numeric parameter
for ( const RigEnsembleParameter& p : m_ensemble->variationSortedEnsembleParameters() )
{
if ( p.isNumeric() && p.isValid() )
{
m_parameter = p.name;
break;
}
}
}
}
}
dataSourceChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleParameterHistogramDataSource::unitNameY() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleParameterHistogramDataSource::unitNameX() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimEnsembleParameterHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) 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;
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 {};
std::vector<double> values;
for ( const QVariant& v : parameter.values )
{
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 );
RiaLogging::info( QString( "%1: P10=%2 Mean=%3 P90=%4" ).arg( QString::fromStdString( name() ) ).arg( p10 ).arg( p50 ).arg( p90 ) );
return computeHistogramFrequencies( histogram, graphType, frequencyType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleParameterHistogramDataSource::name() const
{
std::string name = "";
if ( m_ensemble ) name = m_ensemble->name().toStdString();
if ( !m_parameter().isEmpty() ) name += ", " + m_parameter().toStdString();
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleParameterHistogramDataSource::setEnsembleParameter( const QString& ensembleParameter )
{
m_parameter = ensembleParameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleParameterHistogramDataSource::setEnsemble( RimSummaryEnsemble* ensemble )
{
m_ensemble = ensemble;
}
@@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimHistogramDataSource.h"
#include "cafPdmField.h"
#include "cafPdmPtrField.h"
class RimSummaryEnsemble;
//==================================================================================================
///
///
//==================================================================================================
class RimEnsembleParameterHistogramDataSource : public RimHistogramDataSource
{
CAF_PDM_HEADER_INIT;
public:
RimEnsembleParameterHistogramDataSource();
~RimEnsembleParameterHistogramDataSource() override;
void setEnsembleParameter( const QString& ensembleParameter );
void setEnsemble( RimSummaryEnsemble* ensemble );
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;
std::string name() const override;
protected:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
caf::PdmPtrField<RimSummaryEnsemble*> m_ensemble;
caf::PdmField<QString> m_parameter;
caf::PdmField<int> m_numBins;
};
@@ -0,0 +1,310 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimEnsembleSummaryVectorHistogramDataSource.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RiaQDateTimeTools.h"
#include "RiaResultNames.h"
#include "RifSummaryReaderInterface.h"
#include "Histogram/RimHistogramPlot.h"
#include "RimProject.h"
#include "RimSummaryCase.h"
#include "RimSummaryEnsemble.h"
#include "RigStatisticsMath.h"
#include "cafPdmUiComboBoxEditor.h"
#include "cafPdmUiLineEditor.h"
CAF_PDM_XML_SOURCE_INIT( RimEnsembleSummaryVectorHistogramDataSource, "EnsembleSummaryVectorHistogramDataSource" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleSummaryVectorHistogramDataSource::RimEnsembleSummaryVectorHistogramDataSource()
{
CAF_PDM_InitObject( "Ensemble Summary Vector Histogram Data Source", );
CAF_PDM_InitFieldNoDefault( &m_ensemble, "Ensemble", "Ensemble" );
CAF_PDM_InitFieldNoDefault( &m_summaryAddressUiField, "SelectedVariableDisplayVar", "Vector" );
m_summaryAddressUiField.xmlCapability()->disableIO();
m_summaryAddressUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_summaryAddress, "SummaryAddress", "Summary Address" );
m_summaryAddress.uiCapability()->setUiTreeChildrenHidden( true );
m_summaryAddress = new RimSummaryAddress;
CAF_PDM_InitFieldNoDefault( &m_timeStep, "TimeStep", "Time Step" );
m_timeStep.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_numBins, "NumBins", 15, "Number of Bins" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleSummaryVectorHistogramDataSource::~RimEnsembleSummaryVectorHistogramDataSource()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimEnsembleSummaryVectorHistogramDataSource::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_ensemble )
{
RimProject* proj = RimProject::current();
for ( RimSummaryEnsemble* ensemble : proj->summaryEnsembles() )
{
if ( ensemble->isEnsemble() ) options.push_back( caf::PdmOptionItemInfo( ensemble->name(), ensemble ) );
}
}
else if ( fieldNeedingOptions == &m_summaryAddressUiField )
{
appendOptionItemsForSummaryAddresses( &options, m_ensemble );
}
else if ( fieldNeedingOptions == &m_timeStep )
{
if ( m_ensemble )
{
std::set<time_t> allTimeSteps = m_ensemble->ensembleTimeSteps();
QString dateFormatString = RiaQDateTimeTools::dateFormatString( RiaPreferences::current()->dateFormat(),
RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY );
std::vector<QDateTime> allDateTimes;
for ( time_t timeStep : allTimeSteps )
{
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timeStep );
options.push_back(
caf::PdmOptionItemInfo( RiaQDateTimeTools::toStringUsingApplicationLocale( dateTime, dateFormatString ), dateTime ) );
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::appendOptionItemsForSummaryAddresses( QList<caf::PdmOptionItemInfo>* options,
RimSummaryEnsemble* summaryCaseGroup )
{
if ( !summaryCaseGroup ) return;
auto allSummaryCases = summaryCaseGroup->allSummaryCases();
auto addressesForEnsemble = summaryCaseGroup->ensembleSummaryAddresses();
for ( const auto& addr : addressesForEnsemble )
{
std::string name = addr.uiText();
QString s = QString::fromStdString( name );
options->push_back( caf::PdmOptionItemInfo( s, QVariant::fromValue( addr ) ) );
}
options->push_front( caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), QVariant::fromValue( RifEclipseSummaryAddress() ) ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
m_summaryAddressUiField = m_summaryAddress->address();
uiOrdering.add( &m_ensemble );
uiOrdering.add( &m_summaryAddressUiField );
uiOrdering.add( &m_timeStep );
uiOrdering.add( &m_numBins );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
if ( changedField == &m_ensemble )
{
updateConnectedEditors();
}
else if ( changedField == &m_summaryAddressUiField )
{
m_summaryAddress->setAddress( m_summaryAddressUiField() );
}
dataSourceChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleSummaryVectorHistogramDataSource::unitNameY() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleSummaryVectorHistogramDataSource::unitNameX() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimEnsembleSummaryVectorHistogramDataSource::extractValuesFromEnsemble() const
{
std::vector<double> values;
time_t selectedTimestep = m_timeStep().toSecsSinceEpoch();
auto timeDiff = []( time_t lhs, time_t rhs ) -> time_t
{
if ( lhs >= rhs )
{
return lhs - rhs;
}
return rhs - lhs;
};
if ( m_summaryAddress && m_ensemble )
{
for ( size_t caseIdx = 0u; caseIdx < m_ensemble->allSummaryCases().size(); ++caseIdx )
{
auto summaryCase = m_ensemble->allSummaryCases()[caseIdx];
RifSummaryReaderInterface* reader = summaryCase->summaryReader();
if ( !reader ) continue;
double summaryValue = std::numeric_limits<double>::infinity();
time_t closestTimeStep = 0;
auto [isOk, summaryValues] = reader->values( m_summaryAddressUiField );
if ( isOk )
{
const std::vector<time_t>& timeSteps = reader->timeSteps( m_summaryAddressUiField );
for ( size_t i = 0; i < timeSteps.size(); ++i )
{
if ( timeDiff( timeSteps[i], selectedTimestep ) < timeDiff( selectedTimestep, closestTimeStep ) )
{
summaryValue = summaryValues[i];
closestTimeStep = timeSteps[i];
}
}
}
if ( summaryValue != std::numeric_limits<double>::infinity() ) values.push_back( summaryValue );
}
}
return values;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimEnsembleSummaryVectorHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) 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;
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;
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 );
RiaLogging::info( QString( "%1: P10=%2 Mean=%3 P90=%4" ).arg( QString::fromStdString( name() ) ).arg( p10 ).arg( p50 ).arg( p90 ) );
return computeHistogramFrequencies( histogram, graphType, frequencyType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimEnsembleSummaryVectorHistogramDataSource::name() const
{
std::string name = "";
if ( m_ensemble ) name = m_ensemble->name().toStdString();
if ( !m_summaryAddress->address().uiText().empty() ) name += ", " + m_summaryAddress->address().uiText();
return name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::setEnsemble( RimSummaryEnsemble* ensemble )
{
m_ensemble = ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::setSummaryAddress( RifEclipseSummaryAddress& summaryAddress )
{
m_summaryAddressUiField = summaryAddress;
m_summaryAddress->setAddress( m_summaryAddressUiField );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEnsembleSummaryVectorHistogramDataSource::setTimeStep( QDateTime& timeStep )
{
m_timeStep = timeStep;
}
@@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimHistogramDataSource.h"
#include "RimSummaryAddress.h"
#include "cafPdmField.h"
#include "cafPdmPtrField.h"
#include <QDateTime>
class RimSummaryEnsemble;
//==================================================================================================
///
///
//==================================================================================================
class RimEnsembleSummaryVectorHistogramDataSource : public RimHistogramDataSource
{
CAF_PDM_HEADER_INIT;
public:
RimEnsembleSummaryVectorHistogramDataSource();
~RimEnsembleSummaryVectorHistogramDataSource() override;
void setEnsemble( RimSummaryEnsemble* ensemble );
void setSummaryAddress( RifEclipseSummaryAddress& summaryAddress );
void setTimeStep( QDateTime& timeStep );
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;
std::string name() const override;
protected:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void appendOptionItemsForSummaryAddresses( QList<caf::PdmOptionItemInfo>* options, RimSummaryEnsemble* summaryCaseGroup );
std::vector<double> extractValuesFromEnsemble() const;
caf::PdmPtrField<RimSummaryEnsemble*> m_ensemble;
caf::PdmChildField<RimSummaryAddress*> m_summaryAddress;
caf::PdmField<RifEclipseSummaryAddress> m_summaryAddressUiField;
caf::PdmField<QDateTime> m_timeStep;
caf::PdmField<int> m_numBins;
};
@@ -0,0 +1,243 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimGridStatisticsHistogramDataSource.h"
#include "Histogram/RimHistogramPlot.h"
#include "RimEclipseCase.h"
#include "RimEclipseResultDefinition.h"
#include "RimEclipseView.h"
#include "RimHistogramCalculator.h"
#include "RimProject.h"
#include "RimTools.h"
#include "cafPdmUiComboBoxEditor.h"
CAF_PDM_XML_SOURCE_INIT( RimGridStatisticsHistogramDataSource, "GridStatisticsHistogramDataSource" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGridStatisticsHistogramDataSource::RimGridStatisticsHistogramDataSource()
{
CAF_PDM_InitObject( "Ensemble Parameter Histogram Data Source", );
CAF_PDM_InitFieldNoDefault( &m_case, "Case", "Case" );
m_case.uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitField( &m_timeStep, "TimeStep", -1, "Time Step" );
m_timeStep.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_cellFilterView, "VisibleCellView", "Filter by 3d View Visibility" );
CAF_PDM_InitFieldNoDefault( &m_property, "Property", "Property" );
m_property = new RimEclipseResultDefinition( caf::PdmUiItemInfo::TOP );
m_property.uiCapability()->setUiTreeChildrenHidden( true );
m_property->setTernaryEnabled( false );
CAF_PDM_InitField( &m_numBins, "NumBins", 15, "Number of Bins" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGridStatisticsHistogramDataSource::~RimGridStatisticsHistogramDataSource()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimGridStatisticsHistogramDataSource::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_case )
{
RimTools::eclipseCaseOptionItems( &options );
if ( options.empty() )
{
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
}
}
else if ( fieldNeedingOptions == &m_timeStep )
{
options.push_back( caf::PdmOptionItemInfo( "All Time Steps", -1 ) );
RimTools::timeStepsForCase( m_case, &options );
}
else if ( fieldNeedingOptions == &m_cellFilterView )
{
if ( RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( m_case() ) )
{
options.push_back( caf::PdmOptionItemInfo( "Disabled", nullptr ) );
for ( RimEclipseView* view : eclipseCase->reservoirViews() )
{
CVF_ASSERT( view && "Really always should have a valid view pointer in ReservoirViews" );
options.push_back( caf::PdmOptionItemInfo( view->name(), view, false, view->uiIconProvider() ) );
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridStatisticsHistogramDataSource ::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_case );
if ( m_case )
{
uiOrdering.add( &m_timeStep );
uiOrdering.add( &m_cellFilterView );
caf::PdmUiGroup* propertyGroup = uiOrdering.addNewGroup( "Property" );
m_property->uiOrdering( uiConfigName, *propertyGroup );
}
uiOrdering.add( &m_numBins );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGridStatisticsHistogramDataSource::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
if ( changedField == &m_case )
{
if ( RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( m_case.value() ) )
{
m_property->setEclipseCase( eclipseCase );
m_property->updateConnectedEditors();
dataSourceChanged.send();
}
}
else
{
dataSourceChanged.send();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimGridStatisticsHistogramDataSource::unitNameY() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimGridStatisticsHistogramDataSource::unitNameX() const
{
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimGridStatisticsHistogramDataSource::valuesX( RimHistogramPlot::GraphType graphType ) const
{
RigHistogramData histogramData = createStatisticsData();
if ( !histogramData.isHistogramVectorValid() ) return {};
double min = histogramData.min;
double max = histogramData.max;
return computeHistogramBins( min, max, m_numBins, graphType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimGridStatisticsHistogramDataSource::valuesY( RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType ) const
{
RigHistogramData histogramData = createStatisticsData();
if ( !histogramData.isHistogramVectorValid() ) return {};
return computeHistogramFrequencies( histogramData.histogram, graphType, frequencyType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigHistogramData RimGridStatisticsHistogramDataSource::createStatisticsData() const
{
std::unique_ptr<RimHistogramCalculator> histogramCalculator = std::make_unique<RimHistogramCalculator>();
histogramCalculator->setNumBins( static_cast<size_t>( m_numBins() ) );
RimHistogramCalculator::StatisticsCellRangeType cellRange = RimHistogramCalculator::StatisticsCellRangeType::ALL_CELLS;
RimHistogramCalculator::StatisticsTimeRangeType timeRange = RimHistogramCalculator::StatisticsTimeRangeType::ALL_TIMESTEPS;
int timeStep = 0;
if ( m_timeStep() != -1 && !m_property()->hasStaticResult() )
{
timeStep = m_timeStep();
timeRange = RimHistogramCalculator::StatisticsTimeRangeType::CURRENT_TIMESTEP;
}
if ( m_cellFilterView.value() )
{
// Filter by visible cells of the view
cellRange = RimHistogramCalculator::StatisticsCellRangeType::VISIBLE_CELLS;
RimEclipseView* eclipseView = dynamic_cast<RimEclipseView*>( m_cellFilterView.value() );
return histogramCalculator->histogramData( eclipseView, m_property.value(), cellRange, timeRange, timeStep );
}
else
{
RimEclipseView* eclipseView = nullptr;
return histogramCalculator->histogramData( eclipseView, m_property.value(), cellRange, timeRange, timeStep );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimGridStatisticsHistogramDataSource::name() const
{
if ( m_case() == nullptr ) return "Undefined";
QStringList nameTags;
nameTags += m_property()->resultVariable();
nameTags += m_case()->caseUserDescription();
auto createTimeStepString = [this]() -> QString
{
if ( m_case() && m_property->hasDynamicResult() )
{
if ( m_timeStep == -1 ) return "All Time Steps";
return m_case->timeStepStrings()[m_timeStep];
}
return "";
};
QString timeStepStr = createTimeStepString();
if ( !timeStepStr.isEmpty() )
{
nameTags += timeStepStr;
}
return nameTags.join( ", " ).toStdString();
}
@@ -0,0 +1,64 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RigHistogramData.h"
#include "RimHistogramDataSource.h"
#include "cafPdmField.h"
#include "cafPdmPtrField.h"
class RimSummaryEnsemble;
class RimCase;
class RimGridView;
class RimEclipseResultDefinition;
//==================================================================================================
///
///
//==================================================================================================
class RimGridStatisticsHistogramDataSource : public RimHistogramDataSource
{
CAF_PDM_HEADER_INIT;
public:
RimGridStatisticsHistogramDataSource();
~RimGridStatisticsHistogramDataSource() override;
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;
std::string name() const override;
protected:
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
RigHistogramData createStatisticsData() const;
caf::PdmPtrField<RimCase*> m_case;
caf::PdmField<int> m_timeStep;
caf::PdmPtrField<RimGridView*> m_cellFilterView;
caf::PdmChildField<RimEclipseResultDefinition*> m_property;
caf::PdmField<int> m_numBins;
};
@@ -0,0 +1,407 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimHistogramCurve.h"
#include "RiaGuiApplication.h"
#include "RiaPlotDefines.h"
#include "RimHistogramCurveCollection.h"
#include "RimHistogramDataSource.h"
#include "RimHistogramPlot.h"
#include "RimPlotAxisProperties.h"
#include "RimProject.h"
#include "RimTools.h"
#include "RiuPlotAxis.h"
#include "RiuPlotCurve.h"
#include "RiuPlotMainWindow.h"
#include "cafAssert.h"
#include "cafPdmUiTreeOrdering.h"
CAF_PDM_SOURCE_INIT( RimHistogramCurve, "HistogramCurve" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramCurve::RimHistogramCurve()
{
CAF_PDM_InitObject( "Histogram Curve", ":/SummaryCurve16x16.png" );
CAF_PDM_InitFieldNoDefault( &m_yPlotAxisProperties, "YAxis", "Y Axis" );
CAF_PDM_InitFieldNoDefault( &m_xPlotAxisProperties, "XAxis", "X Axis" );
CAF_PDM_InitFieldNoDefault( &m_dataSource, "DataSource", "Data Source" );
m_dataSource.uiCapability()->setUiTreeHidden( true );
setSymbolSkipDistance( 10.0f );
setLineThickness( 2 );
setDeletable( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramCurve::~RimHistogramCurve()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::setTopOrBottomAxisX( RiuPlotAxis plotAxis )
{
CAF_ASSERT( plotAxis.isHorizontal() );
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
m_xPlotAxisProperties = plot->axisPropertiesForPlotAxis( plotAxis );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::setDataSource( RimHistogramDataSource* dataSource )
{
m_dataSource = dataSource;
if ( m_dataSource )
{
m_dataSource->uiCapability()->setUiTreeHidden( true );
m_dataSource->dataSourceChanged.connect( this, &RimHistogramCurve::onDataSourceChanged );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPlotAxis RimHistogramCurve::axisX() const
{
if ( m_xPlotAxisProperties )
return m_xPlotAxisProperties->plotAxis();
else
return RiuPlotAxis::defaultBottom();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimHistogramCurve::unitNameY() const
{
if ( m_dataSource )
return m_dataSource()->unitNameY();
else
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::string RimHistogramCurve::unitNameX() const
{
if ( m_dataSource )
return m_dataSource()->unitNameX();
else
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimHistogramCurve::valuesY() const
{
if ( m_dataSource )
{
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
return m_dataSource()->valuesY( plot->graphType(), plot->frequencyType() );
}
else
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimHistogramCurve::valuesX() const
{
if ( m_dataSource )
{
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
return m_dataSource()->valuesX( plot->graphType() );
}
else
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::setLeftOrRightAxisY( RiuPlotAxis plotAxis )
{
CAF_ASSERT( plotAxis.isVertical() );
RimHistogramPlot* plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
m_yPlotAxisProperties = plot->axisPropertiesForPlotAxis( plotAxis );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPlotAxis RimHistogramCurve::axisY() const
{
if ( m_yPlotAxisProperties )
return m_yPlotAxisProperties->plotAxis();
else
return RiuPlotAxis::defaultLeft();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimHistogramCurve::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options = RimPlotCurve::calculateValueOptions( fieldNeedingOptions );
if ( !options.isEmpty() )
return options;
else if ( fieldNeedingOptions == &m_yPlotAxisProperties )
{
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::VERTICAL ) )
{
options.push_back( caf::PdmOptionItemInfo( axis->objectName(), axis ) );
}
}
else if ( fieldNeedingOptions == &m_xPlotAxisProperties )
{
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::HORIZONTAL ) )
{
options.push_back( caf::PdmOptionItemInfo( axis->objectName(), axis ) );
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimHistogramCurve::createCurveAutoName()
{
QString curveName = "";
if ( m_dataSource )
{
curveName = QString::fromStdString( m_dataSource->name() );
}
if ( curveName.isEmpty() )
{
curveName = "Curve Name Placeholder";
}
return curveName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::updateZoomInParentPlot()
{
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
plot->updatePlotWidgetFromAxisRanges();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::onLoadDataAndUpdate( bool updateParentPlot )
{
RimPlotCurve::updateCurvePresentation( updateParentPlot );
updateConnectedEditors();
if ( isChecked() )
{
std::vector<double> curveValuesX = valuesX();
std::vector<double> curveValuesY = valuesY();
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
bool useLogarithmicScale = plot->isLogarithmicScaleEnabled( axisY() );
setSamplesFromXYValues( curveValuesX, curveValuesY, useLogarithmicScale );
}
if ( updateParentPlot && hasParentPlot() )
{
updateZoomInParentPlot();
replotParentPlot();
}
if ( updateParentPlot ) updatePlotAxis();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::updateLegendsInPlot()
{
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
plot->updateLegend();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/ )
{
RimPlotCurve::defineUiTreeOrdering( uiTreeOrdering, uiConfigName );
caf::IconProvider iconProvider = uiIconProvider();
if ( !iconProvider.valid() ) return;
uiTreeOrdering.skipRemainingChildren( true );
setUiIcon( iconProvider );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
RimPlotCurve::updateFieldUiState();
if ( m_dataSource )
{
caf::PdmUiGroup* dataSourceGroup = uiOrdering.addNewGroup( "Data Source" );
m_dataSource->uiOrdering( uiConfigName, *dataSourceGroup );
}
caf::PdmUiGroup* stackingGroup = uiOrdering.addNewGroup( "Stacking" );
RimStackablePlotCurve::stackingUiOrdering( *stackingGroup );
caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup( "Appearance" );
RimPlotCurve::appearanceUiOrdering( *appearanceGroup );
caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup( "Curve Name" );
nameGroup->setCollapsedByDefault();
nameGroup->add( &m_showLegend );
RimPlotCurve::curveNameUiOrdering( *nameGroup );
uiOrdering.skipRemainingFields();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::updatePlotAxis()
{
updateYAxisInPlot( axisY() );
updateXAxisInPlot( axisX() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
RimStackablePlotCurve::fieldChangedByUi( changedField, oldValue, newValue );
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
bool loadAndUpdate = false;
if ( &m_showCurve == changedField )
{
plot->updateAxes();
plot->updatePlotTitle();
}
else if ( changedField == &m_yPlotAxisProperties )
{
updateYAxisInPlot( axisY() );
plot->updateAxes();
dataChanged.send();
}
else if ( changedField == &m_xPlotAxisProperties )
{
updateXAxisInPlot( axisX() );
plot->updateAxes();
dataChanged.send();
}
if ( loadAndUpdate )
{
loadAndUpdateDataAndPlot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::loadAndUpdateDataAndPlot()
{
loadDataAndUpdate( true );
auto plot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
plot->updateAxes();
plot->updatePlotTitle();
plot->updateConnectedEditors();
RiuPlotMainWindow* mainPlotWindow = RiaGuiApplication::instance()->mainPlotWindow();
mainPlotWindow->updateMultiPlotToolBar();
dataChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::updateLegendEntryVisibilityNoPlotUpdate()
{
if ( !m_plotCurve ) return;
bool showLegendInPlot = m_showLegend();
m_plotCurve->setVisibleInLegend( showLegendInPlot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimHistogramCurve::canCurveBeAttached() const
{
if ( !RimPlotCurve::canCurveBeAttached() ) return false;
bool isVisibleInPossibleParent = true;
auto histogramCurveCollection = firstAncestorOrThisOfType<RimHistogramCurveCollection>();
if ( histogramCurveCollection ) isVisibleInPossibleParent = histogramCurveCollection->isCurvesVisible();
return isVisibleInPossibleParent;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurve::onDataSourceChanged( const caf::SignalEmitter* emitter )
{
loadAndUpdateDataAndPlot();
}
@@ -0,0 +1,87 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPtrField.h"
#include "RimStackablePlotCurve.h"
class RimPlotAxisPropertiesInterface;
class RimHistogramDataSource;
//==================================================================================================
///
///
//==================================================================================================
class RimHistogramCurve : public RimStackablePlotCurve
{
CAF_PDM_HEADER_INIT;
public:
RimHistogramCurve();
~RimHistogramCurve() override;
// Y Axis functions
std::string unitNameY() const;
virtual std::vector<double> valuesY() const;
void setLeftOrRightAxisY( RiuPlotAxis plotAxis );
RiuPlotAxis axisY() const;
// X Axis functions
std::string unitNameX() const;
virtual std::vector<double> valuesX() const;
void setTopOrBottomAxisX( RiuPlotAxis plotAxis );
RiuPlotAxis axisX() const;
void updatePlotAxis();
void updateLegendEntryVisibilityNoPlotUpdate() override;
void setDataSource( RimHistogramDataSource* dataSource );
protected:
// RimPlotCurve overrides
QString createCurveAutoName() override;
void updateZoomInParentPlot() override;
void onLoadDataAndUpdate( bool updateParentPlot ) override;
void loadAndUpdateDataAndPlot();
void updateLegendsInPlot() override;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
bool canCurveBeAttached() const override;
// Overridden PDM methods
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void hideXAxisGroup();
void onDataSourceChanged( const caf::SignalEmitter* emitter );
private:
caf::PdmPtrField<RimPlotAxisPropertiesInterface*> m_yPlotAxisProperties;
caf::PdmPtrField<RimPlotAxisPropertiesInterface*> m_xPlotAxisProperties;
caf::PdmChildField<RimHistogramDataSource*> m_dataSource;
};
@@ -0,0 +1,302 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimHistogramCurveCollection.h"
#include "RimHistogramCurve.h"
#include "RimHistogramPlot.h"
#include "cafPdmFieldReorderCapability.h"
#include "cafPdmUiTreeAttributes.h"
#include "cafPdmUiTreeViewEditor.h"
#include <QKeyEvent>
CAF_PDM_SOURCE_INIT( RimHistogramCurveCollection, "RimHistogramCurveCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramCurveCollection::RimHistogramCurveCollection()
: curvesChanged( this )
{
CAF_PDM_InitObject( "Histogram Curves", ":/HistogramCurveFilter16x16.png" );
CAF_PDM_InitFieldNoDefault( &m_curves, "CollectionCurves", "Curves" );
caf::PdmFieldReorderCapability::addToFieldWithCallback( &m_curves, this, &RimHistogramCurveCollection::onCurvesReordered );
CAF_PDM_InitField( &m_showCurves, "IsActive", true, "Show Curves" );
m_showCurves.uiCapability()->setUiHidden( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimHistogramCurveCollection::isCurvesVisible()
{
return m_showCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::loadDataAndUpdate( bool updateParentPlot )
{
for ( RimHistogramCurve* curve : m_curves )
{
curve->loadDataAndUpdate( false );
curve->updatePlotAxis();
}
if ( updateParentPlot )
{
auto parentPlot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
parentPlot->updateAll();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& updatedObjects )
{
if ( childArray == &m_curves )
{
for ( auto obj : updatedObjects )
{
// Must use firstAncestorOrThisOfType, since we need to update the curve appearance if the object is a child of a
// RimHistogramCurve. This is the case when modifying curve appearance.
if ( auto curve = obj->firstAncestorOrThisOfType<RimHistogramCurve>() )
{
curve->updateCurveAppearance();
}
}
auto parentPlot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
parentPlot->plotWidget()->scheduleReplot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::setParentPlotAndReplot( RiuPlotWidget* plot )
{
setParentPlotNoReplot( plot );
if ( plot ) plot->replot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::setParentPlotNoReplot( RiuPlotWidget* plot )
{
for ( RimHistogramCurve* curve : m_curves )
{
curve->setParentPlotNoReplot( plot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::detachPlotCurves()
{
for ( RimHistogramCurve* curve : m_curves )
{
curve->detach();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::reattachPlotCurves()
{
for ( RimHistogramCurve* curve : m_curves )
{
if ( curve->isChecked() ) curve->reattach();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::addCurve( RimHistogramCurve* curve )
{
if ( curve )
{
m_curves.push_back( curve );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::insertCurve( RimHistogramCurve* curve, size_t index )
{
if ( index >= m_curves.size() )
{
m_curves.push_back( curve );
}
else
{
m_curves.insert( index, curve );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::deleteCurve( RimHistogramCurve* curve )
{
removeCurve( curve );
if ( curve )
{
delete curve;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::removeCurve( RimHistogramCurve* curve )
{
if ( curve )
{
m_curves.removeChild( curve );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimHistogramCurve*> RimHistogramCurveCollection::curves() const
{
return m_curves.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::deleteAllCurves()
{
m_curves.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::updateCaseNameHasChanged()
{
for ( RimHistogramCurve* curve : m_curves )
{
curve->updateCurveNameNoLegendUpdate();
curve->updateConnectedEditors();
}
auto parentPlot = firstAncestorOrThisOfTypeAsserted<RimHistogramPlot>();
parentPlot->updatePlotTitle();
if ( parentPlot->plotWidget() ) parentPlot->plotWidget()->updateLegend();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::setCurrentHistogramCurve( RimHistogramCurve* curve )
{
m_currentHistogramCurve = curve;
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::PdmFieldHandle*> RimHistogramCurveCollection::fieldsToShowInToolbar()
{
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_showCurves )
{
loadDataAndUpdate( true );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::onCurvesReordered( const SignalEmitter* emitter )
{
updateCurveOrder();
curvesChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& referringObjects )
{
curvesChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimHistogramCurveCollection::objectToggleField()
{
return &m_showCurves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
caf::PdmUiTreeViewEditorAttribute* myAttr = dynamic_cast<caf::PdmUiTreeViewEditorAttribute*>( attribute );
if ( myAttr && m_currentHistogramCurve.notNull() )
{
myAttr->currentObject = m_currentHistogramCurve.p();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramCurveCollection::updateCurveOrder()
{
detachPlotCurves();
reattachPlotCurves();
}
@@ -0,0 +1,91 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmChildArrayField.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
class RimHistogramPlot;
class RimHistogramCurve;
class RiuPlotWidget;
class RiuPlotCurve;
class QKeyEvent;
//==================================================================================================
///
//==================================================================================================
class RimHistogramCurveCollection : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
private:
caf::Signal<> curvesChanged;
public:
RimHistogramCurveCollection();
bool isCurvesVisible();
std::vector<RimHistogramCurve*> curves() const;
void loadDataAndUpdate( bool updateParentPlot );
void updateCurveOrder();
private:
void setParentPlotAndReplot( RiuPlotWidget* plot );
void setParentPlotNoReplot( RiuPlotWidget* plot );
void detachPlotCurves();
void reattachPlotCurves();
void addCurve( RimHistogramCurve* curve );
void insertCurve( RimHistogramCurve* curve, size_t index );
void deleteCurve( RimHistogramCurve* curve );
void removeCurve( RimHistogramCurve* curve );
void deleteAllCurves();
void updateCaseNameHasChanged();
void setCurrentHistogramCurve( RimHistogramCurve* curve );
std::vector<caf::PdmFieldHandle*> fieldsToShowInToolbar();
private:
caf::PdmFieldHandle* objectToggleField() override;
void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void onCurvesReordered( const SignalEmitter* emitter );
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
void onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& updatedObjects ) override;
private:
friend class RimHistogramPlot;
caf::PdmField<bool> m_showCurves;
caf::PdmChildArrayField<RimHistogramCurve*> m_curves;
caf::PdmPointer<RimHistogramCurve> m_currentHistogramCurve;
};
@@ -0,0 +1,99 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimHistogramDataSource.h"
CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimHistogramDataSource, "HistogramDataSource" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramDataSource::RimHistogramDataSource()
: dataSourceChanged( this )
{
CAF_PDM_InitObject( "Histogram Data Source", );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramDataSource::~RimHistogramDataSource()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimHistogramDataSource::computeHistogramBins( double min, double max, int numBins, RimHistogramPlot::GraphType graphType )
{
const double binSize = ( max - min ) / numBins;
std::vector<double> values;
for ( int i = 0; i < numBins; i++ )
{
if ( graphType == RimHistogramPlot::GraphType::BAR_GRAPH )
{
values.push_back( min + binSize * i );
values.push_back( min + binSize * ( i + 1 ) );
}
else if ( graphType == RimHistogramPlot::GraphType::LINE_GRAPH )
{
double centerOfBin = min + binSize * i + binSize / 2.0;
values.push_back( centerOfBin );
}
}
return values;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimHistogramDataSource::computeHistogramFrequencies( const std::vector<size_t>& values,
RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType )
{
std::vector<double> valuesAsDouble( values.begin(), values.end() );
return computeHistogramFrequencies( valuesAsDouble, graphType, frequencyType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimHistogramDataSource::computeHistogramFrequencies( const std::vector<double>& values,
RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType )
{
double sumElements = 0.0;
for ( double value : values )
sumElements += value;
std::vector<double> frequencies;
for ( double frequency : values )
{
double value = frequency;
if ( frequencyType == RimHistogramPlot::FrequencyType::RELATIVE_FREQUENCY ) value /= sumElements;
if ( frequencyType == RimHistogramPlot::FrequencyType::RELATIVE_FREQUENCY_PERCENT ) value = value / sumElements * 100.0;
frequencies.push_back( value );
if ( graphType == RimHistogramPlot::GraphType::BAR_GRAPH )
{
frequencies.push_back( value );
}
}
return frequencies;
}
@@ -0,0 +1,55 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimHistogramPlot.h"
#include "cafPdmObject.h"
#include "cafSignal.h"
//==================================================================================================
///
///
//==================================================================================================
class RimHistogramDataSource : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimHistogramDataSource();
~RimHistogramDataSource() override;
caf::Signal<> dataSourceChanged;
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 std::string name() const = 0;
static std::vector<double> computeHistogramBins( double min, double max, int numBins, RimHistogramPlot::GraphType graphType );
static std::vector<double> computeHistogramFrequencies( const std::vector<size_t>& values,
RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType );
static std::vector<double> computeHistogramFrequencies( const std::vector<double>& values,
RimHistogramPlot::GraphType graphType,
RimHistogramPlot::FrequencyType frequencyType );
};
@@ -0,0 +1,614 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimHistogramMultiPlot.h"
#include "RiaNumericalTools.h"
#include "RiaPlotDefines.h"
#include "RimEnsembleCurveSet.h"
#include "RimHistogramPlot.h"
#include "RimMainPlotCollection.h"
#include "RimMultiPlotCollection.h"
#include "RimPlotAxisProperties.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuQwtPlotWidget.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiPushButtonEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "qwt_scale_engine.h"
#include <QKeyEvent>
#include <cmath>
CAF_PDM_SOURCE_INIT( RimHistogramMultiPlot, "MultiHistogramPlot" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlot::RimHistogramMultiPlot()
: duplicatePlot( this )
{
CAF_PDM_InitObject( "Multi Histogram Plot", ":/HistogramPlotLight16x16.png" );
setDeletable( true );
CAF_PDM_InitField( &m_autoPlotTitle, "AutoPlotTitle", true, "Auto Plot Title" );
CAF_PDM_InitField( &m_autoSubPlotTitle, "AutoSubPlotTitle", true, "Auto Sub Plot Title" );
CAF_PDM_InitField( &m_createPlotDuplicate, "DuplicatePlot", false, "", "", "Duplicate Plot" );
caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_createPlotDuplicate );
m_createPlotDuplicate.uiCapability()->setUiIconFromResourceString( ":/Copy.svg" );
CAF_PDM_InitField( &m_disableWheelZoom, "DisableWheelZoom", true, "", "", "Disable Mouse Wheel Zooming in Multi Histogram Plot" );
caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_disableWheelZoom );
m_disableWheelZoom.uiCapability()->setUiIconFromResourceString( ":/DisableZoom.png" );
CAF_PDM_InitField( &m_autoAdjustAppearance, "AutoAdjustAppearance", true, "Auto Plot Settings" );
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_autoAdjustAppearance );
CAF_PDM_InitField( &m_allow3DSelectionLink, "Allow3DSelectionLink", true, "Allow Well Selection from 3D View" );
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_allow3DSelectionLink );
CAF_PDM_InitField( &m_hidePlotsWithValuesBelow, "HidePlotsWithValuesBelow", false, "" );
caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_hidePlotsWithValuesBelow );
setBottomMargin( 40 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlot::~RimHistogramMultiPlot()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::addPlot( RimPlot* plot )
{
auto* sumPlot = dynamic_cast<RimHistogramPlot*>( plot );
CVF_ASSERT( sumPlot != nullptr );
if ( sumPlot )
{
RimMultiPlot::addPlot( plot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::insertPlot( RimPlot* plot, size_t index )
{
auto* sumPlot = dynamic_cast<RimHistogramPlot*>( plot );
CVF_ASSERT( sumPlot != nullptr );
if ( sumPlot )
{
sumPlot->curvesChanged.connect( this, &RimHistogramMultiPlot::onSubPlotChanged );
sumPlot->titleChanged.connect( this, &RimHistogramMultiPlot::onSubPlotChanged );
sumPlot->autoTitleChanged.connect( this, &RimHistogramMultiPlot::onSubPlotAutoTitleChanged );
RimMultiPlot::insertPlot( plot, index );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::removePlot( RimPlot* plot )
{
auto* sumPlot = dynamic_cast<RimHistogramPlot*>( plot );
CVF_ASSERT( sumPlot != nullptr );
if ( sumPlot )
{
RimMultiPlot::removePlot( plot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::removePlotNoUpdate( RimPlot* plot )
{
auto* sumPlot = dynamic_cast<RimHistogramPlot*>( plot );
CVF_ASSERT( sumPlot != nullptr );
if ( sumPlot )
{
RimMultiPlot::removePlotNoUpdate( plot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::updateAfterPlotRemove()
{
onPlotAdditionOrRemoval();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
auto titlesGroup = uiOrdering.addNewGroup( "Main Plot Settings" );
titlesGroup->setCollapsedByDefault();
// If a checkbox is first in the group, it is not responding to mouse clicks. Set title as first element.
// https://github.com/OPM/ResInsight/issues/10321
titlesGroup->add( &m_plotWindowTitle );
titlesGroup->add( &m_autoPlotTitle );
titlesGroup->add( &m_showPlotWindowTitle );
titlesGroup->add( &m_titleFontSize );
auto subPlotSettingsGroup = uiOrdering.addNewGroup( "Sub Plot Settings" );
subPlotSettingsGroup->setCollapsedByDefault();
subPlotSettingsGroup->add( &m_autoSubPlotTitle );
subPlotSettingsGroup->add( &m_showIndividualPlotTitles );
subPlotSettingsGroup->add( &m_subTitleFontSize );
auto legendsGroup = uiOrdering.addNewGroup( "Legends" );
legendsGroup->setCollapsedByDefault();
legendsGroup->add( &m_showPlotLegends );
legendsGroup->add( &m_plotLegendsHorizontal );
legendsGroup->add( &m_legendPosition );
legendsGroup->add( &m_legendFontSize );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_autoPlotTitle || changedField == &m_autoSubPlotTitle )
{
onLoadDataAndUpdate();
updateLayout();
}
else if ( changedField == &m_hidePlotsWithValuesBelow )
{
m_hidePlotsWithValuesBelow = false;
updatePlotVisibility();
}
else if ( changedField == &m_createPlotDuplicate )
{
m_createPlotDuplicate = false;
duplicate();
}
else if ( changedField == &m_autoAdjustAppearance )
{
analyzePlotsAndAdjustAppearanceSettings();
}
else if ( changedField == &m_plotWindowTitle )
{
// If the user has changed the plot title, disable the auto plot title
// Workaround for https://github.com/OPM/ResInsight/issues/9681
m_autoPlotTitle = false;
}
RimMultiPlot::fieldChangedByUi( changedField, oldValue, newValue );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::updatePlotTitles()
{
if ( m_autoPlotTitle )
{
auto collection = RimMainPlotCollection::current()->histogramMultiPlotCollection();
size_t index = 0;
for ( auto p : collection->histogramMultiPlots() )
{
index++;
if ( p == this ) break;
}
QString title = QString( "Plot %1" ).arg( index );
setMultiPlotTitle( title );
}
if ( !m_viewer.isNull() ) m_viewer->scheduleTitleUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::setAutoPlotTitle( bool enable )
{
m_autoPlotTitle = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::setAutoSubPlotTitle( bool enable )
{
m_autoSubPlotTitle = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimHistogramPlot*> RimHistogramMultiPlot::histogramPlots() const
{
std::vector<RimHistogramPlot*> typedPlots;
for ( auto plot : plots() )
{
auto histogramPlot = dynamic_cast<RimHistogramPlot*>( plot );
if ( histogramPlot ) typedPlots.push_back( histogramPlot );
}
return typedPlots;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimHistogramPlot*> RimHistogramMultiPlot::visibleHistogramPlots() const
{
std::vector<RimHistogramPlot*> visiblePlots;
for ( auto plot : histogramPlots() )
{
if ( plot->showWindow() ) visiblePlots.push_back( plot );
}
return visiblePlots;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimHistogramMultiPlot::handleGlobalKeyEvent( QKeyEvent* keyEvent )
{
if ( isMouseCursorInsidePlot() )
{
if ( keyEvent->key() == Qt::Key_PageUp )
{
m_viewer->goToPrevPage();
return true;
}
if ( keyEvent->key() == Qt::Key_PageDown )
{
m_viewer->goToNextPage();
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimHistogramMultiPlot::handleGlobalWheelEvent( QWheelEvent* wheelEvent )
{
if ( m_disableWheelZoom )
{
if ( isMouseCursorInsidePlot() )
{
if ( wheelEvent->angleDelta().y() > 0 )
{
m_viewer->goToPrevPage();
}
else if ( wheelEvent->angleDelta().y() < 0 )
{
m_viewer->goToNextPage();
}
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::initAfterRead()
{
RimMultiPlot::initAfterRead();
for ( auto plot : histogramPlots() )
{
plot->curvesChanged.connect( this, &RimHistogramMultiPlot::onSubPlotChanged );
plot->titleChanged.connect( this, &RimHistogramMultiPlot::onSubPlotChanged );
plot->autoTitleChanged.connect( this, &RimHistogramMultiPlot::onSubPlotAutoTitleChanged );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::onLoadDataAndUpdate()
{
RimMultiPlot::onLoadDataAndUpdate();
updatePlotTitles();
for ( auto p : histogramPlots() )
{
p->updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::zoomAll()
{
// Reset zoom to make sure the complete range for min/max is available
RimMultiPlot::zoomAll();
syncAxisRanges();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::syncAxisRanges()
{
// Reset zoom for axes with no custom range set to make sure the complete range for min/max is available
for ( auto p : histogramPlots() )
{
for ( auto ax : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
{
ax->setAutoZoomIfNoCustomRangeIsSet();
}
}
updateZoom();
std::map<QString, std::pair<double, double>> axisRanges;
// gather current min/max values for each category (axis label)
for ( auto plot : histogramPlots() )
{
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
{
double minVal = axis->visibleRangeMin();
double maxVal = axis->visibleRangeMax();
if ( axis->isAxisInverted() ) std::swap( minVal, maxVal );
auto key = axis->objectName();
if ( axisRanges.count( key ) == 0 )
{
axisRanges[key] = std::make_pair( minVal, maxVal );
}
else
{
auto& [currentMin, currentMax] = axisRanges[key];
axisRanges[key] = std::make_pair( std::min( currentMin, minVal ), std::max( currentMax, maxVal ) );
}
}
}
// set all plots to use the global min/max values for each category
for ( auto plot : histogramPlots() )
{
for ( auto axis : plot->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
{
auto [minVal, maxVal] = axisRanges[axis->objectName()];
if ( axis->isAxisInverted() ) std::swap( minVal, maxVal );
axis->setAutoZoom( false );
axis->setAutoValueVisibleRangeMin( minVal );
axis->setAutoValueVisibleRangeMax( maxVal );
}
plot->updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::updatePlotVisibility()
{
for ( auto plot : histogramPlots() )
{
plot->setShowWindow( true );
}
updateLayout();
if ( !m_viewer.isNull() ) m_viewer->scheduleUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::duplicate()
{
duplicatePlot.send( this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::analyzePlotsAndAdjustAppearanceSettings()
{
if ( m_autoAdjustAppearance )
{
// Required to sync axis ranges before computing the auto scale
syncAxisRanges();
const bool notifyFieldChanged = false;
for ( auto p : histogramPlots() )
{
for ( auto* axisProp : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
{
auto tickMarkCount = ( rowsPerPage() == 1 ) ? RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_DEFAULT
: RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_FEW;
axisProp->setAutoValueForMajorTickmarkCount( tickMarkCount, notifyFieldChanged );
axisProp->computeAndSetAutoValueForScaleFactor();
auto [row, col] = gridLayoutInfoForSubPlot( p );
bool isFirstColumn = ( col == 0 );
axisProp->setShowUnitText( isFirstColumn );
axisProp->setShowDescription( isFirstColumn );
}
p->updateAxes();
}
}
else
{
for ( auto p : histogramPlots() )
{
for ( auto* axisProp : p->plotAxes( RimPlotAxisProperties::Orientation::ANY ) )
{
axisProp->computeAndSetAutoValueForScaleFactor();
axisProp->setShowUnitText( true );
axisProp->setShowDescription( true );
}
p->updateAxes();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::makeSureIsVisible( RimHistogramPlot* histogramPlot )
{
if ( histogramPlot->plotWidget() && !m_viewer.isNull() ) m_viewer->scrollToPlot( histogramPlot->plotWidget() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<int, int> RimHistogramMultiPlot::gridLayoutInfoForSubPlot( RimHistogramPlot* histogramPlot ) const
{
auto it = m_gridLayoutInfo.find( histogramPlot );
if ( it != m_gridLayoutInfo.end() ) return it->second;
return { -1, -1 };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::setLayoutInfo( RimHistogramPlot* histogramPlot, int row, int col )
{
m_gridLayoutInfo[histogramPlot] = std::make_pair( row, col );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::clearLayoutInfo()
{
m_gridLayoutInfo.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::onSubPlotChanged( const caf::SignalEmitter* emitter )
{
updatePlotTitles();
applyPlotWindowTitleToWidgets();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::onSubPlotAutoTitleChanged( const caf::SignalEmitter* emitter, bool isEnabled )
{
m_autoSubPlotTitle = isEnabled;
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<double, double> RimHistogramMultiPlot::adjustedMinMax( const RimPlotAxisProperties* axis, double min, double max ) const
{
if ( !axis->isLogarithmicScaleEnabled() )
{
int maxMajorTickIntervalCount = RimPlotAxisProperties::tickmarkCountFromEnum( axis->majorTickmarkCount() );
double stepSize = 0.0;
QwtLinearScaleEngine scaleEngine;
// Do not adjust minimum value, as we usually want to keep zero unchanged
double adjustedMin = min;
// Adjust the max value to get some space between the top of the plot and the top of the curve
double adjustedMax = max * 1.05;
scaleEngine.autoScale( maxMajorTickIntervalCount, adjustedMin, adjustedMax, stepSize );
return { adjustedMin, adjustedMax };
}
auto adjustedMin = RiaNumericalTools::roundToClosestPowerOfTenFloor( min );
auto adjustedMax = RiaNumericalTools::roundToClosestPowerOfTenCeil( max );
return { adjustedMin, adjustedMax };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* RimHistogramMultiPlot::createViewWidget( QWidget* mainWindowParent )
{
if ( m_viewer.isNull() )
{
m_viewer = new RiuMultiPlotBook( this, mainWindowParent );
}
recreatePlotWidgets();
return m_viewer;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::onPlotAdditionOrRemoval()
{
m_disableWheelZoom = ( histogramPlots().size() > 1 );
RimMultiPlot::onPlotAdditionOrRemoval();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlot::keepVisiblePageAfterUpdate( bool keepPage )
{
if ( !m_viewer ) return;
if ( keepPage ) m_viewer->keepCurrentPageAfterUpdate();
}
@@ -0,0 +1,127 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimMultiPlot.h"
#include "cafPdmObject.h"
#include "cafPdmUiItem.h"
#include "cafSignal.h"
#include <QList>
#include <vector>
class RimHistogramPlot;
class RimPlotAxisProperties;
//==================================================================================================
///
///
//==================================================================================================
class RimHistogramMultiPlot : public RimMultiPlot
{
CAF_PDM_HEADER_INIT;
public:
caf::Signal<RimHistogramMultiPlot*> duplicatePlot;
public:
RimHistogramMultiPlot();
~RimHistogramMultiPlot() override;
void setLayoutInfo( RimHistogramPlot* histogramPlot, int row, int col );
void clearLayoutInfo();
void setAutoPlotTitle( bool enable );
void setAutoSubPlotTitle( bool enable );
void addPlot( RimPlot* plot ) override;
void insertPlot( RimPlot* plot, size_t index ) override;
void removePlot( RimPlot* plot ) override;
void removePlotNoUpdate( RimPlot* plot ) override;
void updateAfterPlotRemove() override;
void updatePlotTitles() override;
void syncAxisRanges();
void histogramPlotItemInfos( QList<caf::PdmOptionItemInfo>* optionInfos ) const;
std::vector<RimHistogramPlot*> histogramPlots() const;
std::vector<RimHistogramPlot*> visibleHistogramPlots() const;
void makeSureIsVisible( RimHistogramPlot* plot );
void setSubPlotAxesLinked( bool enable );
bool isSubPlotAxesLinked() const;
std::pair<int, int> gridLayoutInfoForSubPlot( RimHistogramPlot* histogramPlot ) const;
void zoomAll() override;
void setDefaultRangeAggregationSteppingDimension();
void analyzePlotsAndAdjustAppearanceSettings();
void keepVisiblePageAfterUpdate( bool keepPage );
protected:
bool handleGlobalKeyEvent( QKeyEvent* keyEvent ) override;
bool handleGlobalWheelEvent( QWheelEvent* wheelEvent ) override;
void initAfterRead() override;
void onLoadDataAndUpdate() override;
QWidget* createViewWidget( QWidget* mainWindowParent ) override;
void onPlotAdditionOrRemoval() override;
private:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void computeAggregatedAxisRange();
void updateSourceStepper();
void updatePlotVisibility();
void duplicate();
void appendSubPlotByStepping( int direction );
void appendCurveByStepping( int direction );
void onSubPlotChanged( const caf::SignalEmitter* emitter );
void onSubPlotAutoTitleChanged( const caf::SignalEmitter* emitter, bool isEnabled );
std::pair<double, double> adjustedMinMax( const RimPlotAxisProperties* axis, double min, double max ) const;
private:
caf::PdmField<bool> m_autoPlotTitle;
caf::PdmField<bool> m_autoSubPlotTitle;
caf::PdmField<bool> m_disableWheelZoom;
caf::PdmField<bool> m_createPlotDuplicate;
caf::PdmField<bool> m_autoAdjustAppearance;
caf::PdmField<bool> m_allow3DSelectionLink;
caf::PdmField<bool> m_hidePlotsWithValuesBelow;
caf::PdmField<double> m_plotFilterYAxisThreshold;
std::map<RimHistogramPlot*, std::pair<int, int>> m_gridLayoutInfo;
};
@@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimHistogramMultiPlotCollection.h"
#include "RimHistogramMultiPlot.h"
#include "RimMainPlotCollection.h"
#include "RimProject.h"
#include "cafCmdFeatureMenuBuilder.h"
CAF_PDM_SOURCE_INIT( RimHistogramMultiPlotCollection, "RimHistogramMultiPlotCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlotCollection::RimHistogramMultiPlotCollection()
{
CAF_PDM_InitObject( "Histogram Plots", ":/MultiPlot16x16.png" );
CAF_PDM_InitFieldNoDefault( &m_histogramMultiPlots, "HistogramMultiPlots", "Histogram Plots" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlotCollection* RimHistogramMultiPlotCollection::instance()
{
return RimProject::current()->mainPlotCollection()->histogramMultiPlotCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlot* RimHistogramMultiPlotCollection::appendHistogramMultiPlot()
{
auto* histogramMultiPlot = new RimHistogramMultiPlot();
m_histogramMultiPlots.push_back( histogramMultiPlot );
return histogramMultiPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimHistogramMultiPlot*> RimHistogramMultiPlotCollection::histogramMultiPlots() const
{
return m_histogramMultiPlots.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlotCollection::loadDataAndUpdateAllPlots()
{
for ( auto plot : histogramMultiPlots() )
{
plot->loadDataAndUpdateAllPlots();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlotCollection::deleteAllPlots()
{
m_histogramMultiPlots.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimHistogramMultiPlotCollection::plotCount() const
{
return m_histogramMultiPlots.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimHistogramMultiPlotCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder.addCmdFeature( "RicNewHistogramMultiPlotFeature", "New Histogram Plot" );
}
@@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimAbstractPlotCollection.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
class RimHistogramMultiPlot;
//==================================================================================================
///
///
//==================================================================================================
class RimHistogramMultiPlotCollection : public caf::PdmObject, public RimPlotCollection
{
CAF_PDM_HEADER_INIT;
public:
RimHistogramMultiPlotCollection();
static RimHistogramMultiPlotCollection* instance();
RimHistogramMultiPlot* appendHistogramMultiPlot();
std::vector<RimHistogramMultiPlot*> histogramMultiPlots() const;
void loadDataAndUpdateAllPlots() override;
size_t plotCount() const override;
void deleteAllPlots() override;
private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
private:
caf::PdmChildArrayField<RimHistogramMultiPlot*> m_histogramMultiPlots;
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,236 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDateTimeDefines.h"
#include "RiaPlotDefines.h"
#include "RimPlot.h"
#include "RimPlotAxisProperties.h"
#include "RiuPlotWidget.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmObjectHandle.h"
#include <QPointer>
#include <memory>
#include <vector>
class RimHistogramCurve;
class RimHistogramCurveCollection;
class RimPlotAxisPropertiesInterface;
class RimPlotAxisProperties;
class RimPlotTemplateFileItem;
class RimStackablePlotCurve;
class PdmUiTreeOrdering;
class QwtInterval;
class QwtPlotCurve;
class QwtPlotTextLabel;
class QKeyEvent;
//==================================================================================================
///
///
//==================================================================================================
class RimHistogramPlot : public RimPlot
{
Q_OBJECT;
CAF_PDM_HEADER_INIT;
public:
caf::Signal<> curvesChanged;
caf::Signal<RimHistogramPlot*> axisChanged;
caf::Signal<> titleChanged;
caf::Signal<RimHistogramPlot*> axisChangedReloadRequired;
caf::Signal<bool> autoTitleChanged;
public:
enum class FrequencyType
{
ABSOLUTE_FREQUENCY,
RELATIVE_FREQUENCY,
RELATIVE_FREQUENCY_PERCENT
};
enum class GraphType
{
BAR_GRAPH,
LINE_GRAPH
};
RimHistogramPlot();
~RimHistogramPlot() override;
void setDescription( const QString& description );
QString description() const override;
void enableAutoPlotTitle( bool enable );
bool autoPlotTitle() const;
void addCurveNoUpdate( RimHistogramCurve* curve, bool autoAssignPlotAxis = true );
size_t curveCount() const;
void detachAllCurves() override;
void reattachAllCurves() override;
void updateAxes() override;
bool isLogarithmicScaleEnabled( RiuPlotAxis plotAxis ) const;
bool isCurveHighlightSupported() const override;
QWidget* viewWidget() override;
QString asciiDataForPlotExport() const override;
QString asciiDataForHistogramPlotExport( RiaDefines::DateTimePeriod resamplingPeriod, bool showTimeAsLongString ) const;
FrequencyType frequencyType() const;
GraphType graphType() const;
void updatePlotTitle();
void updateCurveNames();
void copyMatchingAxisPropertiesFromOther( const RimHistogramPlot& sourceHistogramPlot );
void updateAll();
void updateLegend() override;
void setLegendPosition( RiuPlotWidget::Legend position );
void showPlotInfoLabel( bool show );
void updatePlotInfoLabel();
void applyDefaultCurveAppearances();
void setNormalizationEnabled( bool enable );
bool isNormalizationEnabled();
void setAutoScaleXEnabled( bool enabled ) override;
void setAutoScaleYEnabled( bool enabled ) override;
RiuPlotWidget* plotWidget() override;
void zoomAll() override;
void updatePlotWidgetFromAxisRanges() override;
void updateAxisRangesFromPlotWidget() override;
void onAxisSelected( RiuPlotAxis axis, bool toggle ) override;
std::vector<RimPlotAxisProperties*> plotAxes( RimPlotAxisProperties::Orientation orientation ) const;
RimPlotAxisPropertiesInterface* axisPropertiesForPlotAxis( RiuPlotAxis plotAxis ) const;
RimPlotAxisProperties* addNewAxisProperties( RiaDefines::PlotAxis, const QString& name );
RimPlotAxisProperties* addNewAxisProperties( RiuPlotAxis plotAxis, const QString& name );
std::vector<RimPlotCurve*> visibleCurvesForLegend() override;
void scheduleReplotIfVisible();
public:
// RimViewWindow overrides
void deleteViewWidget() override;
bool isDeletable() const override;
caf::PdmFieldHandle* userDescriptionField() override;
void zoomAllForMultiPlot() override;
private:
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent = nullptr ) override;
void doUpdateLayout() override;
void detachAllPlotItems();
void deleteAllPlotCurves();
void onCurveCollectionChanged( const SignalEmitter* emitter );
void onPlotItemSelected( std::shared_ptr<RiuPlotItem> plotItem, bool toggle, int sampleIndex ) override;
void connectCurveToPlot( RimHistogramCurve* curve, bool update, bool autoAssignPlotAxis );
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void onLoadDataAndUpdate() override;
QImage snapshotWindowContent() override;
private slots:
void onPlotZoomed();
void onUpdateCurveOrder();
private:
void updateNumericalAxis( RiaDefines::PlotAxis plotAxis );
void updateZoomForAxis( RimPlotAxisPropertiesInterface* axisProperties );
void updateZoomForNumericalAxis( RimPlotAxisProperties* axisProperties );
void deletePlotCurvesAndPlotWidget();
void connectCurveSignals( RimStackablePlotCurve* curve );
void disconnectCurveSignals( RimStackablePlotCurve* curve );
void curveDataChanged( const caf::SignalEmitter* emitter );
void curveVisibilityChanged( const caf::SignalEmitter* emitter, bool visible );
void curveAppearanceChanged( const caf::SignalEmitter* emitter );
void curveStackingChanged( const caf::SignalEmitter* emitter, bool stacked );
void curveStackingColorsChanged( const caf::SignalEmitter* emitter, bool stackWithPhaseColors );
void connectAxisSignals( RimPlotAxisProperties* axis );
void axisSettingsChanged( const caf::SignalEmitter* emitter );
void axisLogarithmicChanged( const caf::SignalEmitter* emitter, bool isLogarithmic );
void axisPositionChanged( const caf::SignalEmitter* emitter,
RimPlotAxisProperties* axisProperties,
RiuPlotAxis oldPlotAxis,
RiuPlotAxis newPlotAxis );
std::vector<RimPlotAxisPropertiesInterface*> allPlotAxes() const;
std::vector<RimHistogramCurve*> histogramCurves() const;
std::vector<RimHistogramCurve*> visibleHistogramCurvesForAxis( RiuPlotAxis plotAxis ) const;
void assignPlotAxis( RimHistogramCurve* curve );
void updateStackedCurveData();
private:
caf::PdmField<bool> m_normalizeCurveYValues;
caf::PdmField<bool> m_useAutoPlotTitle;
caf::PdmField<QString> m_description;
caf::PdmField<QString> m_fallbackPlotName;
caf::PdmChildField<RimHistogramCurveCollection*> m_histogramCurveCollection;
caf::PdmChildArrayField<RimPlotAxisPropertiesInterface*> m_axisPropertiesArray;
caf::PdmField<caf::AppEnum<FrequencyType>> m_histogramFrequencyType;
caf::PdmField<caf::AppEnum<GraphType>> m_graphType;
std::unique_ptr<RiuPlotWidget> m_histogramPlot;
bool m_isValid;
RiuPlotWidget::Legend m_legendPosition;
};
@@ -25,6 +25,8 @@
#include "ContourMap/RimEclipseContourMapViewCollection.h"
#include "Formations/RimFormationNames.h"
#include "Formations/RimFormationNamesCollection.h"
#include "Histogram/RimHistogramMultiPlot.h"
#include "Histogram/RimHistogramPlot.h"
#include "PlotTemplates/RimPlotTemplateFileItem.h"
#include "PlotTemplates/RimPlotTemplateFolderItem.h"
#include "Rim3dOverlayInfoConfig.h"
@@ -992,6 +994,25 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
menuBuilder << "RicSaveMultiPlotTemplateFeature";
menuBuilder << "RicPasteSummaryMultiPlotFeature";
}
else if ( dynamic_cast<RimHistogramMultiPlot*>( firstUiItem ) )
{
menuBuilder << "RicNewDefaultHistogramPlotFeature";
}
else if ( dynamic_cast<RimHistogramPlot*>( firstUiItem ) )
{
menuBuilder.subMenuStart( "New Histogram Curve" );
// TODO: make an enum of these?
std::vector<QString> curveTypes = { "Ensemble Parameter", "Grid Statistics", "Summary Vector" };
for ( const QString& curveType : curveTypes )
{
QString menuText = curveType;
menuBuilder.addCmdFeatureWithUserData( "RicNewHistogramCurveFeature", menuText, QVariant( curveType ) );
}
menuBuilder.subMenuEnd();
}
else if ( dynamic_cast<RimMultiPlot*>( firstUiItem ) )
{
menuBuilder << "RicSnapshotViewToPdfFeature";
@@ -23,6 +23,7 @@
#include "Summary/RiaSummaryDefines.h"
#include "Summary/RiaSummaryPlotTools.h"
#include "Histogram/RimHistogramMultiPlotCollection.h"
#include "RimAbstractPlotCollection.h"
#include "RimAnalysisPlotCollection.h"
#include "RimCorrelationPlotCollection.h"
@@ -109,6 +110,9 @@ RimMainPlotCollection::RimMainPlotCollection()
CAF_PDM_InitFieldNoDefault( &m_stimPlanModelPlotCollection, "StimPlanModelPlotCollection", "" );
CAF_PDM_InitFieldNoDefault( &m_vfpPlotCollection, "VfpPlotCollection", "" );
CAF_PDM_InitFieldNoDefault( &m_histogramMultiPlotCollection, "HistogramMultiPlotCollection", "" );
#ifdef USE_QTCHARTS
CAF_PDM_InitFieldNoDefault( &m_gridStatisticsPlotCollection, "GridStatisticsPlotCollection", "" );
@@ -129,6 +133,7 @@ RimMainPlotCollection::RimMainPlotCollection()
m_correlationPlotCollection = new RimCorrelationPlotCollection;
m_stimPlanModelPlotCollection = new RimStimPlanModelPlotCollection;
m_vfpPlotCollection = new RimVfpPlotCollection();
m_histogramMultiPlotCollection = new RimHistogramMultiPlotCollection();
#ifdef USE_QTCHARTS
m_gridStatisticsPlotCollection = new RimGridStatisticsPlotCollection;
m_ensembleFractureStatisticsPlotCollection = new RimEnsembleFractureStatisticsPlotCollection;
@@ -325,6 +330,14 @@ RimStimPlanModelPlotCollection* RimMainPlotCollection::stimPlanModelPlotCollecti
return m_stimPlanModelPlotCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimHistogramMultiPlotCollection* RimMainPlotCollection::histogramMultiPlotCollection() const
{
return m_histogramMultiPlotCollection();
}
#ifdef USE_QTCHARTS
//--------------------------------------------------------------------------------------------------
///
@@ -494,6 +507,7 @@ std::vector<RimPlotCollection*> RimMainPlotCollection::allPlotCollections() cons
plotCollections.push_back( correlationPlotCollection() );
plotCollections.push_back( saturationPressurePlotCollection() );
plotCollections.push_back( multiPlotCollection() );
plotCollections.push_back( histogramMultiPlotCollection() );
#ifdef USE_QTCHARTS
plotCollections.push_back( gridStatisticsPlotCollection() );
@@ -19,6 +19,7 @@
#pragma once
#include "Histogram/RimHistogramMultiPlotCollection.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
@@ -44,6 +45,7 @@ class RimSaturationPressurePlotCollection;
class RimStimPlanModelPlotCollection;
class RimVfpPlotCollection;
class RimPlotCollection;
class RimHistogramMultiPlotCollection;
#ifdef USE_QTCHARTS
class RimGridStatisticsPlotCollection;
@@ -77,6 +79,7 @@ public:
RimMultiPlotCollection* multiPlotCollection() const;
RimStimPlanModelPlotCollection* stimPlanModelPlotCollection() const;
RimVfpPlotCollection* vfpPlotCollection() const;
RimHistogramMultiPlotCollection* histogramMultiPlotCollection() const;
#ifdef USE_QTCHARTS
RimGridStatisticsPlotCollection* gridStatisticsPlotCollection() const;
@@ -121,6 +124,7 @@ private:
caf::PdmChildField<RimMultiPlotCollection*> m_multiPlotCollection;
caf::PdmChildField<RimStimPlanModelPlotCollection*> m_stimPlanModelPlotCollection;
caf::PdmChildField<RimVfpPlotCollection*> m_vfpPlotCollection;
caf::PdmChildField<RimHistogramMultiPlotCollection*> m_histogramMultiPlotCollection;
#ifdef USE_QTCHARTS
caf::PdmChildField<RimGridStatisticsPlotCollection*> m_gridStatisticsPlotCollection;
caf::PdmChildField<RimEnsembleFractureStatisticsPlotCollection*> m_ensembleFractureStatisticsPlotCollection;
@@ -1007,6 +1007,9 @@ void RimPlotCurve::updateCurveAppearance()
QColor fillColor = RiaColorTools::toQColor( m_curveAppearance->fillColor() );
fillColor = RiaColorTools::blendQColors( fillColor, QColor( Qt::white ), 3, 1 );
// TODO: this is a workaround. Create proper api for setting fill color transparency.
fillColor.setAlphaF( 0.5 );
QBrush fillBrush( fillColor, fillStyle() );
m_plotCurve->setAppearance( m_curveAppearance->lineStyle(),
m_curveAppearance->interpolation(),
@@ -1463,6 +1463,12 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
{
uiTreeOrdering.add( m_mainPlotCollection->vfpPlotCollection() );
}
if ( m_mainPlotCollection->histogramMultiPlotCollection() )
{
uiTreeOrdering.add( m_mainPlotCollection->histogramMultiPlotCollection() );
}
#ifdef USE_QTCHARTS
if ( m_mainPlotCollection->gridStatisticsPlotCollection() || m_mainPlotCollection->ensembleFractureStatisticsPlotCollection() )
{