From 78015fa19d8d07c4d9715d44af461b7bcc3827bf Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Tue, 21 Apr 2020 08:56:27 +0200 Subject: [PATCH] Correlation Matrix Plot --- .../Application/RiaSummaryCurveDefinition.cpp | 37 ++ .../Application/RiaSummaryCurveDefinition.h | 13 +- .../CMakeLists_files.cmake | 2 + .../RicNewCorrelationMatrixPlotFeature.cpp | 82 +++ .../RicNewCorrelationMatrixPlotFeature.h | 35 ++ .../AnalysisPlots/RimAnalysisPlot.cpp | 52 +- .../AnalysisPlots/RimAnalysisPlot.h | 6 +- .../RimAnalysisPlotDataEntry.cpp | 27 +- .../AnalysisPlots/RimAnalysisPlotDataEntry.h | 10 +- .../AnalysisPlots/RimPlotDataFilterItem.h | 2 +- .../CorrelationPlots/CMakeLists_files.cmake | 2 + .../RimAbstractCorrelationPlot.cpp | 200 +++++--- .../RimAbstractCorrelationPlot.h | 31 +- .../RimCorrelationMatrixPlot.cpp | 482 ++++++++++++++++++ .../RimCorrelationMatrixPlot.h | 75 +++ .../CorrelationPlots/RimCorrelationPlot.cpp | 37 +- .../RimCorrelationPlotCollection.cpp | 15 +- .../RimCorrelationPlotCollection.h | 2 + .../RimParameterResultCrossPlot.cpp | 61 +-- .../RimContextCommandBuilder.cpp | 6 + .../ProjectDataModel/RimWellLogTrack.cpp | 4 +- .../Summary/RimSummaryCaseCollection.cpp | 65 ++- .../Summary/RimSummaryCaseCollection.h | 2 + .../RiuGroupedBarChartBuilder.cpp | 4 +- .../UserInterface/RiuMultiPlotPage.cpp | 4 +- .../UserInterface/RiuQwtLinearScaleEngine.cpp | 17 + .../UserInterface/RiuQwtLinearScaleEngine.h | 11 +- .../UserInterface/RiuQwtPlotWidget.cpp | 41 +- .../UserInterface/RiuQwtPlotWidget.h | 17 +- 29 files changed, 1154 insertions(+), 188 deletions(-) create mode 100644 ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.cpp create mode 100644 ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.h create mode 100644 ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.cpp create mode 100644 ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.h diff --git a/ApplicationCode/Application/RiaSummaryCurveDefinition.cpp b/ApplicationCode/Application/RiaSummaryCurveDefinition.cpp index 3e02258093..f2746be3fc 100644 --- a/ApplicationCode/Application/RiaSummaryCurveDefinition.cpp +++ b/ApplicationCode/Application/RiaSummaryCurveDefinition.cpp @@ -22,6 +22,8 @@ #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" +#include "cafAssert.h" + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -194,3 +196,38 @@ bool RiaSummaryCurveDefinition::operator<( const RiaSummaryCurveDefinition& othe return ( m_summaryAddress < other.summaryAddress() ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaSummaryCurveDefinitionAnalyser::RiaSummaryCurveDefinitionAnalyser( std::vector curveDefs ) +{ + for ( const auto& curveDef : curveDefs ) + { + bool valid = false; + if ( curveDef.summaryCase() ) + { + m_singleSummaryCases.insert( curveDef.summaryCase() ); + + if ( curveDef.summaryCase()->ensemble() ) + { + m_ensembles.insert( curveDef.summaryCase()->ensemble() ); + valid = true; + } + } + else if ( curveDef.ensemble() ) + { + m_ensembles.insert( curveDef.ensemble() ); + valid = true; + } + if ( valid ) + { + RifEclipseSummaryAddress address = curveDef.summaryAddress(); + + m_quantityNames.insert( address.quantityName() ); + + address.setQuantityName( "" ); + if ( !address.itemUiText().empty() ) m_summaryItems.insert( address ); + } + } +} diff --git a/ApplicationCode/Application/RiaSummaryCurveDefinition.h b/ApplicationCode/Application/RiaSummaryCurveDefinition.h index 5c4c6c6ff5..ded98b12fb 100644 --- a/ApplicationCode/Application/RiaSummaryCurveDefinition.h +++ b/ApplicationCode/Application/RiaSummaryCurveDefinition.h @@ -54,9 +54,20 @@ public: static QString curveDefinitionText( const QString& caseName, const RifEclipseSummaryAddress& summaryAddress ); -private: private: RimSummaryCase* m_summaryCase; RifEclipseSummaryAddress m_summaryAddress; RimSummaryCaseCollection* m_ensemble; }; + +class RiaSummaryCurveDefinitionAnalyser +{ +public: + RiaSummaryCurveDefinitionAnalyser( std::vector curveDefs ); + + std::set m_singleSummaryCases; // All summary cases used + std::set m_ensembles; // All the ensembles referenced by the summary cases + + std::set m_summaryItems; // Quantity name set to "", stores only the identifiers + std::set m_quantityNames; // Quantity names from the addresses +}; diff --git a/ApplicationCode/Commands/CorrelationPlotCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CorrelationPlotCommands/CMakeLists_files.cmake index 0e33a39311..4bfba7d1ef 100644 --- a/ApplicationCode/Commands/CorrelationPlotCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CorrelationPlotCommands/CMakeLists_files.cmake @@ -1,11 +1,13 @@ set (SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationPlotFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationMatrixPlotFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewParameterResultCrossPlotFeature.h ) set (SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationPlotFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicNewCorrelationMatrixPlotFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewParameterResultCrossPlotFeature.cpp ) diff --git a/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.cpp b/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.cpp new file mode 100644 index 0000000000..cddb1edac6 --- /dev/null +++ b/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.cpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewCorrelationMatrixPlotFeature.h" + +#include "RimCorrelationMatrixPlot.h" +#include "RimCorrelationPlot.h" +#include "RimCorrelationPlotCollection.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewCorrelationMatrixPlotFeature, "RicNewCorrelationMatrixPlotFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewCorrelationMatrixPlotFeature::isCommandEnabled() +{ + RimCorrelationPlotCollection* correlationPlotColl = nullptr; + + caf::PdmObject* selObj = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ); + if ( selObj ) + { + selObj->firstAncestorOrThisOfType( correlationPlotColl ); + } + + if ( correlationPlotColl ) return true; + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewCorrelationMatrixPlotFeature::onActionTriggered( bool isChecked ) +{ + RimCorrelationPlotCollection* correlationPlotColl = nullptr; + + caf::PdmObject* selObj = dynamic_cast( caf::SelectionManager::instance()->selectedItem() ); + if ( selObj ) + { + selObj->firstAncestorOrThisOfType( correlationPlotColl ); + } + + if ( !correlationPlotColl ) return; + + auto newPlot = correlationPlotColl->createCorrelationMatrixPlot(); + newPlot->loadDataAndUpdate(); + + correlationPlotColl->updateConnectedEditors(); + + RiuPlotMainWindowTools::setExpanded( newPlot ); + RiuPlotMainWindowTools::selectAsCurrentItem( newPlot ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewCorrelationMatrixPlotFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "New Correlation Matrix Plot" ); + actionToSetup->setIcon( QIcon( ":/AnalysisPlot16x16.png" ) ); +} diff --git a/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.h b/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.h new file mode 100644 index 0000000000..da9caa1ff0 --- /dev/null +++ b/ApplicationCode/Commands/CorrelationPlotCommands/RicNewCorrelationMatrixPlotFeature.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewCorrelationMatrixPlotFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.cpp b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.cpp index 2e6bba8cac..46f23d95cd 100644 --- a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.cpp +++ b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.cpp @@ -52,40 +52,6 @@ #include #include -class RimCurveDefinitionAnalyser -{ -public: - RimCurveDefinitionAnalyser( std::vector curveDefs ) - { - for ( const auto& curveDef : curveDefs ) - { - CVF_ASSERT( !curveDef.isEnsembleCurve() ); - if ( curveDef.summaryCase() ) - { - m_singleSummaryCases.insert( curveDef.summaryCase() ); - - if ( curveDef.summaryCase()->ensemble() ) - { - m_ensembles.insert( curveDef.summaryCase()->ensemble() ); - } - - RifEclipseSummaryAddress address = curveDef.summaryAddress(); - - m_quantityNames.insert( address.quantityName() ); - - address.setQuantityName( "" ); - if ( !address.itemUiText().empty() ) m_summaryItems.insert( address ); - } - } - } - - std::set m_singleSummaryCases; // All summary cases used - std::set m_ensembles; // All the ensembles referenced by the summary cases - - std::set m_summaryItems; // Quantity name set to "", stores only the identifiers - std::set m_quantityNames; // Quantity names from the addresses -}; - namespace caf { template <> @@ -233,7 +199,7 @@ std::set RimAnalysisPlot::unfilteredAddresses() { std::set addresses; - RimCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); for ( RimSummaryCase* sumCase : analyserOfSelectedCurveDefs->m_singleSummaryCases ) { @@ -251,7 +217,7 @@ std::set RimAnalysisPlot::ensembleParameters() { std::set ensembleParms; - RimCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); std::set ensembles; @@ -584,8 +550,8 @@ QList RimAnalysisPlot::calculateValueOptions( const caf: if ( !m_analyserOfSelectedCurveDefs ) { - m_analyserOfSelectedCurveDefs = std::unique_ptr( - new RimCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); } if ( fieldNeedingOptions == &m_addTimestepUiField ) @@ -703,8 +669,8 @@ void RimAnalysisPlot::onLoadDataAndUpdate() { updateMdiWindowVisibility(); - m_analyserOfSelectedCurveDefs = std::unique_ptr( - new RimCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); if ( m_plotWidget ) { @@ -1607,12 +1573,12 @@ void RimAnalysisPlot::updatePlotTitle() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimCurveDefinitionAnalyser* RimAnalysisPlot::getOrCreateSelectedCurveDefAnalyser() +RiaSummaryCurveDefinitionAnalyser* RimAnalysisPlot::getOrCreateSelectedCurveDefAnalyser() { if ( !m_analyserOfSelectedCurveDefs ) { - m_analyserOfSelectedCurveDefs = std::unique_ptr( - new RimCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitionsWithoutEnsembleReference() ) ); } return m_analyserOfSelectedCurveDefs.get(); diff --git a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.h b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.h index 3fc7105f6b..20aa63db6e 100644 --- a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.h +++ b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlot.h @@ -32,7 +32,7 @@ class RiuSummaryQwtPlot; class RiuGroupedBarChartBuilder; class RimAnalysisPlotDataEntry; -class RimCurveDefinitionAnalyser; +class RiaSummaryCurveDefinitionAnalyser; class RimPlotAxisPropertiesInterface; class RimPlotAxisProperties; class RimPlotDataFilterCollection; @@ -151,7 +151,7 @@ private: void addDataToChartBuilder( RiuGroupedBarChartBuilder& chartBuilder ); void updatePlotTitle(); - RimCurveDefinitionAnalyser* getOrCreateSelectedCurveDefAnalyser(); + RiaSummaryCurveDefinitionAnalyser* getOrCreateSelectedCurveDefAnalyser(); std::vector curveDefinitionsWithoutEnsembleReference() const; std::vector curveDefinitionsWithEmbeddedEnsembleReference(); std::vector filteredCurveDefs(); @@ -167,7 +167,7 @@ private: void buildTestPlot( RiuGroupedBarChartBuilder& chartBuilder ); private: - std::unique_ptr m_analyserOfSelectedCurveDefs; + std::unique_ptr m_analyserOfSelectedCurveDefs; QPointer m_plotWidget; diff --git a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.cpp b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.cpp index 884b9f367c..7c778379bb 100644 --- a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.cpp +++ b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.cpp @@ -39,6 +39,10 @@ RimAnalysisPlotDataEntry::RimAnalysisPlotDataEntry() m_summaryCase.uiCapability()->setUiTreeChildrenHidden( true ); m_summaryCase.uiCapability()->setAutoAddingOptionFromValue( false ); + CAF_PDM_InitFieldNoDefault( &m_ensemble, "Ensemble", "Ensemble", "", "", "" ); + m_ensemble.uiCapability()->setUiTreeChildrenHidden( true ); + m_ensemble.uiCapability()->setAutoAddingOptionFromValue( false ); + CAF_PDM_InitFieldNoDefault( &m_summaryAddress, "SummaryAddress", "Summary Address", "", "", "" ); m_summaryAddress.uiCapability()->setUiHidden( true ); m_summaryAddress.uiCapability()->setUiTreeChildrenHidden( true ); @@ -58,9 +62,14 @@ RimAnalysisPlotDataEntry::~RimAnalysisPlotDataEntry() void RimAnalysisPlotDataEntry::setFromCurveDefinition( const RiaSummaryCurveDefinition& curveDef ) { m_summaryAddress->setAddress( curveDef.summaryAddress() ); - CVF_ASSERT( !curveDef.ensemble() ); // We will not support definitions of ensemble curves. Only single cases that - // might be part of an ensemble - m_summaryCase = curveDef.summaryCase(); + if ( curveDef.ensemble() ) + { + m_ensemble = curveDef.ensemble(); + } + else + { + m_summaryCase = curveDef.summaryCase(); + } } //-------------------------------------------------------------------------------------------------- @@ -68,6 +77,10 @@ void RimAnalysisPlotDataEntry::setFromCurveDefinition( const RiaSummaryCurveDefi //-------------------------------------------------------------------------------------------------- RiaSummaryCurveDefinition RimAnalysisPlotDataEntry::curveDefinition() const { + if ( m_ensemble ) + { + return RiaSummaryCurveDefinition( nullptr, m_summaryAddress->address(), m_ensemble() ); + } return RiaSummaryCurveDefinition( m_summaryCase(), m_summaryAddress->address(), nullptr ); } @@ -79,6 +92,14 @@ RimSummaryCase* RimAnalysisPlotDataEntry::summaryCase() const return m_summaryCase; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryCaseCollection* RimAnalysisPlotDataEntry::ensemble() const +{ + return m_ensemble; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.h b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.h index 639ba9a8a6..92dd31c0cb 100644 --- a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.h +++ b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimAnalysisPlotDataEntry.h @@ -39,10 +39,12 @@ public: void setFromCurveDefinition( const RiaSummaryCurveDefinition& curveDef ); RiaSummaryCurveDefinition curveDefinition() const; - RimSummaryCase* summaryCase() const; - RifEclipseSummaryAddress summaryAddress() const; + RimSummaryCase* summaryCase() const; + RimSummaryCaseCollection* ensemble() const; + RifEclipseSummaryAddress summaryAddress() const; private: - caf::PdmPtrField m_summaryCase; - caf::PdmChildField m_summaryAddress; + caf::PdmPtrField m_summaryCase; + caf::PdmPtrField m_ensemble; + caf::PdmChildField m_summaryAddress; }; diff --git a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimPlotDataFilterItem.h b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimPlotDataFilterItem.h index 7d18005dc3..c837da6258 100644 --- a/ApplicationCode/ProjectDataModel/AnalysisPlots/RimPlotDataFilterItem.h +++ b/ApplicationCode/ProjectDataModel/AnalysisPlots/RimPlotDataFilterItem.h @@ -36,7 +36,7 @@ class RiuSummaryQwtPlot; class RiuGroupedBarChartBuilder; class RimAnalysisPlotDataEntry; -class RimCurveDefinitionAnalyser; +class RiaSummaryCurveDefinitionAnalyser; class RimPlotAxisPropertiesInterface; class RimPlotAxisProperties; diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake index 959d0e76af..e7ad3f4920 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/CMakeLists_files.cmake @@ -2,6 +2,7 @@ set (SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RimAbstractCorrelationPlot.h ${CMAKE_CURRENT_LIST_DIR}/RimCorrelationPlot.h +${CMAKE_CURRENT_LIST_DIR}/RimCorrelationMatrixPlot.h ${CMAKE_CURRENT_LIST_DIR}/RimParameterResultCrossPlot.h ${CMAKE_CURRENT_LIST_DIR}/RimCorrelationPlotCollection.h ) @@ -9,6 +10,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimCorrelationPlotCollection.h set (SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RimAbstractCorrelationPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RimCorrelationPlot.cpp +${CMAKE_CURRENT_LIST_DIR}/RimCorrelationMatrixPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RimParameterResultCrossPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RimCorrelationPlotCollection.cpp ) diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.cpp b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.cpp index fb0bc90b0f..6277d7ef77 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.cpp +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.cpp @@ -2,9 +2,11 @@ #include "RiaApplication.h" #include "RiaPreferences.h" +#include "RiaSummaryCurveDefinition.h" #include "RifSummaryReaderInterface.h" +#include "RimAnalysisPlotDataEntry.h" #include "RimEnsembleCurveSet.h" #include "RimProject.h" #include "RimSummaryAddress.h" @@ -24,26 +26,23 @@ CAF_PDM_ABSTRACT_SOURCE_INIT( RimAbstractCorrelationPlot, "AbstractCorrelationPl /// //-------------------------------------------------------------------------------------------------- RimAbstractCorrelationPlot::RimAbstractCorrelationPlot() + : m_selectMultipleVectors( false ) { CAF_PDM_InitObject( "Abstract Correlation Plot", ":/CorrelationPlot16x16.png", "", "" ); - CAF_PDM_InitFieldNoDefault( &m_ensemble, "Ensemble", "Ensemble", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_selectedVarsUiField, "SelectedVariableDisplayVar", "Vector", "", "", "" ); + m_selectedVarsUiField.xmlCapability()->disableIO(); + m_selectedVarsUiField.uiCapability()->setUiEditorTypeName( caf::PdmUiLineEditor::uiEditorTypeName() ); - 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()->setUiHidden( true ); - m_summaryAddress.uiCapability()->setUiTreeChildrenHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_analysisPlotDataSelection, "AnalysisPlotData", "", "", "", "" ); + m_analysisPlotDataSelection.uiCapability()->setUiTreeChildrenHidden( true ); + m_analysisPlotDataSelection.uiCapability()->setUiTreeHidden( true ); CAF_PDM_InitFieldNoDefault( &m_pushButtonSelectSummaryAddress, "SelectAddress", "", "", "", "" ); caf::PdmUiPushButtonEditor::configureEditorForField( &m_pushButtonSelectSummaryAddress ); m_pushButtonSelectSummaryAddress.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_pushButtonSelectSummaryAddress = false; - m_summaryAddress = new RimSummaryAddress; - CAF_PDM_InitFieldNoDefault( &m_timeStep, "TimeStep", "Time Step", "", "", "" ); m_timeStep.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); @@ -70,19 +69,28 @@ void RimAbstractCorrelationPlot::fieldChangedByUi( const caf::PdmFieldHandle* ch if ( changedField == &m_pushButtonSelectSummaryAddress ) { RiuSummaryVectorSelectionDialog dlg( nullptr ); - RimSummaryCaseCollection* candidateEnsemble = m_ensemble; - RifEclipseSummaryAddress candicateAddress = m_summaryAddress->address(); - dlg.hideSummaryCases(); - dlg.setEnsembleAndAddress( candidateEnsemble, candicateAddress ); + if ( m_selectMultipleVectors ) + { + dlg.enableMultiSelect( true ); + } + + dlg.setCaseAndAddress( nullptr, RifEclipseSummaryAddress() ); + dlg.setCurveSelection( curveDefinitions() ); if ( dlg.exec() == QDialog::Accepted ) { auto curveSelection = dlg.curveSelection(); if ( !curveSelection.empty() ) { - m_summaryAddress->setAddress( curveSelection[0].summaryAddress() ); - + std::vector summaryVectorDefinitions = dlg.curveSelection(); + m_analysisPlotDataSelection.deleteAllChildObjects(); + for ( const RiaSummaryCurveDefinition& vectorDef : summaryVectorDefinitions ) + { + auto plotEntry = new RimAnalysisPlotDataEntry(); + plotEntry->setFromCurveDefinition( vectorDef ); + m_analysisPlotDataSelection.push_back( plotEntry ); + } this->loadDataAndUpdate(); this->updateConnectedEditors(); } @@ -95,11 +103,6 @@ void RimAbstractCorrelationPlot::fieldChangedByUi( const caf::PdmFieldHandle* ch this->loadDataAndUpdate(); this->updateConnectedEditors(); } - else if ( changedField == &m_ensemble ) - { - this->loadDataAndUpdate(); - this->updateConnectedEditors(); - } else if ( changedField == &m_showPlotTitle || changedField == &m_useAutoPlotTitle || changedField == &m_description ) { this->updatePlotTitle(); @@ -136,38 +139,14 @@ QList { QList options = RimPlot::calculateValueOptions( fieldNeedingOptions, useOptionsOnly ); - if ( fieldNeedingOptions == &m_ensemble ) + if ( fieldNeedingOptions == &m_timeStep ) { - RimProject* project = RiaApplication::instance()->project(); - std::vector summaryCaseCollections; - project->descendantsIncludingThisOfType( summaryCaseCollections ); - for ( auto summaryCaseCollection : summaryCaseCollections ) + std::set allTimeSteps = allAvailableTimeSteps(); + for ( time_t timeStep : allTimeSteps ) { - if ( summaryCaseCollection->isEnsemble() ) - { - options.push_back( caf::PdmOptionItemInfo( summaryCaseCollection->name(), summaryCaseCollection ) ); - } - } - } - else if ( fieldNeedingOptions == &m_summaryAddressUiField ) - { - if ( m_ensemble ) - { - RimEnsembleCurveSet::appendOptionItemsForSummaryAddresses( &options, m_ensemble ); - } - } - else if ( fieldNeedingOptions == &m_timeStep ) - { - QString dateTimeFormat = RiaApplication::instance()->preferences()->dateTimeFormat(); - if ( m_ensemble ) - { - std::set allTimeSteps = allAvailableTimeSteps(); - for ( time_t timeStep : allTimeSteps ) - { - QDateTime dateTime = QDateTime::fromTime_t( timeStep ); - QString timestepString = dateTime.toString( Qt::ISODate ); - options.push_back( caf::PdmOptionItemInfo( timestepString, dateTime ) ); - } + QDateTime dateTime = QDateTime::fromTime_t( timeStep ); + QString timestepString = dateTime.toString( Qt::ISODate ); + options.push_back( caf::PdmOptionItemInfo( timestepString, dateTime ) ); } } return options; @@ -180,19 +159,102 @@ std::set RimAbstractCorrelationPlot::allAvailableTimeSteps() { std::set timeStepUnion; - for ( RimSummaryCase* sumCase : m_ensemble->allSummaryCases() ) + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + for ( RimSummaryCaseCollection* ensemble : analyserOfSelectedCurveDefs->m_ensembles ) { - const std::vector& timeSteps = sumCase->summaryReader()->timeSteps( m_summaryAddress->address() ); - - for ( time_t t : timeSteps ) - { - timeStepUnion.insert( t ); - } + const std::set& timeSteps = ensemble->ensembleTimeSteps(); + timeStepUnion.insert( timeSteps.begin(), timeSteps.end() ); } return timeStepUnion; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAbstractCorrelationPlot::curveDefinitions() const +{ + std::vector curveDefs; + for ( auto dataEntry : m_analysisPlotDataSelection ) + { + curveDefs.push_back( dataEntry->curveDefinition() ); + } + + return curveDefs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaSummaryCurveDefinitionAnalyser* RimAbstractCorrelationPlot::getOrCreateSelectedCurveDefAnalyser() +{ + if ( !m_analyserOfSelectedCurveDefs ) + { + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitions() ) ); + } + + return m_analyserOfSelectedCurveDefs.get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimAbstractCorrelationPlot::addresses() +{ + std::set addresses; + + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + + for ( RimSummaryCaseCollection* ensemble : analyserOfSelectedCurveDefs->m_ensembles ) + { + const std::set& caseAddrs = ensemble->ensembleSummaryAddresses(); + addresses.insert( caseAddrs.begin(), caseAddrs.end() ); + } + + return addresses; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimAbstractCorrelationPlot::ensembles() +{ + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + return analyserOfSelectedCurveDefs->m_ensembles; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimAbstractCorrelationPlot::ensembleParameters() +{ + std::set ensembleParms; + + RiaSummaryCurveDefinitionAnalyser* analyserOfSelectedCurveDefs = getOrCreateSelectedCurveDefAnalyser(); + + for ( RimSummaryCaseCollection* ensemble : analyserOfSelectedCurveDefs->m_ensembles ) + { + std::vector parameters = ensemble->alphabeticEnsembleParameters(); + ensembleParms.insert( parameters.begin(), parameters.end() ); + } + return ensembleParms; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +EnsembleParameter RimAbstractCorrelationPlot::ensembleParameter( const QString& ensembleParameterName ) +{ + std::set ensembleParms = ensembleParameters(); + for ( const EnsembleParameter& eParam : ensembleParms ) + { + if ( eParam.name == ensembleParameterName ) return eParam; + } + + return EnsembleParameter(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -313,3 +375,25 @@ time_t RimAbstractCorrelationPlot::timeDiff( time_t lhs, time_t rhs ) } return rhs - lhs; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimAbstractCorrelationPlot::selectedVarsText() const +{ + QString vectorNames; + if ( m_analyserOfSelectedCurveDefs ) + { + for ( const std::string& quantityName : m_analyserOfSelectedCurveDefs->m_quantityNames ) + { + vectorNames += QString::fromStdString( quantityName ) + ", "; + } + + if ( !vectorNames.isEmpty() ) + { + vectorNames.chop( 2 ); + } + } + + return vectorNames; +} diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.h b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.h index fe92337d88..0bd6bb9a4a 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.h +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimAbstractCorrelationPlot.h @@ -25,6 +25,11 @@ #include "cafPdmPtrField.h" +#include + +class RiaSummaryCurveDefinition; +class RiaSummaryCurveDefinitionAnalyser; +class RimAnalysisPlotDataEntry; class RimSummaryAddress; class RimAbstractCorrelationPlot : public RimPlot @@ -47,7 +52,14 @@ protected: QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) override; - std::set allAvailableTimeSteps(); + std::set allAvailableTimeSteps(); + std::vector curveDefinitions() const; + RiaSummaryCurveDefinitionAnalyser* getOrCreateSelectedCurveDefAnalyser(); + + std::set addresses(); + std::set ensembles(); + std::set ensembleParameters(); + EnsembleParameter ensembleParameter( const QString& ensembleParameterName ); // RimViewWindow overrides QWidget* viewWidget() override; @@ -84,15 +96,20 @@ protected: static time_t timeDiff( time_t lhs, time_t rhs ); + QString selectedVarsText() const; + protected: - QPointer m_plotWidget; + std::unique_ptr m_analyserOfSelectedCurveDefs; + QPointer m_plotWidget; + + bool m_selectMultipleVectors; // Fields - caf::PdmPtrField m_ensemble; - caf::PdmChildField m_summaryAddress; - caf::PdmField m_summaryAddressUiField; - caf::PdmField m_pushButtonSelectSummaryAddress; - caf::PdmField m_timeStep; + caf::PdmChildArrayField m_analysisPlotDataSelection; + + caf::PdmField m_selectedVarsUiField; + caf::PdmField m_pushButtonSelectSummaryAddress; + caf::PdmField m_timeStep; caf::PdmField m_showPlotTitle; caf::PdmField m_useAutoPlotTitle; diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.cpp b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.cpp new file mode 100644 index 0000000000..fa26d094ba --- /dev/null +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.cpp @@ -0,0 +1,482 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCorrelationMatrixPlot.h" + +#include "RiaApplication.h" +#include "RiaColorTools.h" +#include "RiaPreferences.h" +#include "RiaStatisticsTools.h" +#include "RiuPlotMainWindowTools.h" +#include "RiuQwtLinearScaleEngine.h" +#include "RiuQwtPlotTools.h" +#include "RiuQwtPlotWidget.h" + +#include "RifSummaryReaderInterface.h" + +#include "RimDerivedSummaryCase.h" +#include "RimEnsembleCurveSet.h" +#include "RimPlotAxisProperties.h" +#include "RimPlotAxisPropertiesInterface.h" +#include "RimPlotDataFilterCollection.h" +#include "RimRegularLegendConfig.h" +#include "RimSummaryAddress.h" +#include "RimSummaryCase.h" +#include "RimSummaryCaseCollection.h" +#include "RimSummaryPlotAxisFormatter.h" + +#include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiTreeOrdering.h" + +#include "cvfScalarMapper.h" + +#include "qwt_plot_marker.h" +#include "qwt_scale_draw.h" +#include "qwt_text.h" + +#include +#include +#include +#include + +CAF_PDM_SOURCE_INIT( RimCorrelationMatrixPlot, "CorrelationMatrixPlot" ); + +class TextScaleDraw : public QwtScaleDraw +{ +public: + TextScaleDraw( const std::map& tickLabels ) + : m_tickLabels( tickLabels ) + { + } + + QwtText label( double value ) const override + { + size_t intValue = static_cast( value + 0.25 ); + auto it = m_tickLabels.find( intValue ); + return it != m_tickLabels.end() ? it->second : ""; + } + +private: + std::map m_tickLabels; +}; + +class CorrelationMatrixRowOrColumn +{ +public: + CorrelationMatrixRowOrColumn( const QString& label, + const std::vector& values, + const std::vector& entryLabels ) + : m_label( label ) + , m_values( values ) + , m_entryLabels( entryLabels ) + , m_correlationSum( 0.0 ) + { + bool anyValid = false; + for ( auto value : values ) + { + if ( RiaCurveDataTools::isValidValue( value, false ) ) + { + m_correlationSum += value * value; + anyValid = true; + } + } + if ( !anyValid ) m_correlationSum = std::numeric_limits::infinity(); + } + + QString m_label; + std::vector m_values; + std::vector m_entryLabels; + double m_correlationSum; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCorrelationMatrixPlot::RimCorrelationMatrixPlot() + : RimAbstractCorrelationPlot() +{ + CAF_PDM_InitObject( "Correlation Plot", ":/CorrelationMatrixPlot16x16.png", "", "" ); + + CAF_PDM_InitFieldNoDefault( &m_correlationFactor, "CorrelationFactor", "Correlation Factor", "", "", "" ); + m_correlationFactor.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() ); + CAF_PDM_InitField( &m_showAbsoluteValues, "CorrelationAbsValues", true, "Show Absolute Values", "", "", "" ); + CAF_PDM_InitField( &m_sortByValues, "CorrelationSorting", true, "Sort Matrix by Values", "", "", "" ); + + CAF_PDM_InitFieldNoDefault( &m_legendConfig, "LegendConfig", "", "", "", "" ); + m_legendConfig = new RimRegularLegendConfig(); + m_legendConfig->setAutomaticRanges( -1.0, 1.0, -1.0, 1.0 ); + + m_selectMultipleVectors = true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCorrelationMatrixPlot::~RimCorrelationMatrixPlot() +{ + removeMdiWindowFromMdiArea(); + + cleanupBeforeClose(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + RimAbstractCorrelationPlot::fieldChangedByUi( changedField, oldValue, newValue ); + if ( changedField == &m_correlationFactor || changedField == &m_showAbsoluteValues || changedField == &m_sortByValues ) + { + this->updateLegend(); + this->loadDataAndUpdate(); + this->updateConnectedEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + caf::PdmUiGroup* correlationGroup = uiOrdering.addNewGroup( "Correlation Factor Settings" ); + correlationGroup->add( &m_correlationFactor ); + correlationGroup->add( &m_showAbsoluteValues ); + correlationGroup->add( &m_sortByValues ); + + caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector" ); + m_selectedVarsUiField = selectedVarsText(); + + curveDataGroup->add( &m_selectedVarsUiField ); + curveDataGroup->add( &m_pushButtonSelectSummaryAddress, { false, 1, 0 } ); + curveDataGroup->add( &m_timeStep ); + + caf::PdmUiGroup* plotGroup = uiOrdering.addNewGroup( "Plot Settings" ); + plotGroup->add( &m_showPlotTitle ); + plotGroup->add( &m_useAutoPlotTitle ); + plotGroup->add( &m_description ); + m_description.uiCapability()->setUiReadOnly( m_useAutoPlotTitle() ); + RimPlot::defineUiOrdering( uiConfigName, *plotGroup ); + + uiOrdering.skipRemainingFields( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RimCorrelationMatrixPlot::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) +{ + QList options = + RimAbstractCorrelationPlot::calculateValueOptions( fieldNeedingOptions, useOptionsOnly ); + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::onLoadDataAndUpdate() +{ + updateMdiWindowVisibility(); + + m_selectedVarsUiField = selectedVarsText(); + + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitions() ) ); + + if ( m_plotWidget ) + { + m_plotWidget->detachItems( QwtPlotItem::Rtti_PlotBarChart ); + m_plotWidget->detachItems( QwtPlotItem::Rtti_PlotScale ); + m_plotWidget->detachItems( QwtPlotItem::Rtti_PlotItem ); + + createMatrix(); + + m_plotWidget->insertLegend( nullptr ); + m_plotWidget->updateLegend(); + + this->updateAxes(); + this->updatePlotTitle(); + m_plotWidget->scheduleReplot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) +{ + this->loadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, + QString uiConfigName /*= "" */ ) +{ + uiTreeOrdering.add( m_legendConfig() ); + uiTreeOrdering.skipRemainingChildren( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::updateAxes() +{ + if ( !m_plotWidget ) return; + + m_plotWidget->setAxisScaleEngine( QwtPlot::yLeft, new RiuQwtLinearScaleEngine ); + m_plotWidget->setAxisTitleText( QwtPlot::yLeft, "Result Vector" ); + m_plotWidget->setAxisTitleEnabled( QwtPlot::yLeft, true ); + m_plotWidget->setAxisFontsAndAlignment( QwtPlot::yLeft, 11, 7, false, Qt::AlignCenter ); + m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::yLeft, true, false ); + m_plotWidget->setAxisRange( QwtPlot::yLeft, 0.0, (double)m_resultLabels.size() + 1 ); + m_plotWidget->setAxisScaleDraw( QwtPlot::yLeft, new TextScaleDraw( m_resultLabels ) ); + m_plotWidget->setMajorAndMinorTickIntervalsAndRange( QwtPlot::yLeft, + 1.0, + 0.0, + 0.5, + (double)m_resultLabels.size() - 0.5, + 0.0, + m_resultLabels.size() ); + + auto scaleDraw = new TextScaleDraw( m_paramLabels ); + scaleDraw->setLabelRotation( 30.0 ); + m_plotWidget->setAxisScaleDraw( QwtPlot::xBottom, scaleDraw ); + + m_plotWidget->setAxisScaleEngine( QwtPlot::xBottom, new RiuQwtLinearScaleEngine ); + m_plotWidget->setAxisTitleText( QwtPlot::xBottom, "Ensemble Parameter" ); + m_plotWidget->setAxisTitleEnabled( QwtPlot::xBottom, true ); + m_plotWidget->setAxisFontsAndAlignment( QwtPlot::xBottom, 11, 6, false, Qt::AlignCenter | Qt::AlignTop ); + m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::xBottom, true, false ); + m_plotWidget->setAxisRange( QwtPlot::xBottom, 0.0, (double)m_paramLabels.size() + 1 ); + // m_plotWidget->setAutoTickIntervalCounts( QwtPlot::xBottom, m_paramLabels.size(), m_paramLabels.size() ); + m_plotWidget->setMajorAndMinorTickIntervalsAndRange( QwtPlot::xBottom, + 1.0, + 0.0, + 0.5, + (double)m_paramLabels.size() - 0.5, + 0.0, + (double)m_paramLabels.size() ); + + m_plotWidget->setAxisLabelAlignment( QwtPlot::xBottom, Qt::AlignRight ); +} + +void eraseInvalidEntries( std::vector& matrix ) +{ + matrix.erase( std::remove_if( matrix.begin(), + matrix.end(), + []( auto entry ) { + return !RiaCurveDataTools::isValidValue( entry.m_correlationSum, false ); + } ), + matrix.end() ); +} + +void sortEntries( std::vector& matrix ) +{ + std::sort( matrix.begin(), + matrix.end(), + []( const CorrelationMatrixRowOrColumn& lhs, const CorrelationMatrixRowOrColumn& rhs ) { + return lhs.m_correlationSum > rhs.m_correlationSum; + } ); +} + +std::vector transpose( const std::vector& matrix ) +{ + std::vector transposedMatrix; + for ( size_t rowIdx = 0u; rowIdx < matrix[0].m_values.size(); ++rowIdx ) + { + QString label = matrix[0].m_entryLabels[rowIdx]; + std::vector values; + std::vector entryLabels; + for ( size_t colIdx = 0u; colIdx < matrix.size(); ++colIdx ) + { + values.push_back( matrix[colIdx].m_values[rowIdx] ); + entryLabels.push_back( matrix[colIdx].m_label ); + } + transposedMatrix.push_back( CorrelationMatrixRowOrColumn( label, values, entryLabels ) ); + } + return transposedMatrix; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::createMatrix() +{ + time_t selectedTimestep = m_timeStep().toTime_t(); + + m_paramLabels.clear(); + m_resultLabels.clear(); + + auto curveDefs = curveDefinitions(); + if ( curveDefs.empty() ) return; + + std::vector correlationMatrixColumns; + + for ( EnsembleParameter parameter : ensembleParameters() ) + { + if ( parameter.isNumeric() && parameter.isValid() ) + { + bool anyValidResults = false; + std::vector correlations; + std::vector resultLabels; + + for ( auto curveDef : curveDefs ) + { + double correlation = std::numeric_limits::infinity(); + + auto ensemble = curveDef.ensemble(); + auto address = curveDef.summaryAddress(); + + QString resultLabel = curveDef.curveDefinitionText(); + + if ( ensemble ) + { + std::vector caseValuesAtTimestep; + std::vector parameterValues; + + for ( size_t caseIdx = 0u; caseIdx < ensemble->allSummaryCases().size(); ++caseIdx ) + { + auto summaryCase = ensemble->allSummaryCases()[caseIdx]; + RifSummaryReaderInterface* reader = summaryCase->summaryReader(); + if ( reader ) + { + std::vector values; + double closestValue = std::numeric_limits::infinity(); + time_t closestTimeStep = 0; + if ( reader->values( address, &values ) ) + { + const std::vector& timeSteps = reader->timeSteps( address ); + for ( size_t i = 0; i < timeSteps.size(); ++i ) + { + if ( timeDiff( timeSteps[i], selectedTimestep ) < + timeDiff( selectedTimestep, closestTimeStep ) ) + { + closestValue = values[i]; + closestTimeStep = timeSteps[i]; + } + } + } + if ( closestValue != std::numeric_limits::infinity() ) + { + caseValuesAtTimestep.push_back( closestValue ); + double paramValue = parameter.values[caseIdx].toDouble(); + parameterValues.push_back( paramValue ); + } + } + } + + if ( parameterValues.empty() ) continue; + + if ( m_correlationFactor == CorrelationFactor::PEARSON ) + { + correlation = RiaStatisticsTools::pearsonCorrelation( parameterValues, caseValuesAtTimestep ); + } + else + { + correlation = RiaStatisticsTools::spearmanCorrelation( parameterValues, caseValuesAtTimestep ); + } + + if ( RiaCurveDataTools::isValidValue( correlation, false ) ) + { + if ( m_showAbsoluteValues() ) correlation = std::abs( correlation ); + anyValidResults = true; + } + } + correlations.push_back( correlation ); + resultLabels.push_back( resultLabel ); + } + if ( anyValidResults ) + { + correlationMatrixColumns.push_back( + CorrelationMatrixRowOrColumn( parameter.name, correlations, resultLabels ) ); + } + } + } + + eraseInvalidEntries( correlationMatrixColumns ); + if ( m_sortByValues() ) sortEntries( correlationMatrixColumns ); + + auto correlationMatrixRows = transpose( correlationMatrixColumns ); + + eraseInvalidEntries( correlationMatrixRows ); + if ( m_sortByValues() ) sortEntries( correlationMatrixRows ); + + for ( size_t rowIdx = 0u; rowIdx < correlationMatrixRows.size(); ++rowIdx ) + { + for ( size_t colIdx = 0u; colIdx < correlationMatrixRows[rowIdx].m_values.size(); ++colIdx ) + { + double correlation = correlationMatrixRows[rowIdx].m_values[colIdx]; + auto label = QString( "%1" ).arg( correlation, 0, 'f', 2 ); + cvf::Color3ub color = m_legendConfig->scalarMapper()->mapToColor( correlation ); + QColor qColor( color.r(), color.g(), color.b() ); + QwtPlotItem* rectangle = RiuQwtPlotTools::createBoxShape( label, + (double)colIdx, + (double)colIdx + 1.0, + (double)rowIdx, + (double)rowIdx + 1, + qColor ); + QwtText textLabel( label ); + cvf::Color3f contrastColor = RiaColorTools::contrastColor( cvf::Color3f( color ) ); + textLabel.setColor( RiaColorTools::toQColor( contrastColor ) ); + QFont font = textLabel.font(); + font.setPixelSize( RiaFontCache::pointSizeToPixelSize( 7 ) ); + textLabel.setFont( font ); + QwtPlotMarker* marker = new QwtPlotMarker(); + marker->setLabel( textLabel ); + marker->setXValue( colIdx + 0.5 ); + marker->setYValue( rowIdx + 0.5 ); + rectangle->attach( m_plotWidget ); + marker->attach( m_plotWidget ); + m_paramLabels[colIdx] = correlationMatrixRows[rowIdx].m_entryLabels[colIdx]; + } + m_resultLabels[rowIdx] = correlationMatrixRows[rowIdx].m_label; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::updatePlotTitle() +{ + if ( m_useAutoPlotTitle ) + { + m_description = QString( "%1 Matrix for Parameters vs Result Vectors" ).arg( m_correlationFactor().uiText() ); + } + m_plotWidget->setPlotTitle( m_description ); + m_plotWidget->setPlotTitleEnabled( m_showPlotTitle && isMdiWindow() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCorrelationMatrixPlot::updateLegend() +{ + if ( m_showAbsoluteValues ) + { + m_legendConfig->setAutomaticRanges( -1.0, 1.0, -1.0, 1.0 ); + } + else + { + m_legendConfig->setAutomaticRanges( 0.0, 1.0, 0.0, 1.0 ); + } +} diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.h b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.h new file mode 100644 index 0000000000..7a8b6a81ea --- /dev/null +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationMatrixPlot.h @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2020 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimCorrelationPlot.h" +#include "cafAppEnum.h" + +#include + +class RimRegularLegendConfig; +class RimSummaryAddress; +class RiuGroupedBarChartBuilder; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimCorrelationMatrixPlot : public RimAbstractCorrelationPlot +{ + CAF_PDM_HEADER_INIT; + +public: + using CorrelationFactor = RimCorrelationPlot::CorrelationFactor; + using CorrelationFactorEnum = RimCorrelationPlot::CorrelationFactorEnum; + +public: + RimCorrelationMatrixPlot(); + ~RimCorrelationMatrixPlot() override; + +private: + // Overridden PDM methods + + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) override; + + void onLoadDataAndUpdate() override; + + void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override; + void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override; + + void updateAxes() override; + + // Private methods + void createMatrix(); + void updatePlotTitle() override; + void updateLegend() override; + +private: + caf::PdmField m_correlationFactor; + caf::PdmField m_showAbsoluteValues; + caf::PdmField m_sortByValues; + caf::PdmChildField m_legendConfig; + + std::map m_paramLabels; + std::map m_resultLabels; +}; diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlot.cpp b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlot.cpp index 68a99139ed..9364c14a76 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlot.cpp +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlot.cpp @@ -110,8 +110,8 @@ void RimCorrelationPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder } caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector" ); - curveDataGroup->add( &m_ensemble ); - curveDataGroup->add( &m_summaryAddressUiField ); + + curveDataGroup->add( &m_selectedVarsUiField ); curveDataGroup->add( &m_pushButtonSelectSummaryAddress, { false, 1, 0 } ); curveDataGroup->add( &m_timeStep ); @@ -119,6 +119,8 @@ void RimCorrelationPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder plotGroup->add( &m_showPlotTitle ); plotGroup->add( &m_useAutoPlotTitle ); plotGroup->add( &m_description ); + RimPlot::defineUiOrdering( uiConfigName, *plotGroup ); + m_description.uiCapability()->setUiReadOnly( m_useAutoPlotTitle() ); uiOrdering.skipRemainingFields( true ); } @@ -142,9 +144,12 @@ void RimCorrelationPlot::onLoadDataAndUpdate() { updateMdiWindowVisibility(); - m_summaryAddressUiField = m_summaryAddress->address(); + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitions() ) ); - if ( m_plotWidget ) + m_selectedVarsUiField = selectedVarsText(); + + if ( m_plotWidget && m_analyserOfSelectedCurveDefs ) { m_plotWidget->detachItems( QwtPlotItem::Rtti_PlotBarChart ); m_plotWidget->detachItems( QwtPlotItem::Rtti_PlotScale ); @@ -198,18 +203,18 @@ void RimCorrelationPlot::addDataToChartBuilder( RiuGroupedBarChartBuilder& chart { time_t selectedTimestep = m_timeStep().toTime_t(); - if ( !m_ensemble ) return; - - if ( !m_summaryAddress ) return; - - std::vector ensembleParameters = m_ensemble->variationSortedEnsembleParameters(); + if ( ensembles().empty() ) return; + if ( addresses().empty() ) return; std::vector caseValuesAtTimestep; std::map> parameterValues; - for ( size_t caseIdx = 0u; caseIdx < m_ensemble->allSummaryCases().size(); ++caseIdx ) + auto ensemble = *ensembles().begin(); + auto address = *addresses().begin(); + + for ( size_t caseIdx = 0u; caseIdx < ensemble->allSummaryCases().size(); ++caseIdx ) { - auto summaryCase = m_ensemble->allSummaryCases()[caseIdx]; + auto summaryCase = ensemble->allSummaryCases()[caseIdx]; RifSummaryReaderInterface* reader = summaryCase->summaryReader(); if ( !reader ) continue; @@ -220,9 +225,9 @@ void RimCorrelationPlot::addDataToChartBuilder( RiuGroupedBarChartBuilder& chart double closestValue = std::numeric_limits::infinity(); time_t closestTimeStep = 0; - if ( reader->values( m_summaryAddress->address(), &values ) ) + if ( reader->values( address, &values ) ) { - const std::vector& timeSteps = reader->timeSteps( m_summaryAddress->address() ); + const std::vector& timeSteps = reader->timeSteps( address ); for ( size_t i = 0; i < timeSteps.size(); ++i ) { if ( timeDiff( timeSteps[i], selectedTimestep ) < timeDiff( selectedTimestep, closestTimeStep ) ) @@ -236,7 +241,7 @@ void RimCorrelationPlot::addDataToChartBuilder( RiuGroupedBarChartBuilder& chart { caseValuesAtTimestep.push_back( closestValue ); - for ( auto parameter : ensembleParameters ) + for ( auto parameter : ensembleParameters() ) { if ( parameter.isNumeric() && parameter.isValid() ) { @@ -281,9 +286,7 @@ void RimCorrelationPlot::updatePlotTitle() { if ( m_useAutoPlotTitle ) { - m_description = QString( "%1 for %2" ) - .arg( m_correlationFactor().uiText() ) - .arg( QString::fromStdString( m_summaryAddressUiField().uiText() ) ); + m_description = QString( "%1 for %2" ).arg( m_correlationFactor().uiText() ).arg( m_selectedVarsUiField ); } m_plotWidget->setPlotTitle( m_description ); m_plotWidget->setPlotTitleEnabled( m_showPlotTitle && isMdiWindow() ); diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.cpp b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.cpp index ea0e4db45c..a1aaf70ea6 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.cpp +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.cpp @@ -18,6 +18,7 @@ #include "RimCorrelationPlotCollection.h" +#include "RimCorrelationMatrixPlot.h" #include "RimCorrelationPlot.h" #include "RimParameterResultCrossPlot.h" @@ -49,7 +50,19 @@ RimCorrelationPlot* RimCorrelationPlotCollection::createCorrelationPlot() RimCorrelationPlot* plot = new RimCorrelationPlot(); plot->setAsPlotMdiWindow(); - // plot->enableAutoPlotTitle( true ); + m_correlationPlots.push_back( plot ); + + return plot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCorrelationMatrixPlot* RimCorrelationPlotCollection::createCorrelationMatrixPlot() +{ + RimCorrelationMatrixPlot* plot = new RimCorrelationMatrixPlot(); + plot->setAsPlotMdiWindow(); + m_correlationPlots.push_back( plot ); return plot; diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.h b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.h index 55812a73b3..1ffc1434ca 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.h +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimCorrelationPlotCollection.h @@ -23,6 +23,7 @@ class RimAbstractCorrelationPlot; class RimCorrelationPlot; +class RimCorrelationMatrixPlot; class RimParameterResultCrossPlot; //================================================================================================== @@ -38,6 +39,7 @@ public: ~RimCorrelationPlotCollection() override; RimCorrelationPlot* createCorrelationPlot(); + RimCorrelationMatrixPlot* createCorrelationMatrixPlot(); RimParameterResultCrossPlot* createParameterResultCrossPlot(); void removePlot( RimAbstractCorrelationPlot* CorrelationPlot ); diff --git a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimParameterResultCrossPlot.cpp b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimParameterResultCrossPlot.cpp index 154d42146e..9521df9c56 100644 --- a/ApplicationCode/ProjectDataModel/CorrelationPlots/RimParameterResultCrossPlot.cpp +++ b/ApplicationCode/ProjectDataModel/CorrelationPlots/RimParameterResultCrossPlot.cpp @@ -93,9 +93,10 @@ void RimParameterResultCrossPlot::fieldChangedByUi( const caf::PdmFieldHandle* c //-------------------------------------------------------------------------------------------------- void RimParameterResultCrossPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { + m_selectedVarsUiField = selectedVarsText(); + caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Summary Vector" ); - curveDataGroup->add( &m_ensemble ); - curveDataGroup->add( &m_summaryAddressUiField ); + curveDataGroup->add( &m_selectedVarsUiField ); curveDataGroup->add( &m_pushButtonSelectSummaryAddress, { false, 1, 0 } ); curveDataGroup->add( &m_timeStep ); @@ -106,6 +107,8 @@ void RimParameterResultCrossPlot::defineUiOrdering( QString uiConfigName, caf::P plotGroup->add( &m_showPlotTitle ); plotGroup->add( &m_useAutoPlotTitle ); plotGroup->add( &m_description ); + RimPlot::defineUiOrdering( uiConfigName, *plotGroup ); + m_description.uiCapability()->setUiReadOnly( m_useAutoPlotTitle() ); uiOrdering.skipRemainingFields( true ); } @@ -120,12 +123,9 @@ QList RimAbstractCorrelationPlot::calculateValueOptions( fieldNeedingOptions, useOptionsOnly ); if ( fieldNeedingOptions == &m_ensembleParameter ) { - if ( m_ensemble ) + for ( const auto& param : ensembleParameters() ) { - for ( const auto& param : m_ensemble->variationSortedEnsembleParameters() ) - { - options.push_back( caf::PdmOptionItemInfo( param.uiName(), param.name ) ); - } + options.push_back( caf::PdmOptionItemInfo( param.uiName(), param.name ) ); } } return options; @@ -138,9 +138,12 @@ void RimParameterResultCrossPlot::onLoadDataAndUpdate() { updateMdiWindowVisibility(); - m_summaryAddressUiField = m_summaryAddress->address(); + m_analyserOfSelectedCurveDefs = std::unique_ptr( + new RiaSummaryCurveDefinitionAnalyser( this->curveDefinitions() ) ); - if ( m_plotWidget ) + m_selectedVarsUiField = selectedVarsText(); + + if ( m_plotWidget && m_analyserOfSelectedCurveDefs ) { m_plotWidget->insertLegend( nullptr ); m_plotWidget->updateLegend(); @@ -160,7 +163,7 @@ void RimParameterResultCrossPlot::updateAxes() { if ( !m_plotWidget ) return; - m_plotWidget->setAxisTitleText( QwtPlot::yLeft, QString::fromStdString( m_summaryAddressUiField().uiText() ) ); + m_plotWidget->setAxisTitleText( QwtPlot::yLeft, m_selectedVarsUiField ); m_plotWidget->setAxisTitleEnabled( QwtPlot::yLeft, true ); m_plotWidget->setAxisAutoScale( QwtPlot::yLeft, true ); m_plotWidget->setAxisFontsAndAlignment( QwtPlot::yLeft, 11, 11, false, Qt::AlignCenter ); @@ -178,19 +181,22 @@ void RimParameterResultCrossPlot::createPoints() { time_t selectedTimestep = m_timeStep().toTime_t(); - if ( !m_ensemble ) return; + caf::ColorTable colorTable = RiaColorTables::categoryPaletteColors(); - if ( !m_summaryAddress ) return; + if ( ensembles().empty() ) return; + if ( addresses().empty() ) return; - EnsembleParameter ensembleParameter = m_ensemble->ensembleParameter( m_ensembleParameter ); - if ( !( ensembleParameter.isNumeric() && ensembleParameter.isValid() ) ) return; + auto ensemble = *ensembles().begin(); + auto address = *addresses().begin(); + EnsembleParameter parameter = ensembleParameter( m_ensembleParameter ); + if ( !( parameter.isNumeric() && parameter.isValid() ) ) return; - for ( size_t caseIdx = 0u; caseIdx < m_ensemble->allSummaryCases().size(); ++caseIdx ) + for ( size_t caseIdx = 0u; caseIdx < ensemble->allSummaryCases().size(); ++caseIdx ) { std::vector caseValuesAtTimestep; std::vector parameterValues; - auto summaryCase = m_ensemble->allSummaryCases()[caseIdx]; + auto summaryCase = ensemble->allSummaryCases()[caseIdx]; RifSummaryReaderInterface* reader = summaryCase->summaryReader(); if ( !reader ) continue; @@ -201,9 +207,9 @@ void RimParameterResultCrossPlot::createPoints() double closestValue = std::numeric_limits::infinity(); time_t closestTimeStep = 0; - if ( reader->values( m_summaryAddress->address(), &values ) ) + if ( reader->values( address, &values ) ) { - const std::vector& timeSteps = reader->timeSteps( m_summaryAddress->address() ); + const std::vector& timeSteps = reader->timeSteps( address ); for ( size_t i = 0; i < timeSteps.size(); ++i ) { if ( timeDiff( timeSteps[i], selectedTimestep ) < timeDiff( selectedTimestep, closestTimeStep ) ) @@ -216,18 +222,15 @@ void RimParameterResultCrossPlot::createPoints() if ( closestValue != std::numeric_limits::infinity() ) { caseValuesAtTimestep.push_back( closestValue ); - double paramValue = ensembleParameter.values[caseIdx].toDouble(); + double paramValue = parameter.values[caseIdx].toDouble(); parameterValues.push_back( paramValue ); - RiuQwtPlotCurve* plotCurve = new RiuQwtPlotCurve; - plotCurve->setSamplesFromXValuesAndYValues( parameterValues, caseValuesAtTimestep, false ); - plotCurve->setAppearance( RiuQwtPlotCurve::STYLE_NONE, - RiuQwtPlotCurve::INTERPOLATION_POINT_TO_POINT, - 0, - QColor( Qt::red ) ); - RiuQwtSymbol* symbol = new RiuQwtSymbol( RiuQwtSymbol::SYMBOL_ELLIPSE, "" ); + QwtPlotCurve* plotCurve = new QwtPlotCurve; + plotCurve->setSamples( parameterValues.data(), caseValuesAtTimestep.data(), (int)parameterValues.size() ); + plotCurve->setStyle( QwtPlotCurve::NoCurve ); + RiuQwtSymbol* symbol = new RiuQwtSymbol( RiuQwtSymbol::SYMBOL_DIAMOND, "" ); symbol->setSize( 12, 12 ); - symbol->setColor( QColor( Qt::red ) ); + symbol->setColor( colorTable.cycledQColor( caseIdx ) ); plotCurve->setSymbol( symbol ); plotCurve->attach( m_plotWidget ); } @@ -241,9 +244,7 @@ void RimParameterResultCrossPlot::updatePlotTitle() { if ( m_useAutoPlotTitle ) { - m_description = QString( "Cross Plot %1 x %2" ) - .arg( m_ensembleParameter ) - .arg( QString::fromStdString( m_summaryAddressUiField().uiText() ) ); + m_description = QString( "Cross Plot %1 x %2" ).arg( m_ensembleParameter ).arg( m_selectedVarsUiField() ); } m_plotWidget->setPlotTitle( m_description ); m_plotWidget->setPlotTitleEnabled( m_showPlotTitle && isMdiWindow() ); diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index 7338b6e4f7..0369a971c3 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -39,6 +39,7 @@ #include "RimCellEdgeColors.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" +#include "RimCorrelationMatrixPlot.h" #include "RimCorrelationPlot.h" #include "RimCorrelationPlotCollection.h" #include "RimEclipseCase.h" @@ -530,12 +531,17 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() else if ( dynamic_cast( firstUiItem ) ) { menuBuilder << "RicNewCorrelationPlotFeature"; + menuBuilder << "RicNewCorrelationMatrixPlotFeature"; menuBuilder << "RicNewParameterResultCrossPlotFeature"; } else if ( dynamic_cast( firstUiItem ) ) { menuBuilder << "RicNewCorrelationPlotFeature"; } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicNewCorrelationMatrixPlotFeature"; + } else if ( dynamic_cast( firstUiItem ) ) { menuBuilder << "RicNewParameterResultCrossPlotFeature"; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 81e8c96eaa..d12acbaac9 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -697,11 +697,11 @@ void RimWellLogTrack::updateXAxisAndGridTickIntervals() { m_plotWidget->enableGridLines( QwtPlot::xTop, false, false ); m_plotWidget->setAxisRange( QwtPlot::xTop, 0.0, 1.0 ); - m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::xTop, false ); + m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::xTop, false, false ); } else { - m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::xTop, true ); + m_plotWidget->setAxisLabelsAndTicksEnabled( QwtPlot::xTop, true, true ); if ( m_explicitTickIntervals ) { m_plotWidget->setMajorAndMinorTickIntervals( QwtPlot::xTop, diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index c2ace5f23e..baa94524a4 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -249,7 +249,7 @@ void RimSummaryCaseCollection::addCase( RimSummaryCase* summaryCase, bool update if ( m_isEnsemble ) { - validateEnsembleCases( {summaryCase} ); + validateEnsembleCases( { summaryCase } ); calculateEnsembleParametersIntersectionHash(); } @@ -339,6 +339,42 @@ std::set RimSummaryCaseCollection::ensembleSummaryAddr return addresses; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimSummaryCaseCollection::ensembleTimeSteps() const +{ + std::set allTimeSteps; + size_t maxAddrCount = 0; + int maxAddrIndex = -1; + + for ( int i = 0; i < (int)m_cases.size(); i++ ) + { + RimSummaryCase* currCase = m_cases[i]; + if ( !currCase ) continue; + + RifSummaryReaderInterface* reader = currCase->summaryReader(); + if ( !reader ) continue; + + size_t addrCount = reader->allResultAddresses().size(); + if ( addrCount > maxAddrCount ) + { + maxAddrCount = addrCount; + maxAddrIndex = (int)i; + } + } + + if ( maxAddrIndex >= 0 && m_cases[maxAddrIndex]->summaryReader() ) + { + const std::set& addrs = m_cases[maxAddrIndex]->summaryReader()->allResultAddresses(); + for ( RifEclipseSummaryAddress addr : addrs ) + { + std::vector timeSteps = m_cases[maxAddrIndex]->summaryReader()->timeSteps( addr ); + allTimeSteps.insert( timeSteps.begin(), timeSteps.end() ); + } + } + return allTimeSteps; +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -413,6 +449,33 @@ const std::vector& RimSummaryCaseCollection::variationSortedE return m_cachedSortedEnsembleParameters; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSummaryCaseCollection::alphabeticEnsembleParameters() const +{ + std::set paramSet; + for ( RimSummaryCase* rimCase : this->allSummaryCases() ) + { + if ( rimCase->caseRealizationParameters() != nullptr ) + { + auto ps = rimCase->caseRealizationParameters()->parameters(); + for ( auto p : ps ) + { + paramSet.insert( p.first ); + } + } + } + + std::vector sortedEnsembleParameters; + sortedEnsembleParameters.reserve( paramSet.size() ); + for ( const QString& parameterName : paramSet ) + { + sortedEnsembleParameters.push_back( this->createEnsembleParameter( parameterName ) ); + } + return sortedEnsembleParameters; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h index f0e6ba5705..5ced98f299 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h @@ -102,6 +102,7 @@ public: bool isEnsemble() const; void setAsEnsemble( bool isEnsemble ); virtual std::set ensembleSummaryAddresses() const; + virtual std::set ensembleTimeSteps() const; std::set wellsWithRftData() const; std::set rftTimeStepsForWell( const QString& wellName ) const; RifReaderRftInterface* rftStatisticsReader(); @@ -109,6 +110,7 @@ public: int ensembleId() const; const std::vector& variationSortedEnsembleParameters() const; + std::vector alphabeticEnsembleParameters() const; EnsembleParameter ensembleParameter( const QString& paramName ) const; void calculateEnsembleParametersIntersectionHash(); diff --git a/ApplicationCode/UserInterface/AnalysisPlots/RiuGroupedBarChartBuilder.cpp b/ApplicationCode/UserInterface/AnalysisPlots/RiuGroupedBarChartBuilder.cpp index ac4511f8b2..51f00e1c96 100644 --- a/ApplicationCode/UserInterface/AnalysisPlots/RiuGroupedBarChartBuilder.cpp +++ b/ApplicationCode/UserInterface/AnalysisPlots/RiuGroupedBarChartBuilder.cpp @@ -507,10 +507,10 @@ void RiuGroupedBarChartBuilder::addBarChartToPlot( QwtPlot* plot, Qt::Orientatio barPoints = &( legendToBarPointsPair->second ); } - barPoints->push_back( {currentBarPosition, barDef.m_value} ); + barPoints->push_back( { currentBarPosition, barDef.m_value } ); if ( !barDef.m_barText.isEmpty() ) { - positionedBarLabels[currentBarPosition] = {QwtScaleDiv::MinorTick, barDef.m_barText}; + positionedBarLabels[currentBarPosition] = { QwtScaleDiv::MinorTick, barDef.m_barText }; } // Increment the bar position for the next bar diff --git a/ApplicationCode/UserInterface/RiuMultiPlotPage.cpp b/ApplicationCode/UserInterface/RiuMultiPlotPage.cpp index b72ffbe618..3344885ec9 100644 --- a/ApplicationCode/UserInterface/RiuMultiPlotPage.cpp +++ b/ApplicationCode/UserInterface/RiuMultiPlotPage.cpp @@ -622,7 +622,9 @@ void RiuMultiPlotPage::reinsertPlotWidgets() subTitles[visibleIndex]->setVisible( m_showSubTitles ); - plotWidgets[visibleIndex]->setAxisLabelsAndTicksEnabled( QwtPlot::yLeft, showYAxis( row, column ) ); + plotWidgets[visibleIndex]->setAxisLabelsAndTicksEnabled( QwtPlot::yLeft, + showYAxis( row, column ), + showYAxis( row, column ) ); plotWidgets[visibleIndex]->setAxisTitleEnabled( QwtPlot::yLeft, showYAxis( row, column ) ); plotWidgets[visibleIndex]->show(); diff --git a/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.cpp b/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.cpp index 71df814ae4..633b11ea58 100644 --- a/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.cpp +++ b/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.cpp @@ -33,3 +33,20 @@ QwtScaleDiv RiuQwtLinearScaleEngine::divideScaleWithExplicitIntervals( double x1 return QwtScaleDiv( x1, x2, minorTicks, minorTicks, majorTicks ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QwtScaleDiv RiuQwtLinearScaleEngine::divideScaleWithExplicitIntervalsAndRange( double tickStart, + double tickEnd, + double majorStepInterval, + double minorStepInterval, + double rangeStart, + double rangeEnd ) +{ + QwtInterval tickInterval( tickStart, tickEnd ); + QList majorTicks = this->buildMajorTicks( tickInterval, majorStepInterval ); + QList minorTicks = this->buildMajorTicks( tickInterval, minorStepInterval ); + + return QwtScaleDiv( rangeStart, rangeEnd, minorTicks, minorTicks, majorTicks ); +} diff --git a/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.h b/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.h index 7e4a81f02a..99a237f98a 100644 --- a/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.h +++ b/ApplicationCode/UserInterface/RiuQwtLinearScaleEngine.h @@ -28,5 +28,14 @@ class RiuQwtLinearScaleEngine : public QwtLinearScaleEngine { public: - QwtScaleDiv divideScaleWithExplicitIntervals( double x1, double x2, double majorStepInterval, double minorStepInterval ); + QwtScaleDiv divideScaleWithExplicitIntervals( double tickStart, + double tickEnd, + double majorStepInterval, + double minorStepInterval ); + QwtScaleDiv divideScaleWithExplicitIntervalsAndRange( double tickStart, + double tickEnd, + double majorStepInterval, + double minorStepInterval, + double rangeStart, + double rangeEnd ); }; diff --git a/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp b/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp index 4af8a7ce7e..065346a15c 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp @@ -162,11 +162,11 @@ int RiuQwtPlotWidget::axisValueFontSize( QwtPlot::Axis axis ) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQwtPlotWidget::setAxisFontsAndAlignment( QwtPlot::Axis axis, - int titleFontSize, - int valueFontSize, - bool titleBold, - Qt::AlignmentFlag alignment ) +void RiuQwtPlotWidget::setAxisFontsAndAlignment( QwtPlot::Axis axis, + int titleFontSize, + int valueFontSize, + bool titleBold, + int alignment ) { // Axis number font QFont axisFont = this->axisFont( axis ); @@ -308,10 +308,10 @@ void RiuQwtPlotWidget::setAxisInverted( QwtPlot::Axis axis ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuQwtPlotWidget::setAxisLabelsAndTicksEnabled( QwtPlot::Axis axis, bool enable ) +void RiuQwtPlotWidget::setAxisLabelsAndTicksEnabled( QwtPlot::Axis axis, bool enableLabels, bool enableTicks ) { - this->axisScaleDraw( axis )->enableComponent( QwtAbstractScaleDraw::Ticks, enable ); - this->axisScaleDraw( axis )->enableComponent( QwtAbstractScaleDraw::Labels, enable ); + this->axisScaleDraw( axis )->enableComponent( QwtAbstractScaleDraw::Ticks, enableTicks ); + this->axisScaleDraw( axis )->enableComponent( QwtAbstractScaleDraw::Labels, enableLabels ); recalculateAxisExtents( axis ); } @@ -360,6 +360,31 @@ void RiuQwtPlotWidget::setMajorAndMinorTickIntervals( QwtPlot::Axis axis, } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::setMajorAndMinorTickIntervalsAndRange( QwtPlot::Axis axis, + double majorTickInterval, + double minorTickInterval, + double minTickValue, + double maxTickValue, + double rangeMin, + double rangeMax ) +{ + RiuQwtLinearScaleEngine* scaleEngine = dynamic_cast( this->axisScaleEngine( axis ) ); + if ( scaleEngine ) + { + QwtScaleDiv scaleDiv = scaleEngine->divideScaleWithExplicitIntervalsAndRange( minTickValue, + maxTickValue, + majorTickInterval, + minorTickInterval, + rangeMin, + rangeMax ); + + this->setAxisScaleDiv( axis, scaleDiv ); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuQwtPlotWidget.h b/ApplicationCode/UserInterface/RiuQwtPlotWidget.h index ddf4fd1aba..74e9f1072c 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotWidget.h +++ b/ApplicationCode/UserInterface/RiuQwtPlotWidget.h @@ -71,10 +71,10 @@ public: int axisTitleFontSize( QwtPlot::Axis axis ) const; int axisValueFontSize( QwtPlot::Axis axis ) const; void setAxisFontsAndAlignment( QwtPlot::Axis, - int titleFontSize, - int valueFontSize, - bool titleBold = false, - Qt::AlignmentFlag alignment = Qt::AlignRight ); + int titleFontSize, + int valueFontSize, + bool titleBold = false, + int alignment = (int)Qt::AlignRight ); void setAxisTitleText( QwtPlot::Axis axis, const QString& title ); void setAxisTitleEnabled( QwtPlot::Axis axis, bool enable ); @@ -91,7 +91,7 @@ public: void setAxisRange( QwtPlot::Axis axis, double min, double max ); void setAxisInverted( QwtPlot::Axis axis ); - void setAxisLabelsAndTicksEnabled( QwtPlot::Axis axis, bool enable ); + void setAxisLabelsAndTicksEnabled( QwtPlot::Axis axis, bool enableLabels, bool enableTicks ); void enableGridLines( QwtPlot::Axis axis, bool majorGridLines, bool minorGridLines ); @@ -100,6 +100,13 @@ public: double minorTickInterval, double minValue, double maxValue ); + void setMajorAndMinorTickIntervalsAndRange( QwtPlot::Axis axis, + double majorTickInterval, + double minorTickInterval, + double minTickValue, + double maxTickValue, + double rangeMin, + double rangeMax ); void setAutoTickIntervalCounts( QwtPlot::Axis axis, int maxMajorTickIntervalCount, int maxMinorTickIntervalCount ); double majorTickInterval( QwtPlot::Axis axis ) const; double minorTickInterval( QwtPlot::Axis axis ) const;