///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2021 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 "RimSummaryMultiPlot.h" #include "RiaApplication.h" #include "RiaPlotDefines.h" #include "RiaSummaryAddressAnalyzer.h" #include "RiaSummaryStringTools.h" #include "RifEclEclipseSummary.h" #include "RifEclipseRftAddress.h" #include "RifEclipseSummaryAddress.h" #include "RimEnsembleCurveSet.h" #include "RimMainPlotCollection.h" #include "RimMultiPlotCollection.h" #include "RimMultipleSummaryPlotNameHelper.h" #include "RimPlotAxisProperties.h" #include "RimProject.h" #include "RimSummaryAddress.h" #include "RimSummaryAddressModifier.h" #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" #include "RimSummaryCurve.h" #include "RimSummaryPlot.h" #include "RimSummaryPlotControls.h" #include "RimSummaryPlotNameHelper.h" #include "RimSummaryPlotSourceStepping.h" #include "RimSummaryTimeAxisProperties.h" #include "RiuSummaryMultiPlotBook.h" #include "RiuSummaryVectorSelectionUi.h" #include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiPushButtonEditor.h" #include "cafPdmUiTreeOrdering.h" #include "cafPdmUiTreeSelectionEditor.h" #include "qwt_scale_engine.h" #include #include namespace caf { template <> void AppEnum::setUp() { addItem( RimSummaryMultiPlot::AxisRangeAggregation::INDIVIDUAL, "INDIVIDUAL", "Individual" ); addItem( RimSummaryMultiPlot::AxisRangeAggregation::SUB_PLOTS, "SUB_PLOTS", "All Sub Plots" ); addItem( RimSummaryMultiPlot::AxisRangeAggregation::WELLS, "WELLS", "All Wells" ); addItem( RimSummaryMultiPlot::AxisRangeAggregation::REGIONS, "REGIONS", "All Regions" ); addItem( RimSummaryMultiPlot::AxisRangeAggregation::REALIZATIONS, "REALIZATIONS", "All Realizations" ); setDefault( RimSummaryMultiPlot::AxisRangeAggregation::INDIVIDUAL ); } } // namespace caf CAF_PDM_SOURCE_INIT( RimSummaryMultiPlot, "MultiSummaryPlot" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::setLayoutInfo( RimSummaryPlot* summaryPlot, int row, int col ) { m_gridLayoutInfo[summaryPlot] = std::make_pair( row, col ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::clearLayoutInfo() { m_gridLayoutInfo.clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimSummaryMultiPlot::RimSummaryMultiPlot() : duplicatePlot( this ) { CAF_PDM_InitObject( "Multi Summary Plot", ":/SummaryPlotLight16x16.png" ); this->setDeletable( true ); CAF_PDM_InitField( &m_autoPlotTitles, "AutoPlotTitles", true, "Auto Plot Titles" ); CAF_PDM_InitField( &m_autoPlotTitlesOnSubPlots, "AutoPlotTitlesSubPlots", true, "Auto Plot Titles Sub Plots" ); CAF_PDM_InitField( &m_createPlotDuplicate, "DuplicatePlot", false, "", "", "Duplicate Plot" ); m_createPlotDuplicate.xmlCapability()->disableIO(); m_createPlotDuplicate.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() ); m_createPlotDuplicate.uiCapability()->setUiIconFromResourceString( ":/Copy.svg" ); CAF_PDM_InitField( &m_disableWheelZoom, "DisableWheelZoom", true, "", "", "Disable Mouse Wheel Zooming in Multi Summary Plot" ); m_disableWheelZoom.xmlCapability()->disableIO(); m_disableWheelZoom.uiCapability()->setUiEditorTypeName( caf::PdmUiPushButtonEditor::uiEditorTypeName() ); m_disableWheelZoom.uiCapability()->setUiIconFromResourceString( ":/DisableZoom.png" ); CAF_PDM_InitField( &m_linkSubPlotAxes, "LinkSubPlotAxes", true, "Link Sub Plot Axes" ); CAF_PDM_InitField( &m_autoAdjustAppearance, "AutoAdjustAppearance", false, "Auto Adjust Appearance" ); CAF_PDM_InitFieldNoDefault( &m_axisRangeAggregation, "AxisRangeAggregation", "Axis Range Aggregation" ); CAF_PDM_InitFieldNoDefault( &m_sourceStepping, "SourceStepping", "" ); m_sourceStepping = new RimSummaryPlotSourceStepping; m_sourceStepping->setSourceSteppingType( RimSummaryDataSourceStepping::Axis::Y_AXIS ); m_sourceStepping->setSourceSteppingObject( this ); m_sourceStepping.uiCapability()->setUiTreeHidden( true ); m_sourceStepping.uiCapability()->setUiTreeChildrenHidden( true ); m_sourceStepping.xmlCapability()->disableIO(); m_nameHelper = std::make_unique(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimSummaryMultiPlot::~RimSummaryMultiPlot() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::addPlot( RimPlot* plot ) { auto* sumPlot = dynamic_cast( plot ); CVF_ASSERT( sumPlot != nullptr ); if ( sumPlot ) { RimMultiPlot::addPlot( plot ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::insertPlot( RimPlot* plot, size_t index ) { auto* sumPlot = dynamic_cast( plot ); CVF_ASSERT( sumPlot != nullptr ); if ( sumPlot ) { sumPlot->axisChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAxisChanged ); sumPlot->curvesChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged ); RimMultiPlot::insertPlot( plot, index ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::addPlot( const std::vector& objects ) { if ( objects.empty() ) return; auto* addr = dynamic_cast( objects[0] ); if ( addr ) { auto* plot = new RimSummaryPlot(); plot->enableAutoPlotTitle( true ); plot->handleDroppedObjects( objects ); addPlot( plot ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::removePlot( RimPlot* plot ) { auto* sumPlot = dynamic_cast( plot ); CVF_ASSERT( sumPlot != nullptr ); if ( sumPlot ) { RimMultiPlot::removePlot( plot ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::removePlotNoUpdate( RimPlot* plot ) { auto* sumPlot = dynamic_cast( plot ); CVF_ASSERT( sumPlot != nullptr ); if ( sumPlot ) { RimMultiPlot::removePlotNoUpdate( plot ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::updateAfterPlotRemove() { onPlotAdditionOrRemoval(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::availableAxes() const { return { RimSummaryDataSourceStepping::Axis::X_AXIS }; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::curvesForStepping( RimSummaryDataSourceStepping::Axis axis ) const { std::vector curves; for ( auto summaryPlot : summaryPlots() ) { for ( auto curve : summaryPlot->curvesForStepping( axis ) ) { curves.push_back( curve ); } } return curves; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::curveSets() const { std::vector curveSets; for ( auto summaryPlot : summaryPlots() ) { for ( auto curveSet : summaryPlot->curveSets() ) { curveSets.push_back( curveSet ); } } return curveSets; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::allCurves( RimSummaryDataSourceStepping::Axis axis ) const { std::vector curves; for ( auto summaryPlot : summaryPlots() ) { for ( auto curve : summaryPlot->allCurves( axis ) ) { curves.push_back( curve ); } } return curves; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::populateNameHelper( RimSummaryPlotNameHelper* nameHelper ) { nameHelper->clear(); std::vector addresses; std::vector sumCases; std::vector ensembleCases; for ( RimSummaryCurve* curve : allCurves( RimSummaryDataSourceStepping::Axis::Y_AXIS ) ) { addresses.push_back( curve->summaryAddressY() ); sumCases.push_back( curve->summaryCaseY() ); } for ( auto curveSet : curveSets() ) { addresses.push_back( curveSet->summaryAddress() ); ensembleCases.push_back( curveSet->summaryCaseCollection() ); } nameHelper->appendAddresses( addresses ); nameHelper->setSummaryCases( sumCases ); nameHelper->setEnsembleCases( ensembleCases ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { auto titlesGroup = uiOrdering.addNewGroup( "Main Plot Settings" ); titlesGroup->add( &m_autoPlotTitles ); titlesGroup->add( &m_showPlotWindowTitle ); titlesGroup->add( &m_plotWindowTitle ); titlesGroup->add( &m_titleFontSize ); auto subPlotSettingsGroup = uiOrdering.addNewGroup( "Sub Plot Settings" ); subPlotSettingsGroup->add( &m_autoPlotTitlesOnSubPlots ); subPlotSettingsGroup->add( &m_showIndividualPlotTitles ); subPlotSettingsGroup->add( &m_subTitleFontSize ); auto legendsGroup = uiOrdering.addNewGroup( "Legends" ); legendsGroup->add( &m_showPlotLegends ); legendsGroup->add( &m_plotLegendsHorizontal ); legendsGroup->add( &m_legendFontSize ); auto layoutGroup = uiOrdering.addNewGroup( "Layout" ); layoutGroup->add( &m_columnCount ); layoutGroup->add( &m_rowsPerPage ); auto axesGroup = uiOrdering.addNewGroup( "Axes" ); axesGroup->add( &m_axisRangeAggregation ); axesGroup->add( &m_linkSubPlotAxes ); axesGroup->add( &m_autoAdjustAppearance ); m_linkSubPlotAxes.uiCapability()->setUiReadOnly( m_autoAdjustAppearance() ); if ( m_autoAdjustAppearance() ) m_linkSubPlotAxes = false; auto dataSourceGroup = uiOrdering.addNewGroup( "Data Source" ); m_sourceStepping()->uiOrdering( uiConfigName, *dataSourceGroup ); uiOrdering.skipRemainingFields( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { if ( changedField == &m_autoPlotTitles || changedField == &m_autoPlotTitlesOnSubPlots ) { onLoadDataAndUpdate(); updateLayout(); } else if ( changedField == &m_linkSubPlotAxes || changedField == &m_axisRangeAggregation ) { syncAxisRanges(); } else if ( changedField == &m_createPlotDuplicate ) { m_createPlotDuplicate = false; duplicate(); } else if ( changedField == &m_autoAdjustAppearance ) { checkAndApplyAutoAppearance(); } else { RimMultiPlot::fieldChangedByUi( changedField, oldValue, newValue ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::updatePlotWindowTitle() { if ( m_autoPlotTitles ) { populateNameHelper( m_nameHelper.get() ); auto title = m_nameHelper->plotTitle(); if ( title.isEmpty() ) title = "Empty Plot"; setMultiPlotTitle( title ); } if ( m_autoPlotTitlesOnSubPlots ) { for ( auto plot : summaryPlots() ) { auto subPlotNameHelper = plot->plotTitleHelper(); // Disable auto plot, as this is required to be able to include the information in the multi plot title plot->enableAutoPlotTitle( false ); auto plotName = subPlotNameHelper->aggregatedPlotTitle( *m_nameHelper ); plot->setDescription( plotName ); plot->updatePlotTitle(); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RimSummaryNameHelper* RimSummaryMultiPlot::nameHelper() const { return m_nameHelper.get(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::setAutoTitlePlot( bool enable ) { m_autoPlotTitles = enable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::setAutoTitleGraphs( bool enable ) { m_autoPlotTitlesOnSubPlots = enable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::summaryPlots() const { std::vector typedPlots; for ( auto plot : plots() ) { auto summaryPlot = dynamic_cast( plot ); if ( summaryPlot ) typedPlots.push_back( summaryPlot ); } return typedPlots; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::visibleSummaryPlots() const { std::vector visiblePlots; for ( auto plot : summaryPlots() ) { if ( plot->showWindow() ) visiblePlots.push_back( plot ); } return visiblePlots; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimSummaryMultiPlot::fieldsToShowInToolbar() { std::vector toolBarFields; toolBarFields.push_back( &m_disableWheelZoom ); toolBarFields.push_back( &m_createPlotDuplicate ); auto& sourceObject = m_sourceStepping(); if ( sourceObject ) { auto fields = sourceObject->fieldsToShowInToolbar(); toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) ); } auto multiFields = RimMultiPlot::fieldsToShowInToolbar(); toolBarFields.insert( std::end( toolBarFields ), std::begin( multiFields ), std::end( multiFields ) ); return toolBarFields; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimSummaryMultiPlot::handleGlobalKeyEvent( QKeyEvent* keyEvent ) { if ( !RimSummaryPlotControls::handleKeyEvents( m_sourceStepping(), keyEvent ) ) { if ( isMouseCursorInsidePlot() ) { if ( keyEvent->key() == Qt::Key_PageUp ) { m_viewer->goToPrevPage(); return true; } else if ( keyEvent->key() == Qt::Key_PageDown ) { m_viewer->goToNextPage(); return true; } } return false; } return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimSummaryMultiPlot::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 RimSummaryMultiPlot::initAfterRead() { RimMultiPlot::initAfterRead(); for ( auto plot : summaryPlots() ) { plot->axisChanged.connect( this, &RimSummaryMultiPlot::onSubPlotAxisChanged ); plot->curvesChanged.connect( this, &RimSummaryMultiPlot::onSubPlotChanged ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::onLoadDataAndUpdate() { RimMultiPlot::onLoadDataAndUpdate(); checkAndApplyAutoAppearance(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::zoomAll() { syncAxisRanges(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::checkAndApplyAutoAppearance() { if ( m_autoAdjustAppearance ) { analyzePlotsAndAdjustAppearanceSettings(); syncAxisRanges(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::syncAxisRanges() { // Reset zoom to make sure the complete range for min/max is available RimMultiPlot::zoomAll(); if ( m_axisRangeAggregation() == AxisRangeAggregation::INDIVIDUAL ) { return; } else if ( m_axisRangeAggregation() == AxisRangeAggregation::SUB_PLOTS ) { std::map> axisRanges; // gather current min/max values for each category (axis label) for ( auto plot : summaryPlots() ) { for ( auto axis : plot->plotAxes() ) { double minVal = axis->visibleRangeMin(); double maxVal = axis->visibleRangeMax(); if ( axisRanges.count( axis->plotAxisType() ) == 0 ) { axisRanges[axis->plotAxisType()] = std::make_pair( axis->visibleRangeMin(), axis->visibleRangeMax() ); } else { auto& [currentMin, currentMax] = axisRanges[axis->plotAxisType()]; axisRanges[axis->plotAxisType()] = 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 : summaryPlots() ) { for ( auto axis : plot->plotAxes() ) { const auto& [minVal, maxVal] = axisRanges[axis->plotAxisType()]; axis->setAutoZoom( false ); axis->setVisibleRangeMin( minVal ); axis->setVisibleRangeMax( maxVal ); } plot->updateAxes(); } } else { computeAggregatedAxisRange(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::computeAggregatedAxisRange() { auto readValues = []( RimSummaryCase* summaryCase, RifEclipseSummaryAddress addr ) { std::vector values; if ( summaryCase && summaryCase->summaryReader() ) { RifSummaryReaderInterface* reader = summaryCase->summaryReader(); reader->values( addr, &values ); } return values; }; auto findMinMaxForSummaryCase = [readValues]( RimSummaryCase* summaryCase, RifEclipseSummaryAddress addr ) { auto values = readValues( summaryCase, addr ); if ( values.empty() ) return std::make_pair( HUGE_VAL, -HUGE_VAL ); auto minMaxPair = std::minmax_element( values.begin(), values.end() ); double caseMinimum = *minMaxPair.first; double caseMaximum = *minMaxPair.second; return std::make_pair( caseMinimum, caseMaximum ); }; auto summaryCasesForCurve = []( RimSummaryCurve* curve, AxisRangeAggregation axisRangeAggregation ) { std::vector summaryCases; if ( axisRangeAggregation == AxisRangeAggregation::REALIZATIONS ) { if ( curve->summaryCaseY() ) { auto ensemble = curve->summaryCaseY()->ensemble(); if ( ensemble ) { summaryCases = ensemble->allSummaryCases(); } else { summaryCases.push_back( curve->summaryCaseY() ); } } } else if ( axisRangeAggregation == AxisRangeAggregation::WELLS || axisRangeAggregation == AxisRangeAggregation::REGIONS ) { // Use only the current summary case when aggregation across wells/regions summaryCases.push_back( curve->summaryCaseY() ); } return summaryCases; }; auto addressesForCurve = []( RimSummaryCurve* curve, AxisRangeAggregation axisRangeAggregation ) { std::vector addresses; if ( axisRangeAggregation == AxisRangeAggregation::REALIZATIONS ) { RifEclipseSummaryAddress addr = RifEclipseSummaryAddress::fieldAddress( curve->summaryAddressY().quantityName() ); addresses = { addr }; } else if ( axisRangeAggregation == AxisRangeAggregation::WELLS || axisRangeAggregation == AxisRangeAggregation::REGIONS ) { RiaSummaryAddressAnalyzer analyzer; auto ensemble = curve->summaryCaseY()->ensemble(); if ( ensemble ) { analyzer.appendAddresses( ensemble->ensembleSummaryAddresses() ); } else { analyzer.appendAddresses( curve->summaryCaseY()->summaryReader()->allResultAddresses() ); } if ( axisRangeAggregation == AxisRangeAggregation::WELLS ) { for ( const auto& wellName : analyzer.wellNames() ) { addresses.push_back( RifEclipseSummaryAddress::wellAddress( curve->summaryAddressY().quantityName(), wellName ) ); } } if ( axisRangeAggregation == AxisRangeAggregation::REGIONS ) { for ( auto regionNumber : analyzer.regionNumbers() ) { addresses.push_back( RifEclipseSummaryAddress::regionAddress( curve->summaryAddressY().quantityName(), regionNumber ) ); } } } return addresses; }; auto findMinMaxForAddressesInSummaryCases = [findMinMaxForSummaryCase]( const std::vector& addresses, const std::vector& summaryCases ) { double minimum = HUGE_VAL; double maximum = -HUGE_VAL; for ( auto summaryCase : summaryCases ) { for ( const auto& addr : addresses ) { auto [caseMinimum, caseMaximum] = findMinMaxForSummaryCase( summaryCase, addr ); minimum = std::min( minimum, caseMinimum ); maximum = std::max( maximum, caseMaximum ); } } return std::make_pair( minimum, maximum ); }; // gather current min/max values for each category (axis label) for ( auto plot : summaryPlots() ) { std::map> axisRanges; for ( auto axis : plot->plotAxes() ) { for ( auto curve : plot->summaryAndEnsembleCurves() ) { if ( curve->axisY() == axis->plotAxisType() ) { std::vector summaryCases = summaryCasesForCurve( curve, m_axisRangeAggregation() ); std::vector addresses = addressesForCurve( curve, m_axisRangeAggregation() ); auto [minimum, maximum] = findMinMaxForAddressesInSummaryCases( addresses, summaryCases ); if ( axisRanges.count( axis->plotAxisType() ) == 0 ) { axisRanges[axis->plotAxisType()] = std::make_pair( minimum, maximum ); } else { auto& [currentMin, currentMax] = axisRanges[axis->plotAxisType()]; axisRanges[axis->plotAxisType()] = std::make_pair( std::min( currentMin, minimum ), std::max( currentMax, maximum ) ); } } } } // set all plots to use the global min/max values for each category for ( auto axis : plot->plotAxes() ) { QwtLinearScaleEngine scaleEngine; const auto& [minVal, maxVal] = axisRanges[axis->plotAxisType()]; if ( axis->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT && minVal <= maxVal ) { axis->setAutoZoom( false ); auto adjustedMin = minVal; auto adjustedMax = maxVal; if ( !axis->isLogarithmicScaleEnabled() ) { int maxMajorTickIntervalCount = 8; double stepSize = 0.0; scaleEngine.autoScale( maxMajorTickIntervalCount, adjustedMin, adjustedMax, stepSize ); } axis->setVisibleRangeMin( adjustedMin ); axis->setVisibleRangeMax( adjustedMax ); } } plot->updateAxes(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::summaryPlotItemInfos( QList* optionInfos ) const { for ( RimSummaryPlot* plot : summaryPlots() ) { QString displayName = plot->description(); optionInfos->push_back( caf::PdmOptionItemInfo( displayName, plot, false, plot->uiCapability()->uiIconProvider() ) ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::duplicate() { duplicatePlot.send( this ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::analyzePlotsAndAdjustAppearanceSettings() { RiaSummaryAddressAnalyzer analyzer; for ( auto p : summaryPlots() ) { auto addresses = RimSummaryAddressModifier::createEclipseSummaryAddress( p ); analyzer.appendAddresses( addresses ); } bool hasOnlyOneQuantity = analyzer.quantities().size() == 1; for ( auto p : summaryPlots() ) { auto timeAxisProp = p->timeAxisProperties(); if ( columnCount() < 3 ) timeAxisProp->setMajorTickmarkCount( RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_DEFAULT ); else timeAxisProp->setMajorTickmarkCount( RimPlotAxisProperties::LegendTickmarkCount::TICKMARK_FEW ); for ( RimPlotAxisPropertiesInterface* axisInterface : p->plotAxes() ) { auto axisProp = dynamic_cast( axisInterface ); if ( !axisProp ) continue; if ( rowsPerPage() == 1 ) axisProp->setMajorTickmarkCount( RimPlotAxisPropertiesInterface::LegendTickmarkCount::TICKMARK_DEFAULT ); else axisProp->setMajorTickmarkCount( RimPlotAxisPropertiesInterface::LegendTickmarkCount::TICKMARK_FEW ); axisProp->computeAndSetScaleFactor(); if ( hasOnlyOneQuantity ) { // Disable sub plot linking to be able to configure individually setSubPlotAxesLinked( false ); axisProp->setShowDescription( false ); auto [row, col] = gridLayoutInfoForSubPlot( p ); if ( col == 0 ) axisProp->setShowUnitText( true ); else axisProp->setShowUnitText( false ); } } p->updateAxes(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::makeSureIsVisible( RimSummaryPlot* summaryPlot ) { if ( summaryPlot->plotWidget() && !m_viewer.isNull() ) m_viewer->scrollToPlot( summaryPlot->plotWidget() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::setSubPlotAxesLinked( bool enable ) { m_linkSubPlotAxes = enable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimSummaryMultiPlot::isSubPlotAxesLinked() const { return m_linkSubPlotAxes(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::pair RimSummaryMultiPlot::gridLayoutInfoForSubPlot( RimSummaryPlot* summaryPlot ) const { auto it = m_gridLayoutInfo.find( summaryPlot ); if ( it != m_gridLayoutInfo.end() ) return it->second; return { -1, -1 }; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::onSubPlotChanged( const caf::SignalEmitter* emitter ) { updatePlotWindowTitle(); applyPlotWindowTitleToWidgets(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::onSubPlotAxisChanged( const caf::SignalEmitter* emitter, RimSummaryPlot* summaryPlot ) { if ( !m_linkSubPlotAxes() ) return; for ( auto plot : summaryPlots() ) { if ( plot != summaryPlot ) { plot->copyMatchingAxisPropertiesFromOther( *summaryPlot ); plot->updateAll(); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QWidget* RimSummaryMultiPlot::createViewWidget( QWidget* mainWindowParent ) { if ( m_viewer.isNull() ) { m_viewer = new RiuSummaryMultiPlotBook( this, mainWindowParent ); } recreatePlotWidgets(); return m_viewer; }