ResInsight/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp
Magne Sjaastad 945f1b1902
Use field auto values for summary plots
Use auto value concept in summary plot configuration. Default behavior is unchanged, but it is now possible to unlink a field to specify a custom value for this field.

Other changes:
* Add missing requirement for Svg in test application
* Use calculator icon and rename panel text
Use icon and relevant text to make it clear that the content in Calculator Data can be used for Grid Property Calculator and nothing else.
* Add example with scoped enum and auto value
* Use enum value starting av 10 to make sure enum values (not option item index) are working as expected
2022-09-05 14:12:49 +02:00

3018 lines
107 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2016 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimSummaryPlot.h"
#include "RiaColorTables.h"
#include "RiaColorTools.h"
#include "RiaDefines.h"
#include "RiaFieldHandleTools.h"
#include "RiaPlotDefines.h"
#include "RiaPreferences.h"
#include "RiaPreferencesSummary.h"
#include "RiaRegressionTestRunner.h"
#include "RiaStdStringTools.h"
#include "RiaSummaryAddressAnalyzer.h"
#include "RiaSummaryCurveDefinition.h"
#include "RiaSummaryTools.h"
#include "RiaTimeHistoryCurveResampler.h"
#include "RifReaderEclipseSummary.h"
#include "RicfCommandObject.h"
#include "SummaryPlotCommands/RicSummaryPlotEditorUi.h"
#include "PlotTemplates/RimPlotTemplateFileItem.h"
#include "PlotTemplates/RimPlotTemplateFolderItem.h"
#include "RimAsciiDataCurve.h"
#include "RimEnsembleCurveSet.h"
#include "RimEnsembleCurveSetCollection.h"
#include "RimGridTimeHistoryCurve.h"
#include "RimMultiPlot.h"
#include "RimPlotAxisLogRangeCalculator.h"
#include "RimPlotAxisProperties.h"
#include "RimProject.h"
#include "RimSummaryAddress.h"
#include "RimSummaryAddressCollection.h"
#include "RimSummaryCase.h"
#include "RimSummaryCurve.h"
#include "RimSummaryCurveCollection.h"
#include "RimSummaryCurvesData.h"
#include "RimSummaryPlotAxisFormatter.h"
#include "RimSummaryPlotControls.h"
#include "RimSummaryPlotFilterTextCurveSetEditor.h"
#include "RimSummaryPlotNameHelper.h"
#include "RimSummaryTimeAxisProperties.h"
#include "RiuPlotAxis.h"
#include "RiuPlotMainWindowTools.h"
#include "RiuQwtPlotCurve.h"
#include "RiuQwtPlotItem.h"
#include "RiuSummaryQwtPlot.h"
#include "RiuTreeViewEventFilter.h"
#ifdef USE_QTCHARTS
#include "RiuSummaryQtChartsPlot.h"
#endif
#include "cvfColor3.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include "cafSelectionManager.h"
#include "qwt_plot.h"
#include "qwt_plot_curve.h"
#include "qwt_plot_textlabel.h"
#include "qwt_text.h"
#include <QDateTime>
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>
#include <QRectF>
#include <QString>
#include <algorithm>
#include <limits>
#include <set>
CAF_PDM_SOURCE_INIT( RimSummaryPlot, "SummaryPlot" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlot::RimSummaryPlot( bool isCrossPlot )
: RimPlot()
, m_isCrossPlot( isCrossPlot )
, curvesChanged( this )
, axisChanged( this )
, m_isValid( true )
{
CAF_PDM_InitScriptableObject( "Summary Plot", ":/SummaryPlotLight16x16.png", "", "A Summary Plot" );
CAF_PDM_InitScriptableField( &m_useAutoPlotTitle, "IsUsingAutoName", true, "Auto Title" );
CAF_PDM_InitScriptableField( &m_description, "PlotDescription", QString( "Summary Plot" ), "Name" );
CAF_PDM_InitScriptableField( &m_normalizeCurveYValues, "normalizeCurveYValues", false, "Normalize all curves" );
#ifdef USE_QTCHARTS
bool useQtChart = RiaPreferences::current()->useQtChartsAsDefaultPlotType();
CAF_PDM_InitScriptableField( &m_useQtChartsPlot, "useQtChartsPlot", useQtChart, "Use Qt Charts" );
m_useQtChartsPlot.uiCapability()->setUiHidden( true );
#endif
CAF_PDM_InitFieldNoDefault( &m_summaryCurveCollection, "SummaryCurveCollection", "" );
m_summaryCurveCollection.uiCapability()->setUiTreeHidden( true );
m_summaryCurveCollection = new RimSummaryCurveCollection;
m_summaryCurveCollection->curvesChanged.connect( this, &RimSummaryPlot::onCurveCollectionChanged );
CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSetCollection, "EnsembleCurveSetCollection", "" );
m_ensembleCurveSetCollection.uiCapability()->setUiTreeHidden( true );
m_ensembleCurveSetCollection = new RimEnsembleCurveSetCollection();
CAF_PDM_InitFieldNoDefault( &m_gridTimeHistoryCurves, "GridTimeHistoryCurves", "" );
m_gridTimeHistoryCurves.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_asciiDataCurves, "AsciiDataCurves", "" );
m_asciiDataCurves.uiCapability()->setUiTreeHidden( true );
CAF_PDM_InitFieldNoDefault( &m_axisProperties, "AxisProperties", "Axes", ":/Axes16x16.png" );
if ( m_isCrossPlot )
{
addNewAxisProperties( RiuPlotAxis::defaultBottom(), "Bottom" );
}
else
{
auto* timeAxisProperties = new RimSummaryTimeAxisProperties;
timeAxisProperties->settingsChanged.connect( this, &RimSummaryPlot::axisSettingsChanged );
m_axisProperties.push_back( timeAxisProperties );
}
auto leftAxis = addNewAxisProperties( RiuPlotAxis::defaultLeft(), "Left" );
leftAxis->setAlwaysRequired( true );
auto rightAxis = addNewAxisProperties( RiuPlotAxis::defaultRight(), "Right" );
rightAxis->setAlwaysRequired( true );
CAF_PDM_InitFieldNoDefault( &m_textCurveSetEditor, "SummaryPlotFilterTextCurveSetEditor", "Text Filter Curve Creator" );
m_textCurveSetEditor.uiCapability()->setUiTreeHidden( true );
m_textCurveSetEditor = new RimSummaryPlotFilterTextCurveSetEditor;
m_nameHelperAllCurves = std::make_unique<RimSummaryPlotNameHelper>();
CAF_PDM_InitFieldNoDefault( &m_sourceStepping, "SourceStepping", "" );
m_sourceStepping = new RimSummaryPlotSourceStepping;
if ( m_isCrossPlot )
{
m_sourceStepping->setSourceSteppingType( RimSummaryDataSourceStepping::Axis::UNION_X_Y_AXIS );
}
else
{
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();
CAF_PDM_InitFieldNoDefault( &m_fallbackPlotName, "AlternateName", "AlternateName" );
m_fallbackPlotName.uiCapability()->setUiReadOnly( true );
m_fallbackPlotName.uiCapability()->setUiHidden( true );
m_fallbackPlotName.xmlCapability()->disableIO();
setPlotInfoLabel( "Filters Active" );
// Obsolete axis fields
CAF_PDM_InitFieldNoDefault( &m_leftYAxisProperties_OBSOLETE, "LeftYAxisProperties", "Left Y Axis" );
m_leftYAxisProperties_OBSOLETE.uiCapability()->setUiTreeHidden( true );
m_leftYAxisProperties_OBSOLETE.xmlCapability()->setIOWritable( false );
m_leftYAxisProperties_OBSOLETE = new RimPlotAxisProperties;
CAF_PDM_InitFieldNoDefault( &m_rightYAxisProperties_OBSOLETE, "RightYAxisProperties", "Right Y Axis" );
m_rightYAxisProperties_OBSOLETE.uiCapability()->setUiTreeHidden( true );
m_rightYAxisProperties_OBSOLETE.xmlCapability()->setIOWritable( false );
m_rightYAxisProperties_OBSOLETE = new RimPlotAxisProperties;
CAF_PDM_InitFieldNoDefault( &m_bottomAxisProperties_OBSOLETE, "BottomAxisProperties", "Bottom X Axis" );
m_bottomAxisProperties_OBSOLETE.uiCapability()->setUiTreeHidden( true );
m_bottomAxisProperties_OBSOLETE.xmlCapability()->setIOWritable( false );
m_bottomAxisProperties_OBSOLETE = new RimPlotAxisProperties;
CAF_PDM_InitFieldNoDefault( &m_timeAxisProperties_OBSOLETE, "TimeAxisProperties", "Time Axis" );
m_timeAxisProperties_OBSOLETE.uiCapability()->setUiTreeHidden( true );
m_timeAxisProperties_OBSOLETE.xmlCapability()->setIOWritable( false );
m_timeAxisProperties_OBSOLETE = new RimSummaryTimeAxisProperties;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlot::~RimSummaryPlot()
{
m_isValid = false;
removeMdiWindowFromMdiArea();
deletePlotCurvesAndPlotWidget();
delete m_summaryCurveCollection;
delete m_ensembleCurveSetCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxes()
{
updateAxis( RiaDefines::PlotAxis::PLOT_AXIS_LEFT );
updateAxis( RiaDefines::PlotAxis::PLOT_AXIS_RIGHT );
if ( m_summaryPlot ) m_summaryPlot->clearAnnotationObjects();
if ( timeAxisProperties() && plotWidget() )
{
m_summaryPlot->updateAnnotationObjects( timeAxisProperties() );
}
RimPlotAxisPropertiesInterface* leftYAxisProperties = axisPropertiesForPlotAxis( RiuPlotAxis::defaultLeft() );
if ( leftYAxisProperties && plotWidget() )
{
m_summaryPlot->updateAnnotationObjects( leftYAxisProperties );
}
if ( m_isCrossPlot )
{
updateAxis( RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM );
}
else
{
updateTimeAxis( timeAxisProperties() );
}
updateZoomInParentPlot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isLogarithmicScaleEnabled( RiuPlotAxis plotAxis ) const
{
auto axisProperties = axisPropertiesForPlotAxis( plotAxis );
if ( !axisProperties ) return false;
return axisProperties->isLogarithmicScaleEnabled();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryTimeAxisProperties* RimSummaryPlot::timeAxisProperties()
{
// Find the first time axis (which is correct since there is only one).
for ( const auto& ap : m_axisProperties )
{
auto* timeAxis = dynamic_cast<RimSummaryTimeAxisProperties*>( ap.p() );
if ( timeAxis ) return timeAxis;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
time_t RimSummaryPlot::firstTimeStepOfFirstCurve()
{
RimSummaryCurve* firstCurve = nullptr;
if ( m_summaryCurveCollection )
{
std::vector<RimSummaryCurve*> curves = m_summaryCurveCollection->curves();
size_t i = 0;
while ( firstCurve == nullptr && i < curves.size() )
{
firstCurve = curves[i];
++i;
}
}
if ( firstCurve && !firstCurve->timeStepsY().empty() )
{
return firstCurve->timeStepsY()[0];
}
return time_t( 0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* RimSummaryPlot::viewWidget()
{
return plotWidget();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPlotWidget* RimSummaryPlot::plotWidget()
{
if ( !m_summaryPlot ) return nullptr;
return m_summaryPlot->plotWidget();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::asciiDataForPlotExport() const
{
return asciiDataForSummaryPlotExport( RiaDefines::DateTimePeriod::YEAR, false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::asciiDataForSummaryPlotExport( RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString ) const
{
std::vector<RimSummaryCurve*> curves;
this->descendantsIncludingThisOfType( curves );
auto gridCurves = m_gridTimeHistoryCurves.children();
auto asciiCurves = m_asciiDataCurves.children();
QString text =
RimSummaryCurvesData::createTextForExport( curves, asciiCurves, gridCurves, resamplingPeriod, showTimeAsLongString );
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmObject* RimSummaryPlot::findPdmObjectFromPlotCurve( const RiuPlotCurve* plotCurve ) const
{
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
if ( curve->isSameCurve( plotCurve ) )
{
return curve;
}
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
if ( curve->isSameCurve( plotCurve ) )
{
return curve;
}
}
if ( m_summaryCurveCollection )
{
RimSummaryCurve* foundCurve = m_summaryCurveCollection->findRimCurveFromPlotCurve( plotCurve );
if ( foundCurve )
{
m_summaryCurveCollection->setCurrentSummaryCurve( foundCurve );
return foundCurve;
}
}
if ( m_ensembleCurveSetCollection )
{
RimSummaryCurve* foundCurve = m_ensembleCurveSetCollection->findRimCurveFromPlotCurve( plotCurve );
if ( foundCurve )
{
return foundCurve;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onAxisSelected( RiuPlotAxis axis, bool toggle )
{
RiuPlotMainWindowTools::showPlotMainWindow();
caf::PdmObject* itemToSelect = axisPropertiesForPlotAxis( axis );
RiuPlotMainWindowTools::selectOrToggleObject( itemToSelect, toggle );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::moveCurvesToPlot( RimSummaryPlot* plot, const std::vector<RimSummaryCurve*> curves, int insertAtPosition )
{
CAF_ASSERT( plot );
std::set<RimSummaryPlot*> srcPlots;
for ( auto curve : curves )
{
RimSummaryPlot* srcPlot = nullptr;
curve->firstAncestorOrThisOfTypeAsserted( srcPlot );
srcPlot->removeCurve( curve );
srcPlots.insert( srcPlot );
}
for ( auto srcPlot : srcPlots )
{
srcPlot->updateConnectedEditors();
srcPlot->loadDataAndUpdate();
}
for ( size_t cIdx = 0; cIdx < curves.size(); ++cIdx )
{
if ( insertAtPosition >= 0 )
{
size_t position = (size_t)insertAtPosition + cIdx;
plot->insertCurve( curves[cIdx], position );
}
else
{
plot->addCurveNoUpdate( curves[cIdx] );
}
}
plot->updateConnectedEditors();
plot->updateStackedCurveData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::curvesForStepping( RimSummaryDataSourceStepping::Axis axis ) const
{
auto curveForStepping = summaryCurveCollection()->curveForSourceStepping();
if ( curveForStepping )
{
return { curveForStepping };
}
return summaryCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEnsembleCurveSet*> RimSummaryPlot::curveSets() const
{
return ensembleCurveSetCollection()->curveSets();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::allCurves( RimSummaryDataSourceStepping::Axis axis ) const
{
return summaryCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryDataSourceStepping::Axis> RimSummaryPlot::availableAxes() const
{
if ( m_isCrossPlot )
return { RimSummaryDataSourceStepping::Axis::X_AXIS, RimSummaryDataSourceStepping::Axis::Y_AXIS };
return { RimSummaryDataSourceStepping::Axis::X_AXIS };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::summaryAndEnsembleCurves() const
{
std::vector<RimSummaryCurve*> curves = summaryCurves();
for ( const auto& curveSet : ensembleCurveSetCollection()->curveSets() )
{
for ( const auto& curve : curveSet->curves() )
{
curves.push_back( curve );
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaSummaryCurveDefinition> RimSummaryPlot::summaryAndEnsembleCurveDefinitions() const
{
std::set<RiaSummaryCurveDefinition> allCurveDefs;
for ( const auto& curve : this->summaryAndEnsembleCurves() )
{
allCurveDefs.insert(
RiaSummaryCurveDefinition( curve->summaryCaseY(), curve->summaryAddressY(), curve->isEnsembleCurve() ) );
}
return allCurveDefs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::summaryCurves() const
{
return m_summaryCurveCollection->curves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteAllSummaryCurves()
{
m_summaryCurveCollection->deleteAllCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCurveCollection* RimSummaryPlot::summaryCurveCollection() const
{
return m_summaryCurveCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::visibleStackedSummaryCurvesForAxis( RiuPlotAxis plotAxis )
{
auto visibleCurves = visibleSummaryCurvesForAxis( plotAxis );
std::vector<RimSummaryCurve*> visibleStackedCurves;
std::copy_if( visibleCurves.begin(),
visibleCurves.end(),
std::back_inserter( visibleStackedCurves ),
[]( RimSummaryCurve* curve ) { return curve->isStacked(); } );
return visibleStackedCurves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updatePlotTitle()
{
m_nameHelperAllCurves->clear();
updateNameHelperWithCurveData( m_nameHelperAllCurves.get() );
if ( m_useAutoPlotTitle )
{
m_description = m_nameHelperAllCurves->plotTitle();
}
if ( m_description().isEmpty() )
{
RimMultiPlot* plotWindow = nullptr;
firstAncestorOrThisOfType( plotWindow );
size_t index = 0;
if ( plotWindow ) index = plotWindow->plotIndex( this );
QString title = QString( "Sub Plot %1" ).arg( index + 1 );
m_fallbackPlotName = title;
}
updateCurveNames();
updateMdiWindowTitle();
if ( plotWidget() )
{
QString plotTitle = description();
plotWidget()->setPlotTitle( plotTitle );
plotWidget()->setPlotTitleEnabled( m_showPlotTitle && !isSubPlot() );
scheduleReplotIfVisible();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimSummaryNameHelper* RimSummaryPlot::activePlotTitleHelperAllCurves() const
{
if ( m_useAutoPlotTitle() )
{
return m_nameHelperAllCurves.get();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RimSummaryNameHelper* RimSummaryPlot::plotTitleHelper() const
{
return m_nameHelperAllCurves.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::copyAxisPropertiesFromOther( const RimSummaryPlot& sourceSummaryPlot )
{
for ( auto ap : sourceSummaryPlot.plotAxes() )
{
QString data = ap->writeObjectToXmlString();
axisPropertiesForPlotAxis( ap->plotAxisType() )
->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::copyAxisPropertiesFromOther( RiaDefines::PlotAxis plotAxisType, const RimSummaryPlot& sourceSummaryPlot )
{
for ( auto ap : sourceSummaryPlot.plotAxes() )
{
if ( ap->plotAxisType().axis() != plotAxisType ) continue;
QString data = ap->writeObjectToXmlString();
axisPropertiesForPlotAxis( ap->plotAxisType() )
->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::copyMatchingAxisPropertiesFromOther( const RimSummaryPlot& summaryPlot )
{
for ( auto apToCopy : summaryPlot.plotAxes() )
{
for ( auto ap : plotAxes() )
{
if ( ap->objectName().compare( apToCopy->objectName() ) == 0 )
{
QString data = apToCopy->writeObjectToXmlString();
ap->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAll()
{
if ( plotWidget() )
{
updatePlotTitle();
plotWidget()->updateLegend();
updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateLegend()
{
if ( plotWidget() )
{
plotWidget()->setInternalLegendVisible( m_showPlotLegends && !isSubPlot() );
for ( auto c : summaryCurves() )
{
c->updateLegendEntryVisibilityNoPlotUpdate();
}
}
reattachAllCurves();
if ( plotWidget() )
{
plotWidget()->updateLegend();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setPlotInfoLabel( const QString& label )
{
auto qwtText = QwtText( label );
qwtText.setRenderFlags( Qt::AlignBottom | Qt::AlignRight );
QFont font;
font.setBold( true );
qwtText.setFont( font );
m_plotInfoLabel = std::make_unique<QwtPlotTextLabel>();
m_plotInfoLabel->setText( qwtText );
m_plotInfoLabel->setMargin( 10 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::showPlotInfoLabel( bool show )
{
auto* qwtPlotWidget = dynamic_cast<RiuQwtPlotWidget*>( plotWidget() );
if ( !qwtPlotWidget ) return;
if ( show )
m_plotInfoLabel->attach( qwtPlotWidget->qwtPlot() );
else
m_plotInfoLabel->detach();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updatePlotInfoLabel()
{
bool anyCurveSetFiltered = false;
for ( auto group : m_ensembleCurveSetCollection->curveSets() )
{
if ( group->isFiltered() )
{
anyCurveSetFiltered = true;
break;
}
}
showPlotInfoLabel( anyCurveSetFiltered );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::containsResamplableCurves() const
{
std::vector<RimSummaryCurve*> summaryCurves = summaryAndEnsembleCurves();
size_t resamplableSummaryCurveCount =
std::count_if( summaryCurves.begin(), summaryCurves.end(), []( RimSummaryCurve* curve ) {
return curve->summaryCaseY() ? !curve->summaryCaseY()->isObservedData() : false;
} );
return !m_gridTimeHistoryCurves.empty() || resamplableSummaryCurveCount > 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimSummaryPlot::singleColorCurveCount() const
{
auto allCurveSets = ensembleCurveSetCollection()->curveSets();
size_t colorIndex = std::count_if( allCurveSets.begin(), allCurveSets.end(), []( RimEnsembleCurveSet* curveSet ) {
return curveSet->colorMode() == RimEnsembleCurveSet::ColorMode::SINGLE_COLOR;
} );
colorIndex += curveCount();
return colorIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::applyDefaultCurveAppearances()
{
applyDefaultCurveAppearances( summaryCurves() );
applyDefaultCurveAppearances( ensembleCurveSetCollection()->curveSets() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::applyDefaultCurveAppearances( std::vector<RimSummaryCurve*> curvesToUpdate )
{
std::set<RiaSummaryCurveDefinition> allCurveDefs = this->summaryAndEnsembleCurveDefinitions();
RimSummaryCurveAppearanceCalculator curveLookCalc( allCurveDefs );
for ( auto& curve : curvesToUpdate )
{
curve->resetAppearance();
curveLookCalc.setupCurveLook( curve );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::applyDefaultCurveAppearances( std::vector<RimEnsembleCurveSet*> ensembleCurvesToUpdate )
{
auto allCurveSets = ensembleCurveSetCollection()->curveSets();
for ( auto curveSet : ensembleCurvesToUpdate )
{
size_t colorIndex = 0;
auto it = std::find( allCurveSets.begin(), allCurveSets.end(), curveSet );
if ( it != allCurveSets.end() )
{
colorIndex = std::distance( allCurveSets.begin(), it );
}
if ( curveSet->colorMode() != RimEnsembleCurveSet::ColorMode::SINGLE_COLOR ) continue;
cvf::Color3f curveColor =
RimSummaryCurveAppearanceCalculator::computeTintedCurveColorForAddress( curveSet->summaryAddress(),
static_cast<int>( colorIndex ) );
auto adr = curveSet->summaryAddress();
if ( adr.isHistoryVector() ) curveColor = RiaPreferencesSummary::current()->historyCurveContrastColor();
curveSet->setColor( curveColor );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setNormalizationEnabled( bool enable )
{
m_normalizeCurveYValues = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isNormalizationEnabled()
{
return m_normalizeCurveYValues();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateAxis( RiaDefines::PlotAxis plotAxis )
{
if ( !plotWidget() ) return;
for ( RimPlotAxisPropertiesInterface* yAxisProperties : m_axisProperties )
{
RiuPlotAxis riuPlotAxis = yAxisProperties->plotAxisType();
if ( riuPlotAxis.axis() == plotAxis )
{
auto* axisProperties = dynamic_cast<RimPlotAxisProperties*>( yAxisProperties );
if ( axisProperties )
{
if ( yAxisProperties->isActive() && hasVisibleCurvesForAxis( riuPlotAxis ) )
{
plotWidget()->enableAxis( riuPlotAxis, true );
}
else
{
plotWidget()->enableAxis( riuPlotAxis, false );
}
if ( !hasVisibleCurvesForAxis( riuPlotAxis ) )
{
axisProperties->setNameForUnusedAxis();
}
else
{
std::set<QString> timeHistoryQuantities;
for ( auto c : visibleTimeHistoryCurvesForAxis( riuPlotAxis ) )
{
timeHistoryQuantities.insert( c->quantityName() );
}
std::vector<RiaSummaryCurveDefinition> curveDefs;
for ( auto summaryCurve : summaryCurves() )
{
if ( summaryCurve->axisY() != riuPlotAxis ) continue;
curveDefs.push_back( summaryCurve->curveDefinitionY() );
}
for ( auto curveSet : ensembleCurveSetCollection()->curveSets() )
{
if ( curveSet->axisY() != riuPlotAxis ) continue;
RiaSummaryCurveDefinition def( curveSet->summaryCaseCollection(), curveSet->summaryAddress() );
curveDefs.push_back( def );
}
RimSummaryPlotAxisFormatter calc( axisProperties,
{},
curveDefs,
visibleAsciiDataCurvesForAxis( riuPlotAxis ),
timeHistoryQuantities );
calc.applyAxisPropertiesToPlot( plotWidget() );
}
}
plotWidget()->enableAxisNumberLabels( riuPlotAxis, axisProperties->showNumbers() );
RimSummaryTimeAxisProperties::LegendTickmarkCount tickmarkCountEnum = axisProperties->majorTickmarkCount();
int maxTickmarkCount = RimPlotAxisPropertiesInterface::tickmarkCountFromEnum( tickmarkCountEnum );
plotWidget()->setAutoTickIntervalCounts( riuPlotAxis, maxTickmarkCount, maxTickmarkCount );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomForAxis( RiuPlotAxis plotAxis )
{
RimPlotAxisPropertiesInterface* yAxisProps = axisPropertiesForPlotAxis( plotAxis );
if ( !yAxisProps ) return;
if ( yAxisProps->isAutoZoom() )
{
if ( yAxisProps->isLogarithmicScaleEnabled() )
{
plotWidget()->setAxisScaleType( yAxisProps->plotAxisType(), RiuQwtPlotWidget::AxisScaleType::LOGARITHMIC );
std::vector<const RimPlotCurve*> plotCurves;
for ( RimSummaryCurve* c : visibleSummaryCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c );
}
for ( RimGridTimeHistoryCurve* c : visibleTimeHistoryCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c );
}
for ( RimAsciiDataCurve* c : visibleAsciiDataCurvesForAxis( plotAxis ) )
{
plotCurves.push_back( c );
}
double min, max;
RimPlotAxisLogRangeCalculator calc( plotAxis.axis(), plotCurves );
calc.computeAxisRange( &min, &max );
if ( yAxisProps->isAxisInverted() )
{
std::swap( min, max );
}
plotWidget()->setAxisScale( yAxisProps->plotAxisType(), min, max );
}
else if ( ( plotAxis.axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT ||
plotAxis.axis() == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT ) &&
isOnlyWaterCutCurvesVisible( plotAxis ) )
{
plotWidget()->setAxisScale( yAxisProps->plotAxisType(), 0.0, 1.0 );
}
else
{
plotWidget()->setAxisAutoScale( yAxisProps->plotAxisType(), true );
}
}
else
{
double min = yAxisProps->visibleRangeMin();
double max = yAxisProps->visibleRangeMax();
if ( yAxisProps->isAxisInverted() ) std::swap( min, max );
plotWidget()->setAxisScale( yAxisProps->plotAxisType(), min, max );
}
plotWidget()->setAxisInverted( yAxisProps->plotAxisType(), yAxisProps->isAxisInverted() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isOnlyWaterCutCurvesVisible( RiuPlotAxis plotAxis )
{
auto curves = visibleSummaryCurvesForAxis( plotAxis );
if ( curves.empty() ) return false;
size_t waterCutCurveCount = 0;
for ( auto c : curves )
{
auto quantityName = c->summaryAddressY().vectorName();
if ( RiaStdStringTools::endsWith( quantityName, "WCT" ) ) waterCutCurveCount++;
}
return ( waterCutCurveCount == curves.size() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::scheduleReplotIfVisible()
{
if ( showWindow() && plotWidget() ) plotWidget()->scheduleReplot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCurve*> RimSummaryPlot::visibleSummaryCurvesForAxis( RiuPlotAxis plotAxis ) const
{
std::vector<RimSummaryCurve*> curves;
if ( plotAxis.axis() == RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM )
{
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
if ( curve->isCurveVisible() )
{
curves.push_back( curve );
}
}
}
}
else
{
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
if ( curve->isCurveVisible() && curve->axisY() == plotAxis )
{
curves.push_back( curve );
}
}
}
if ( m_ensembleCurveSetCollection && m_ensembleCurveSetCollection->isCurveSetsVisible() )
{
for ( RimEnsembleCurveSet* curveSet : m_ensembleCurveSetCollection->curveSets() )
{
for ( RimSummaryCurve* curve : curveSet->curves() )
{
if ( curve->isCurveVisible() && curve->axisY() == plotAxis )
{
curves.push_back( curve );
}
}
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::hasVisibleCurvesForAxis( RiuPlotAxis plotAxis ) const
{
if ( !visibleSummaryCurvesForAxis( plotAxis ).empty() )
{
return true;
}
if ( !visibleTimeHistoryCurvesForAxis( plotAxis ).empty() )
{
return true;
}
if ( !visibleAsciiDataCurvesForAxis( plotAxis ).empty() )
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotAxisPropertiesInterface* RimSummaryPlot::axisPropertiesForPlotAxis( RiuPlotAxis plotAxis ) const
{
for ( RimPlotAxisPropertiesInterface* axisProperties : m_axisProperties )
{
if ( axisProperties->plotAxisType() == plotAxis ) return axisProperties;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridTimeHistoryCurve*> RimSummaryPlot::visibleTimeHistoryCurvesForAxis( RiuPlotAxis plotAxis ) const
{
std::vector<RimGridTimeHistoryCurve*> curves;
for ( const auto& c : m_gridTimeHistoryCurves )
{
if ( c->isCurveVisible() )
{
if ( c->yAxis() == plotAxis || plotAxis.axis() == RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM )
{
curves.push_back( c );
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimAsciiDataCurve*> RimSummaryPlot::visibleAsciiDataCurvesForAxis( RiuPlotAxis plotAxis ) const
{
std::vector<RimAsciiDataCurve*> curves;
for ( const auto& c : m_asciiDataCurves )
{
if ( c->isCurveVisible() )
{
if ( c->yAxis() == plotAxis || plotAxis.axis() == RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM )
{
curves.push_back( c );
}
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateTimeAxis( RimSummaryTimeAxisProperties* timeAxisProperties )
{
if ( !plotWidget() ) return;
if ( !timeAxisProperties->isActive() )
{
plotWidget()->enableAxis( RiuPlotAxis::defaultBottom(), false );
return;
}
if ( timeAxisProperties->timeMode() == RimSummaryTimeAxisProperties::DATE )
{
RiaDefines::DateFormatComponents dateComponents = timeAxisProperties->dateComponents();
RiaDefines::TimeFormatComponents timeComponents = timeAxisProperties->timeComponents();
const QString& dateFormat = timeAxisProperties->dateFormat();
const QString& timeFormat = timeAxisProperties->timeFormat();
m_summaryPlot->useDateBasedTimeAxis( dateFormat, timeFormat, dateComponents, timeComponents );
}
else
{
m_summaryPlot->useTimeBasedTimeAxis();
}
plotWidget()->enableAxis( RiuPlotAxis::defaultBottom(), true );
{
Qt::AlignmentFlag alignment = Qt::AlignCenter;
if ( timeAxisProperties->titlePosition() == RimPlotAxisPropertiesInterface::AXIS_TITLE_END )
{
alignment = Qt::AlignRight;
}
plotWidget()->setAxisFontsAndAlignment( RiuPlotAxis::defaultBottom(),
timeAxisProperties->titleFontSize(),
timeAxisProperties->valuesFontSize(),
true,
alignment );
plotWidget()->setAxisTitleText( RiuPlotAxis::defaultBottom(), timeAxisProperties->title() );
plotWidget()->setAxisTitleEnabled( RiuPlotAxis::defaultBottom(), timeAxisProperties->showTitle );
{
RimSummaryTimeAxisProperties::LegendTickmarkCount tickmarkCountEnum = timeAxisProperties->majorTickmarkCount();
int maxTickmarkCount = RimPlotAxisPropertiesInterface::tickmarkCountFromEnum( tickmarkCountEnum );
plotWidget()->setAxisMaxMajor( RiuPlotAxis::defaultBottom(), maxTickmarkCount );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateCaseNameHasChanged()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->updateCaseNameHasChanged();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addTimeAnnotation( time_t time )
{
RimSummaryTimeAxisProperties* axisProps = timeAxisProperties();
{
auto* annotation = new RimTimeAxisAnnotation;
annotation->setTime( time );
axisProps->appendAnnotation( annotation );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addTimeRangeAnnotation( time_t startTime, time_t endTime )
{
RimSummaryTimeAxisProperties* axisProps = timeAxisProperties();
{
auto* annotation = new RimTimeAxisAnnotation;
annotation->setTimeRange( startTime, endTime );
axisProps->appendAnnotation( annotation );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::removeAllTimeAnnotations()
{
RimSummaryTimeAxisProperties* axisProps = timeAxisProperties();
axisProps->removeAllAnnotations();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::zoomAll()
{
setAutoScaleXEnabled( true );
setAutoScaleYEnabled( true );
updateZoomInParentPlot();
axisChanged.send( this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addCurveAndUpdate( RimSummaryCurve* curve, bool autoAssignPlotAxis )
{
if ( curve )
{
m_summaryCurveCollection->addCurve( curve );
connectCurveToPlot( curve, true, autoAssignPlotAxis );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addCurveNoUpdate( RimSummaryCurve* curve, bool autoAssignPlotAxis )
{
if ( curve )
{
m_summaryCurveCollection->addCurve( curve );
connectCurveToPlot( curve, false, autoAssignPlotAxis );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::insertCurve( RimSummaryCurve* curve, size_t insertAtPosition )
{
if ( curve )
{
m_summaryCurveCollection->insertCurve( curve, insertAtPosition );
connectCurveToPlot( curve, false, true );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::connectCurveToPlot( RimSummaryCurve* curve, bool update, bool autoAssignPlotAxis )
{
if ( autoAssignPlotAxis ) assignPlotAxis( curve );
connectCurveSignals( curve );
if ( plotWidget() )
{
plotWidget()->ensureAxisIsCreated( curve->axisY() );
if ( update )
{
curve->setParentPlotAndReplot( plotWidget() );
this->updateAxes();
}
else
{
curve->setParentPlotNoReplot( plotWidget() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::removeCurve( RimSummaryCurve* curve )
{
m_summaryCurveCollection->removeCurve( curve );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurve( RimSummaryCurve* curve )
{
deleteCurves( { curve } );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurves( const std::vector<RimSummaryCurve*>& curves )
{
for ( const auto curve : curves )
{
if ( m_summaryCurveCollection )
{
for ( auto& c : m_summaryCurveCollection->curves() )
{
if ( c == curve )
{
disconnectCurveSignals( curve );
m_summaryCurveCollection->deleteCurve( curve );
continue;
}
}
}
if ( m_ensembleCurveSetCollection )
{
for ( auto& curveSet : m_ensembleCurveSetCollection->curveSets() )
{
for ( auto& c : curveSet->curves() )
{
if ( c == curve )
{
curveSet->deleteCurve( curve );
if ( curveSet->curves().empty() )
{
if ( curveSet->colorMode() == RimEnsembleCurveSet::ColorMode::BY_ENSEMBLE_PARAM &&
plotWidget() && curveSet->legendFrame() )
{
plotWidget()->removeOverlayFrame( curveSet->legendFrame() );
}
m_ensembleCurveSetCollection->deleteCurveSet( curveSet );
}
continue;
}
}
}
}
}
RiuPlotMainWindowTools::refreshToolbars();
updateCaseNameHasChanged();
curvesChanged.send();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteCurvesAssosiatedWithCase( RimSummaryCase* summaryCase )
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->deleteCurvesAssosiatedWithCase( summaryCase );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleCurveSetCollection* RimSummaryPlot::ensembleCurveSetCollection() const
{
return m_ensembleCurveSetCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addGridTimeHistoryCurve( RimGridTimeHistoryCurve* curve )
{
CVF_ASSERT( curve );
m_gridTimeHistoryCurves.push_back( curve );
if ( plotWidget() )
{
curve->setParentPlotAndReplot( plotWidget() );
this->updateAxes();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addGridTimeHistoryCurveNoUpdate( RimGridTimeHistoryCurve* curve )
{
CVF_ASSERT( curve );
m_gridTimeHistoryCurves.push_back( curve );
if ( plotWidget() )
{
curve->setParentPlotNoReplot( plotWidget() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimGridTimeHistoryCurve*> RimSummaryPlot::gridTimeHistoryCurves() const
{
return m_gridTimeHistoryCurves.children();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::addAsciiDataCruve( RimAsciiDataCurve* curve )
{
CVF_ASSERT( curve );
m_asciiDataCurves.push_back( curve );
if ( plotWidget() )
{
curve->setParentPlotAndReplot( plotWidget() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimSummaryPlot::userDescriptionField()
{
if ( m_description().isEmpty() )
{
return &m_fallbackPlotName;
}
return &m_description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
RimPlot::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_showPlotTitle || changedField == &m_description || changedField == &m_useAutoPlotTitle )
{
updatePlotTitle();
updateConnectedEditors();
if ( !m_useAutoPlotTitle )
{
// When auto name of plot is turned off, update the auto name for all curves
for ( auto c : summaryCurves() )
{
c->updateCurveNameNoLegendUpdate();
}
}
}
if ( changedField == &m_showPlotLegends ) updateLegend();
#ifdef USE_QTCHARTS
if ( changedField == &m_useQtChartsPlot )
{
// Hide window
setShowWindow( false );
// Detach and destroy plot curves
for ( auto c : summaryCurves() )
{
c->detach( true );
}
for ( auto& curveSet : this->ensembleCurveSetCollection()->curveSets() )
{
curveSet->deletePlotCurves();
}
// Destroy viewer
removeMdiWindowFromMdiArea();
deletePlotCurvesAndPlotWidget();
}
#endif
if ( changedField == &m_normalizeCurveYValues )
{
this->loadDataAndUpdate();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
{
updateStackedCurveData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateStackedCurveData()
{
auto anyStackedCurvesPresent = updateStackedCurveDataForRelevantAxes();
if ( plotWidget() && anyStackedCurvesPresent )
{
reattachAllCurves();
scheduleReplotIfVisible();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::updateStackedCurveDataForRelevantAxes()
{
bool anyStackedCurvesPresent = false;
for ( RimPlotAxisPropertiesInterface* axisProperties : m_axisProperties )
{
if ( axisProperties->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT ||
axisProperties->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT )
{
anyStackedCurvesPresent |= updateStackedCurveDataForAxis( axisProperties->plotAxisType() );
}
}
return anyStackedCurvesPresent;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::updateStackedCurveDataForAxis( RiuPlotAxis plotAxis )
{
auto stackedCurves = visibleStackedSummaryCurvesForAxis( plotAxis );
if ( stackedCurves.empty() ) return false;
std::map<RiaDefines::PhaseType, size_t> curvePhaseCount;
for ( RimSummaryCurve* curve : stackedCurves )
{
// Apply a area filled style if it isn't already set
if ( curve->fillStyle() == Qt::NoBrush )
{
curve->setFillStyle( Qt::SolidPattern );
}
curve->loadDataAndUpdate( false );
curvePhaseCount[curve->phaseType()]++;
}
{
// Z-position of curve, to draw them in correct order
double zPos = -10000.0;
std::vector<time_t> allTimeSteps;
for ( RimSummaryCurve* curve : stackedCurves )
{
allTimeSteps.insert( allTimeSteps.end(), curve->timeStepsY().begin(), curve->timeStepsY().end() );
}
std::sort( allTimeSteps.begin(), allTimeSteps.end() );
allTimeSteps.erase( std::unique( allTimeSteps.begin(), allTimeSteps.end() ), allTimeSteps.end() );
std::vector<double> allStackedValues( allTimeSteps.size(), 0.0 );
size_t stackIndex = 0u;
for ( RimSummaryCurve* curve : stackedCurves )
{
for ( size_t i = 0; i < allTimeSteps.size(); ++i )
{
double value = curve->yValueAtTimeT( allTimeSteps[i] );
if ( value != std::numeric_limits<double>::infinity() )
{
allStackedValues[i] += value;
}
}
curve->setOverrideCurveDataY( allTimeSteps, allStackedValues );
curve->setZOrder( zPos );
if ( curve->isStackedWithPhaseColors() )
{
curve->assignStackColor( stackIndex, curvePhaseCount[curve->phaseType()] );
}
zPos -= 1.0;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QImage RimSummaryPlot::snapshotWindowContent()
{
QImage image;
if ( plotWidget() )
{
QPixmap pix = plotWidget()->grab();
image = pix.toImage();
}
return image;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/ )
{
if ( !m_isValid ) return;
bool isPlotEditor = ( uiConfigName == RicSummaryPlotEditorUi::CONFIGURATION_NAME );
if ( !isPlotEditor ) uiTreeOrdering.add( &m_axisProperties );
for ( auto& curve : m_summaryCurveCollection->curves() )
{
uiTreeOrdering.add( curve );
}
if ( !m_isCrossPlot )
{
for ( auto& curveSet : m_ensembleCurveSetCollection->curveSets() )
{
uiTreeOrdering.add( curveSet );
}
}
if ( !isPlotEditor )
{
uiTreeOrdering.add( &m_gridTimeHistoryCurves );
uiTreeOrdering.add( &m_asciiDataCurves );
}
uiTreeOrdering.skipRemainingChildren( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onLoadDataAndUpdate()
{
updatePlotTitle();
RimMultiPlot* plotWindow = nullptr;
firstAncestorOrThisOfType( plotWindow );
if ( plotWindow == nullptr ) updateMdiWindowVisibility();
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->loadDataAndUpdate( false );
}
m_ensembleCurveSetCollection->loadDataAndUpdate( false );
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->loadDataAndUpdate( false );
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->loadDataAndUpdate( false );
}
if ( plotWidget() )
{
plotWidget()->setInternalLegendVisible( m_showPlotLegends && !isSubPlot() );
plotWidget()->setLegendFontSize( legendFontSize() );
plotWidget()->updateLegend();
}
this->updateAxes();
m_textCurveSetEditor->updateTextFilter();
updateStackedCurveData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomInParentPlot()
{
if ( !plotWidget() ) return;
for ( const auto& axisProperty : m_axisProperties )
{
updateZoomForAxis( axisProperty->plotAxisType() );
}
plotWidget()->updateAxes();
updateZoomFromParentPlot();
plotWidget()->updateZoomDependentCurveProperties();
scheduleReplotIfVisible();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateZoomFromParentPlot()
{
if ( !plotWidget() ) return;
for ( RimPlotAxisPropertiesInterface* axisProperties : m_axisProperties )
{
auto [axisMin, axisMax] = plotWidget()->axisRange( axisProperties->plotAxisType() );
if ( axisProperties->isAxisInverted() ) std::swap( axisMin, axisMax );
auto propertyAxis = dynamic_cast<RimPlotAxisProperties*>( axisProperties );
if ( propertyAxis )
{
propertyAxis->setAutoValueVisibleRangeMax( axisMax );
propertyAxis->setAutoValueVisibleRangeMin( axisMin );
}
else
{
axisProperties->setVisibleRangeMax( axisMax );
axisProperties->setVisibleRangeMin( axisMin );
}
axisProperties->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deletePlotCurvesAndPlotWidget()
{
if ( isDeletable() )
{
detachAllPlotItems();
if ( plotWidget() )
{
plotWidget()->setParent( nullptr );
}
deleteAllPlotCurves();
if ( m_summaryPlot )
{
m_summaryPlot.reset();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::connectCurveSignals( RimSummaryCurve* curve )
{
curve->dataChanged.connect( this, &RimSummaryPlot::curveDataChanged );
curve->visibilityChanged.connect( this, &RimSummaryPlot::curveVisibilityChanged );
curve->appearanceChanged.connect( this, &RimSummaryPlot::curveAppearanceChanged );
curve->stackingChanged.connect( this, &RimSummaryPlot::curveStackingChanged );
curve->stackingColorsChanged.connect( this, &RimSummaryPlot::curveStackingColorsChanged );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::disconnectCurveSignals( RimSummaryCurve* curve )
{
curve->dataChanged.disconnect( this );
curve->visibilityChanged.disconnect( this );
curve->appearanceChanged.disconnect( this );
curve->stackingChanged.disconnect( this );
curve->stackingColorsChanged.disconnect( this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::curveDataChanged( const caf::SignalEmitter* emitter )
{
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::curveVisibilityChanged( const caf::SignalEmitter* emitter, bool visible )
{
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::curveAppearanceChanged( const caf::SignalEmitter* emitter )
{
scheduleReplotIfVisible();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::curveStackingChanged( const caf::SignalEmitter* emitter, bool stacked )
{
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::curveStackingColorsChanged( const caf::SignalEmitter* emitter, bool stackWithPhaseColors )
{
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::connectAxisSignals( RimPlotAxisProperties* axis )
{
axis->settingsChanged.connect( this, &RimSummaryPlot::axisSettingsChanged );
axis->logarithmicChanged.connect( this, &RimSummaryPlot::axisLogarithmicChanged );
axis->axisPositionChanged.connect( this, &RimSummaryPlot::axisPositionChanged );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::axisSettingsChanged( const caf::SignalEmitter* emitter )
{
axisChanged.send( this );
updateAxes();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::axisLogarithmicChanged( const caf::SignalEmitter* emitter, bool isLogarithmic )
{
axisChanged.send( this );
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotAxisProperties* RimSummaryPlot::addNewAxisProperties( RiaDefines::PlotAxis plotAxis, const QString& name )
{
RiuPlotAxis newPlotAxis = plotWidget()->createNextPlotAxis( plotAxis );
return addNewAxisProperties( newPlotAxis, name );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPlotAxisProperties* RimSummaryPlot::addNewAxisProperties( RiuPlotAxis plotAxis, const QString& name )
{
auto* axisProperties = new RimPlotAxisProperties;
axisProperties->setNameAndAxis( name, name, plotAxis.axis(), plotAxis.index() );
m_axisProperties.push_back( axisProperties );
connectAxisSignals( axisProperties );
return axisProperties;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlotCurve*> RimSummaryPlot::visibleCurvesForLegend()
{
std::vector<RimPlotCurve*> curves;
for ( auto c : summaryCurves() )
{
if ( !c->isCurveVisible() ) continue;
if ( !c->showInLegend() ) continue;
curves.push_back( c );
}
for ( auto curveSet : curveSets() )
{
if ( !curveSet->isCurvesVisible() ) continue;
if ( curveSet->colorMode() == RimEnsembleCurveSetColorManager::ColorMode::SINGLE_COLOR )
{
auto curveSetCurves = curveSet->curves();
if ( !curveSetCurves.empty() ) curves.push_back( curveSetCurves.front() );
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::axisPositionChanged( const caf::SignalEmitter* emitter,
RimPlotAxisProperties* axisProperties,
RiuPlotAxis oldPlotAxis,
RiuPlotAxis newPlotAxis )
{
if ( !axisProperties ) return;
if ( plotWidget() && plotWidget()->isMultiAxisSupported() )
{
// Make sure the new axis on the correct side exists.
RiuPlotAxis fixedUpPlotAxis = plotWidget()->createNextPlotAxis( newPlotAxis.axis() );
// The index can change so need to update.
axisProperties->setNameAndAxis( axisProperties->objectName(),
axisProperties->axisTitleText(),
fixedUpPlotAxis.axis(),
fixedUpPlotAxis.index() );
// Move all attached curves
for ( auto curve : summaryCurves() )
{
if ( curve->axisY() == oldPlotAxis ) curve->setLeftOrRightAxisY( fixedUpPlotAxis );
}
for ( auto curveSet : ensembleCurveSetCollection()->curveSets() )
{
if ( curveSet->axisY() == oldPlotAxis ) curveSet->setLeftOrRightAxisY( fixedUpPlotAxis );
}
// Remove the now unused axis (but keep the default axis)
if ( oldPlotAxis != RiuPlotAxis::defaultLeft() && oldPlotAxis != RiuPlotAxis::defaultRight() )
{
auto oldAxisProperties = axisPropertiesForPlotAxis( oldPlotAxis );
if ( oldAxisProperties ) m_axisProperties.removeChild( oldAxisProperties );
plotWidget()->moveAxis( oldPlotAxis, newPlotAxis );
}
updateAxes();
}
// This is probably to much, but difficult to find the required updates
loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteAllGridTimeHistoryCurves()
{
m_gridTimeHistoryCurves.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setDescription( const QString& description )
{
m_description = description;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlot::description() const
{
return m_description();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::enableAutoPlotTitle( bool enable )
{
m_useAutoPlotTitle = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::autoPlotTitle() const
{
return m_useAutoPlotTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<int, std::vector<RimSummaryCurve*>> RimSummaryPlot::handleSummaryCaseDrop( RimSummaryCase* summaryCase )
{
int newCurves = 0;
std::vector<RimSummaryCurve*> curves;
std::map<RifEclipseSummaryAddress, std::set<RimSummaryCase*>> dataVectorMap;
for ( auto& curve : summaryCurves() )
{
const auto addr = curve->summaryAddressY();
dataVectorMap[addr].insert( curve->summaryCaseY() );
}
for ( const auto& [addr, cases] : dataVectorMap )
{
if ( cases.count( summaryCase ) > 0 ) continue;
curves.push_back( addNewCurveY( addr, summaryCase ) );
newCurves++;
}
return { newCurves, curves };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<int, std::vector<RimEnsembleCurveSet*>> RimSummaryPlot::handleEnsembleDrop( RimSummaryCaseCollection* ensemble )
{
int newCurves = 0;
std::vector<RimEnsembleCurveSet*> curveSetsToUpdate;
std::map<RifEclipseSummaryAddress, std::set<RimSummaryCaseCollection*>> dataVectorMap;
for ( auto& curve : curveSets() )
{
const auto addr = curve->summaryAddress();
dataVectorMap[addr].insert( curve->summaryCaseCollection() );
}
for ( const auto& [addr, ensembles] : dataVectorMap )
{
if ( ensembles.count( ensemble ) > 0 ) continue;
auto curveSet = addNewEnsembleCurveY( addr, ensemble );
curveSetsToUpdate.push_back( curveSet );
newCurves++;
}
return { newCurves, curveSetsToUpdate };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<int, std::vector<RimSummaryCurve*>>
RimSummaryPlot::handleAddressCollectionDrop( RimSummaryAddressCollection* addressCollection )
{
int newCurves = 0;
std::vector<RimSummaryCurve*> curves;
auto droppedName = addressCollection->name().toStdString();
auto summaryCase = RiaSummaryTools::summaryCaseById( addressCollection->caseId() );
auto ensembleCase = RiaSummaryTools::ensembleById( addressCollection->ensembleId() );
std::vector<RiaSummaryCurveDefinition> sourceCurveDefs;
std::map<RiaSummaryCurveDefinition, std::set<std::string>> newCurveDefsWithObjectNames;
if ( summaryCase && !ensembleCase )
{
for ( auto& curve : summaryCurves() )
{
sourceCurveDefs.push_back( curve->curveDefinitionY() );
}
}
if ( ensembleCase )
{
auto curveSets = m_ensembleCurveSetCollection->curveSets();
for ( auto curveSet : curveSets )
{
sourceCurveDefs.push_back( RiaSummaryCurveDefinition( ensembleCase, curveSet->summaryAddress() ) );
}
}
for ( auto& curveDef : sourceCurveDefs )
{
auto newCurveDef = curveDef;
auto curveAdr = newCurveDef.summaryAddress();
std::string objectIdentifierString;
if ( ( curveAdr.category() == RifEclipseSummaryAddress::SUMMARY_WELL ) &&
( addressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::WELL ) )
{
objectIdentifierString = curveAdr.wellName();
curveAdr.setWellName( droppedName );
newCurveDef.setSummaryAddress( curveAdr );
}
else if ( ( curveAdr.category() == RifEclipseSummaryAddress::SUMMARY_GROUP ) &&
( addressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::GROUP ) )
{
objectIdentifierString = curveAdr.groupName();
curveAdr.setGroupName( droppedName );
newCurveDef.setSummaryAddress( curveAdr );
}
else if ( ( curveAdr.category() == RifEclipseSummaryAddress::SUMMARY_REGION ) &&
( addressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::REGION ) )
{
objectIdentifierString = std::to_string( curveAdr.regionNumber() );
int droppedRegion = std::stoi( droppedName );
curveAdr.setRegion( droppedRegion );
newCurveDef.setSummaryAddress( curveAdr );
}
if ( !objectIdentifierString.empty() )
{
newCurveDefsWithObjectNames[newCurveDef].insert( objectIdentifierString );
const auto& addr = curveDef.summaryAddress();
if ( !addr.isHistoryVector() && RiaPreferencesSummary::current()->appendHistoryVectors() )
{
auto historyAddr = addr;
historyAddr.setVectorName( addr.vectorName() + RifReaderEclipseSummary::historyIdentifier() );
auto historyCurveDef = newCurveDef;
historyCurveDef.setSummaryAddress( historyAddr );
newCurveDefsWithObjectNames[historyCurveDef].insert( objectIdentifierString );
}
}
}
for ( auto& [curveDef, objectNames] : newCurveDefsWithObjectNames )
{
// Skip adding new curves if the object name is already present for the curve definition
if ( objectNames.count( droppedName ) > 0 ) continue;
if ( curveDef.ensemble() )
{
auto addresses = curveDef.ensemble()->ensembleSummaryAddresses();
if ( addresses.find( curveDef.summaryAddress() ) != addresses.end() )
{
addNewEnsembleCurveY( curveDef.summaryAddress(), curveDef.ensemble() );
newCurves++;
}
}
else if ( curveDef.summaryCase() )
{
if ( curveDef.summaryCase()->summaryReader() &&
curveDef.summaryCase()->summaryReader()->hasAddress( curveDef.summaryAddress() ) )
{
curves.push_back( addNewCurveY( curveDef.summaryAddress(), curveDef.summaryCase() ) );
newCurves++;
}
}
}
return { newCurves, curves };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<int, std::vector<RimSummaryCurve*>> RimSummaryPlot::handleSummaryAddressDrop( RimSummaryAddress* summaryAddr )
{
int newCurves = 0;
std::vector<RimSummaryCurve*> curves;
std::vector<RifEclipseSummaryAddress> newCurveAddresses;
newCurveAddresses.push_back( summaryAddr->address() );
if ( !summaryAddr->address().isHistoryVector() && RiaPreferencesSummary::current()->appendHistoryVectors() )
{
auto historyAddr = summaryAddr->address();
historyAddr.setVectorName( summaryAddr->address().vectorName() + RifReaderEclipseSummary::historyIdentifier() );
newCurveAddresses.push_back( historyAddr );
}
if ( summaryAddr->isEnsemble() )
{
std::map<RifEclipseSummaryAddress, std::set<RimSummaryCaseCollection*>> dataVectorMap;
for ( auto& curve : curveSets() )
{
const auto addr = curve->summaryAddress();
dataVectorMap[addr].insert( curve->summaryCaseCollection() );
}
auto ensemble = RiaSummaryTools::ensembleById( summaryAddr->ensembleId() );
if ( ensemble )
{
for ( const auto& droppedAddress : newCurveAddresses )
{
auto addresses = ensemble->ensembleSummaryAddresses();
if ( addresses.find( droppedAddress ) == addresses.end() ) continue;
bool skipAddress = false;
if ( dataVectorMap.count( droppedAddress ) > 0 )
{
skipAddress = ( dataVectorMap[droppedAddress].count( ensemble ) > 0 );
}
if ( !skipAddress )
{
addNewEnsembleCurveY( droppedAddress, ensemble );
newCurves++;
}
}
}
}
else
{
std::map<RifEclipseSummaryAddress, std::set<RimSummaryCase*>> dataVectorMap;
for ( auto& curve : summaryCurves() )
{
const auto addr = curve->summaryAddressY();
dataVectorMap[addr].insert( curve->summaryCaseY() );
}
auto summaryCase = RiaSummaryTools::summaryCaseById( summaryAddr->caseId() );
if ( summaryCase )
{
for ( const auto& droppedAddress : newCurveAddresses )
{
if ( !summaryCase->summaryReader() || !summaryCase->summaryReader()->hasAddress( droppedAddress ) )
continue;
bool skipAddress = false;
if ( dataVectorMap.count( droppedAddress ) > 0 )
{
skipAddress = ( dataVectorMap[droppedAddress].count( summaryCase ) > 0 );
}
if ( !skipAddress )
{
curves.push_back( addNewCurveY( droppedAddress, summaryCase ) );
newCurves++;
}
}
}
}
return { newCurves, curves };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::handleDroppedObjects( const std::vector<caf::PdmObjectHandle*>& objects )
{
int accumulatedCurveCount = 0;
std::vector<RimSummaryCurve*> curvesToUpdate;
std::vector<RimEnsembleCurveSet*> curveSetsToUpdate;
for ( auto obj : objects )
{
auto summaryCase = dynamic_cast<RimSummaryCase*>( obj );
if ( summaryCase )
{
auto [curveCount, curvesCreated] = handleSummaryCaseDrop( summaryCase );
accumulatedCurveCount += curveCount;
curvesToUpdate.insert( curvesToUpdate.end(), curvesCreated.begin(), curvesCreated.end() );
continue;
}
auto ensemble = dynamic_cast<RimSummaryCaseCollection*>( obj );
if ( ensemble )
{
auto [curveCount, curvesCreated] = handleEnsembleDrop( ensemble );
accumulatedCurveCount += curveCount;
curveSetsToUpdate.insert( curveSetsToUpdate.end(), curvesCreated.begin(), curvesCreated.end() );
continue;
}
auto summaryAddr = dynamic_cast<RimSummaryAddress*>( obj );
if ( summaryAddr )
{
auto [curveCount, curvesCreated] = handleSummaryAddressDrop( summaryAddr );
accumulatedCurveCount += curveCount;
curvesToUpdate.insert( curvesToUpdate.end(), curvesCreated.begin(), curvesCreated.end() );
continue;
}
auto addressCollection = dynamic_cast<RimSummaryAddressCollection*>( obj );
if ( addressCollection )
{
if ( addressCollection->isFolder() )
{
for ( auto coll : addressCollection->subFolders() )
{
auto [curveCount, curvesCreated] = handleAddressCollectionDrop( coll );
accumulatedCurveCount += curveCount;
curvesToUpdate.insert( curvesToUpdate.end(), curvesCreated.begin(), curvesCreated.end() );
}
continue;
}
else
{
auto [curveCount, curvesCreated] = handleAddressCollectionDrop( addressCollection );
accumulatedCurveCount += curveCount;
curvesToUpdate.insert( curvesToUpdate.end(), curvesCreated.begin(), curvesCreated.end() );
continue;
}
}
}
if ( accumulatedCurveCount > 0 )
{
applyDefaultCurveAppearances( curvesToUpdate );
applyDefaultCurveAppearances( curveSetsToUpdate );
loadDataAndUpdate();
curvesChanged.send();
}
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryCurve* RimSummaryPlot::addNewCurveY( const RifEclipseSummaryAddress& address, RimSummaryCase* summaryCase )
{
auto* newCurve = new RimSummaryCurve();
newCurve->setSummaryCaseY( summaryCase );
newCurve->setSummaryAddressYAndApplyInterpolation( address );
addCurveNoUpdate( newCurve );
return newCurve;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEnsembleCurveSet* RimSummaryPlot::addNewEnsembleCurveY( const RifEclipseSummaryAddress& address,
RimSummaryCaseCollection* ensemble )
{
auto* curveSet = new RimEnsembleCurveSet();
curveSet->setSummaryCaseCollection( ensemble );
curveSet->setSummaryAddress( address );
cvf::Color3f curveColor =
RimSummaryCurveAppearanceCalculator::computeTintedCurveColorForAddress( curveSet->summaryAddress(),
static_cast<int>(
ensembleCurveSetCollection()
->curveSetCount() ) );
auto adr = curveSet->summaryAddress();
if ( adr.isHistoryVector() ) curveColor = RiaPreferencesSummary::current()->historyCurveContrastColor();
curveSet->setColor( curveColor );
ensembleCurveSetCollection()->addCurveSet( curveSet );
return curveSet;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onPlotZoomed()
{
setAutoScaleXEnabled( false );
setAutoScaleYEnabled( false );
updateZoomFromParentPlot();
axisChanged.send( this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
{
auto group = uiOrdering.addNewGroup( "Data Source" );
m_sourceStepping()->uiOrdering( uiConfigName, *group );
}
caf::PdmUiGroup* mainOptions = uiOrdering.addNewGroup( "General Plot Options" );
#ifdef USE_QTCHARTS
mainOptions->add( &m_useQtChartsPlot );
#endif
if ( isMdiWindow() )
{
mainOptions->add( &m_showPlotTitle );
if ( m_showPlotTitle )
{
mainOptions->add( &m_useAutoPlotTitle );
mainOptions->add( &m_description );
}
}
else
{
mainOptions->add( &m_useAutoPlotTitle );
mainOptions->add( &m_description );
mainOptions->add( &m_colSpan );
}
m_description.uiCapability()->setUiReadOnly( m_useAutoPlotTitle );
if ( isMdiWindow() )
{
uiOrderingForPlotLayout( uiConfigName, *mainOptions );
}
mainOptions->add( &m_normalizeCurveYValues );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuPlotWidget* RimSummaryPlot::doCreatePlotViewWidget( QWidget* mainWindowParent )
{
if ( !plotWidget() )
{
#ifdef USE_QTCHARTS
bool useQtCharts = m_useQtChartsPlot;
auto regTestRunner = RiaRegressionTestRunner::instance();
if ( regTestRunner->isRunningRegressionTests() )
{
if ( regTestRunner->overridePlotEngine() == RiaRegressionTest::PlotEngine::USE_QWT )
useQtCharts = false;
else if ( regTestRunner->overridePlotEngine() == RiaRegressionTest::PlotEngine::USER_QTCHARTS )
useQtCharts = true;
}
// Disable all use of QtCharts for now. If a plot was created using QtCharts during the period this flag was
// active, the use of QtCharts was stored in the project file or template file. Set flag to false to force use
// of Qwt
useQtCharts = false;
if ( useQtCharts )
{
m_summaryPlot = std::make_unique<RiuSummaryQtChartsPlot>( this, mainWindowParent );
}
else
{
m_summaryPlot = std::make_unique<RiuSummaryQwtPlot>( this, mainWindowParent );
}
#else
m_summaryPlot = std::make_unique<RiuSummaryQwtPlot>( this, mainWindowParent );
#endif
for ( const auto& axisProperties : m_axisProperties )
{
plotWidget()->ensureAxisIsCreated( axisProperties->plotAxisType() );
}
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->setParentPlotNoReplot( plotWidget() );
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->setParentPlotNoReplot( plotWidget() );
}
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->setParentPlotNoReplot( plotWidget() );
}
if ( m_ensembleCurveSetCollection )
{
m_ensembleCurveSetCollection->setParentPlotNoReplot( plotWidget() );
}
this->connect( plotWidget(), SIGNAL( plotZoomed() ), SLOT( onPlotZoomed() ) );
updatePlotTitle();
}
plotWidget()->setParent( mainWindowParent );
return plotWidget();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteViewWidget()
{
deletePlotCurvesAndPlotWidget();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::initAfterRead()
{
RimViewWindow::initAfterRead();
if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2021.10.2" ) )
{
auto copyAxis = [this]( RiuPlotAxis axis, auto sourceObject ) {
auto axisProperties = axisPropertiesForPlotAxis( axis );
if ( axisProperties )
{
QString data = sourceObject->writeObjectToXmlString();
// This operation will overwrite the plot axis side, default is left
axisProperties->readObjectFromXmlString( data, caf::PdmDefaultObjectFactory::instance() );
auto plotAxisProperties = dynamic_cast<RimPlotAxisProperties*>( axisProperties );
if ( plotAxisProperties )
{
// Reset the plot axis for the axis property
plotAxisProperties->setNameAndAxis( axisProperties->objectName(),
axisProperties->axisTitleText(),
axis.axis(),
0 );
}
}
};
copyAxis( RiuPlotAxis::defaultLeft(), m_leftYAxisProperties_OBSOLETE.v() );
copyAxis( RiuPlotAxis::defaultRight(), m_rightYAxisProperties_OBSOLETE.v() );
if ( m_isCrossPlot )
copyAxis( RiuPlotAxis::defaultBottom(), m_bottomAxisProperties_OBSOLETE.v() );
else
copyAxis( RiuPlotAxis::defaultBottom(), m_timeAxisProperties_OBSOLETE.v() );
}
for ( const auto& axisProperties : m_axisProperties )
{
auto plotAxisProperties = dynamic_cast<RimPlotAxisProperties*>( axisProperties.p() );
if ( plotAxisProperties )
{
connectAxisSignals( plotAxisProperties );
}
auto* timeAxis = dynamic_cast<RimSummaryTimeAxisProperties*>( axisProperties.p() );
if ( timeAxis )
{
timeAxis->settingsChanged.connect( this, &RimSummaryPlot::axisSettingsChanged );
}
}
for ( auto curve : summaryCurves() )
{
connectCurveSignals( curve );
}
updateStackedCurveData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateNameHelperWithCurveData( RimSummaryPlotNameHelper* nameHelper ) const
{
if ( !nameHelper ) return;
nameHelper->clear();
std::vector<RifEclipseSummaryAddress> addresses;
std::vector<RimSummaryCase*> sumCases;
std::vector<RimSummaryCaseCollection*> ensembleCases;
if ( m_summaryCurveCollection && m_summaryCurveCollection->isCurvesVisible() )
{
for ( RimSummaryCurve* curve : m_summaryCurveCollection->curves() )
{
if ( curve->summaryAddressY().category() == RifEclipseSummaryAddress::SUMMARY_CALCULATED )
{
RiaSummaryTools::getSummaryCasesAndAddressesForCalculation( curve->summaryAddressY().id(),
sumCases,
addresses );
}
else
{
addresses.push_back( curve->summaryAddressY() );
sumCases.push_back( curve->summaryCaseY() );
if ( curve->summaryCaseX() )
{
sumCases.push_back( curve->summaryCaseX() );
if ( curve->summaryAddressX().category() != RifEclipseSummaryAddress::SUMMARY_INVALID )
{
addresses.push_back( curve->summaryAddressX() );
}
}
}
}
}
for ( auto curveSet : m_ensembleCurveSetCollection->curveSets() )
{
addresses.push_back( curveSet->summaryAddress() );
ensembleCases.push_back( curveSet->summaryCaseCollection() );
}
nameHelper->clear();
nameHelper->appendAddresses( addresses );
nameHelper->setSummaryCases( sumCases );
nameHelper->setEnsembleCases( ensembleCases );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::doUpdateLayout()
{
updateFonts();
this->loadDataAndUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::detachAllPlotItems()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->detachPlotCurves();
}
if ( m_ensembleCurveSetCollection )
{
m_ensembleCurveSetCollection->detachPlotCurves();
}
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->detach();
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->detach();
}
m_plotInfoLabel->detach();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::deleteAllPlotCurves()
{
for ( auto* c : summaryCurves() )
{
c->deletePlotCurve();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateCurveNames()
{
if ( m_summaryCurveCollection->isCurvesVisible() )
{
for ( auto c : summaryCurves() )
{
if ( c->isCurveVisible() )
{
c->updateCurveNameNoLegendUpdate();
}
}
}
for ( auto curveSet : m_ensembleCurveSetCollection->curveSets() )
{
curveSet->updateEnsembleLegendItem();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::detachAllCurves()
{
detachAllPlotItems();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::reattachAllCurves()
{
if ( m_summaryCurveCollection )
{
m_summaryCurveCollection->reattachPlotCurves();
}
m_ensembleCurveSetCollection->reattachPlotCurves();
for ( RimGridTimeHistoryCurve* curve : m_gridTimeHistoryCurves )
{
curve->reattach();
}
for ( RimAsciiDataCurve* curve : m_asciiDataCurves )
{
curve->reattach();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::handleGlobalKeyEvent( QKeyEvent* keyEvent )
{
return RimSummaryPlotControls::handleKeyEvents( sourceSteppingObjectForKeyEventHandling(), keyEvent );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onCurveCollectionChanged( const SignalEmitter* emitter )
{
curvesChanged.send();
updateStackedCurveData();
scheduleReplotIfVisible();
updateAllRequiredEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onPlotItemSelected( std::shared_ptr<RiuPlotItem> plotItem, bool toggle, int sampleIndex )
{
auto wrapper = dynamic_cast<RiuQwtPlotItem*>( plotItem.get() );
if ( !wrapper ) return;
auto qwtPlotItem = wrapper->qwtPlotItem();
if ( !qwtPlotItem ) return;
auto riuPlotCurve = dynamic_cast<RiuQwtPlotCurve*>( qwtPlotItem );
if ( !riuPlotCurve ) return;
auto rimPlotCurve = riuPlotCurve->ownerRimCurve();
RiuPlotMainWindowTools::selectOrToggleObject( rimPlotCurve, toggle );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlotSourceStepping* RimSummaryPlot::sourceSteppingObjectForKeyEventHandling() const
{
return m_sourceStepping;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::PdmFieldHandle*> RimSummaryPlot::fieldsToShowInToolbar()
{
std::vector<caf::PdmFieldHandle*> toolBarFields;
{
auto fields = m_textCurveSetEditor->fieldsToShowInToolbar();
toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) );
}
bool anyFieldsAvailableForSummary = false;
auto sourceObject = sourceSteppingObjectForKeyEventHandling();
if ( sourceObject )
{
auto fields = sourceObject->fieldsToShowInToolbar();
toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) );
anyFieldsAvailableForSummary = !fields.empty();
}
if ( !anyFieldsAvailableForSummary )
{
// Show ensemble stepping if no fields are available from summary stepping
auto fields = ensembleCurveSetCollection()->fieldsToShowInToolbar();
toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) );
}
return toolBarFields;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setAutoScaleXEnabled( bool enabled )
{
for ( const auto& ap : m_axisProperties )
{
if ( ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_TOP ||
ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM )
{
ap->setAutoZoom( enabled );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::setAutoScaleYEnabled( bool enabled )
{
for ( const auto& ap : m_axisProperties )
{
if ( ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT ||
ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT )
{
ap->setAutoZoom( enabled );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimSummaryPlot::curveCount() const
{
return m_summaryCurveCollection->curves().size() + m_gridTimeHistoryCurves.size() + m_asciiDataCurves.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlot::isDeletable() const
{
RimMultiPlot* plotWindow = nullptr;
firstAncestorOrThisOfType( plotWindow );
return plotWindow == nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlotAxisPropertiesInterface*> RimSummaryPlot::plotAxes() const
{
std::vector<RimPlotAxisPropertiesInterface*> axisProps;
for ( const auto& ap : m_axisProperties )
{
axisProps.push_back( ap );
}
return axisProps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlotAxisProperties*> RimSummaryPlot::plotYAxes() const
{
std::vector<RimPlotAxisProperties*> axisProps;
for ( const auto& ap : m_axisProperties )
{
auto plotAxisProp = dynamic_cast<RimPlotAxisProperties*>( ap.p() );
if ( plotAxisProp ) axisProps.push_back( plotAxisProp );
}
return axisProps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::assignPlotAxis( RimSummaryCurve* destinationCurve )
{
enum class AxisAssignmentStrategy
{
ALL_TO_LEFT,
ALL_TO_RIGHT,
ALTERNATING,
USE_MATCHING_UNIT
};
RiaDefines::PlotAxis plotAxis = RiaDefines::PlotAxis::PLOT_AXIS_LEFT;
auto strategy = AxisAssignmentStrategy::USE_MATCHING_UNIT;
if ( strategy == AxisAssignmentStrategy::USE_MATCHING_UNIT )
{
auto destinationUnit = destinationCurve->unitNameY();
bool isLeftUsed = false;
bool isRightUsed = false;
for ( auto c : summaryCurves() )
{
if ( c == destinationCurve ) continue;
if ( c->axisY() == RiuPlotAxis::defaultLeft() ) isLeftUsed = true;
if ( c->axisY() == RiuPlotAxis::defaultRight() ) isRightUsed = true;
auto currentUnit = c->unitNameY();
if ( currentUnit == destinationUnit )
{
for ( RimPlotAxisPropertiesInterface* axisProperties : m_axisProperties )
{
if ( axisProperties->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT ||
axisProperties->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT )
{
destinationCurve->setLeftOrRightAxisY( c->axisY() );
return;
}
}
}
}
if ( !isLeftUsed )
{
destinationCurve->setLeftOrRightAxisY( RiuPlotAxis::defaultLeft() );
return;
}
if ( !isRightUsed )
{
destinationCurve->setLeftOrRightAxisY( RiuPlotAxis::defaultRight() );
return;
}
strategy = AxisAssignmentStrategy::ALTERNATING;
}
if ( strategy == AxisAssignmentStrategy::ALTERNATING )
{
size_t axisCountLeft = 0;
size_t axisCountRight = 0;
for ( const auto& ap : m_axisProperties )
{
if ( ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_LEFT )
axisCountLeft++;
else if ( ap->plotAxisType().axis() == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT )
axisCountRight++;
}
if ( axisCountLeft > axisCountRight ) plotAxis = RiaDefines::PlotAxis::PLOT_AXIS_RIGHT;
}
else if ( strategy == AxisAssignmentStrategy::ALL_TO_LEFT )
{
plotAxis = RiaDefines::PlotAxis::PLOT_AXIS_LEFT;
}
else if ( strategy == AxisAssignmentStrategy::ALL_TO_RIGHT )
{
plotAxis = RiaDefines::PlotAxis::PLOT_AXIS_RIGHT;
}
RiuPlotAxis newPlotAxis = RiuPlotAxis::defaultLeft();
if ( plotWidget() && plotWidget()->isMultiAxisSupported() )
{
QString axisObjectName = "New Axis";
if ( !destinationCurve->summaryAddressY().uiText().empty() )
axisObjectName = QString::fromStdString( destinationCurve->summaryAddressY().uiText() );
newPlotAxis = plotWidget()->createNextPlotAxis( plotAxis );
addNewAxisProperties( newPlotAxis, axisObjectName );
}
destinationCurve->setLeftOrRightAxisY( newPlotAxis );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& referringObjects )
{
if ( childArray == &m_axisProperties )
{
for ( caf::PdmObjectHandle* reffingObj : referringObjects )
{
auto* curve = dynamic_cast<RimSummaryCurve*>( reffingObj );
auto* curveSet = dynamic_cast<RimEnsembleCurveSet*>( reffingObj );
if ( curve )
{
curve->setLeftOrRightAxisY( RiuPlotAxis::defaultLeft() );
}
else if ( curveSet )
{
curveSet->setLeftOrRightAxisY( RiuPlotAxis::defaultLeft() );
}
}
if ( plotWidget() )
{
std::set<RiuPlotAxis> usedPlotAxis;
for ( const auto& axisProperties : m_axisProperties )
{
usedPlotAxis.insert( axisProperties->plotAxisType() );
}
plotWidget()->pruneAxes( usedPlotAxis );
updateAxes();
scheduleReplotIfVisible();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlotSourceStepping* RimSummaryPlot::sourceStepper()
{
return m_sourceStepping();
}