From cb60a8b9ae03a159652edd9bf4cc729031bece54 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 23 Oct 2026 14:42:47 +0200 Subject: [PATCH] Avoid duplicate plots when appending wells and keep legend order same as project tree Skip appending plots for wells, groups and networks already present in the multi plot. Reattach curves in project tree order only when the attached order differs. --- ...RicAppendSummaryPlotsForObjectsFeature.cpp | 50 +++++++++++++++++++ .../Summary/RimSummaryPlot.cpp | 15 ++++++ .../UserInterface/RiuQwtPlotWidget.cpp | 33 ++++++++++++ .../UserInterface/RiuQwtPlotWidget.h | 3 ++ 4 files changed, 101 insertions(+) diff --git a/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp b/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp index 4e853629e9..c634bf1b99 100644 --- a/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp +++ b/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp @@ -64,11 +64,61 @@ void RicAppendSummaryPlotsForObjectsFeature::appendPlots( RimSummaryMultiPlot* caf::ProgressInfo info( sumAddressCollections.size(), "Appending plots..." ); + // Objects that already have a plot of their own are skipped to avoid duplicated plots. Plots showing several objects of the + // selected type do not count, as they are not a plot for each single object. Objects appended in this call are added to the set. + std::set existingObjects; + for ( auto sourcePlot : sourcePlots ) + { + RiaSummaryAddressAnalyzer analyzer; + analyzer.appendAddresses( RiaSummaryAddressModifier::allSummaryAddressesY( sourcePlot ) ); + + std::set names; + switch ( selectionType ) + { + case RimSummaryAddressCollection::CollectionContentType::WELL: + names = analyzer.wellNames(); + break; + case RimSummaryAddressCollection::CollectionContentType::GROUP: + names = analyzer.groupNames(); + break; + case RimSummaryAddressCollection::CollectionContentType::NETWORK: + names = analyzer.networkNames(); + break; + case RimSummaryAddressCollection::CollectionContentType::REGION: + for ( int regionNumber : analyzer.regionNumbers() ) + { + names.insert( std::to_string( regionNumber ) ); + } + break; + default: + break; + } + if ( names.size() == 1 ) existingObjects.insert( *names.begin() ); + } + + auto isDeduplicatedType = []( RimSummaryAddressCollection::CollectionContentType type ) + { + using CollectionContentType = RimSummaryAddressCollection::CollectionContentType; + return type == CollectionContentType::WELL || type == CollectionContentType::GROUP || type == CollectionContentType::NETWORK || + type == CollectionContentType::REGION; + }; + summaryMultiPlot->startBatchAddOperation(); RiaPlotWindowRedrawScheduler::instance()->blockUpdate( true ); for ( auto summaryAdrCollection : sumAddressCollections ) { + if ( isDeduplicatedType( summaryAdrCollection->contentType() ) ) + { + const auto objectName = summaryAdrCollection->name().toStdString(); + if ( !existingObjects.insert( objectName ).second ) + { + RiaLogging::info( "Skipped appending plots for '" + objectName + "', as it is already present." ); + info.incrementProgress(); + continue; + } + } + auto duplicatedPlots = RiaSummaryPlotTools::duplicateSummaryPlots( plotsForOneInstance ); for ( auto duplicatedPlot : duplicatedPlots ) diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index ca4e59454d..cfcf522491 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -2316,6 +2316,21 @@ void RimSummaryPlot::onLoadDataAndUpdate() if ( plotWidget() ) { + // Curves can be attached in a different order than the order in the project tree, and the + // legend follows the order of the attached plot items. Reattaching is costly for many curves, + // so only do it when the order differs. + auto* qwtPlotWidget = dynamic_cast( plotWidget() ); + if ( m_summaryCurveCollection && qwtPlotWidget ) + { + std::vector treeOrderCurves; + for ( auto curve : m_summaryCurveCollection->curves() ) + { + treeOrderCurves.push_back( curve ); + } + + if ( !qwtPlotWidget->isCurveOrderConsistentWith( treeOrderCurves ) ) m_summaryCurveCollection->updateCurveOrder(); + } + if ( m_showPlotLegends && !isSubPlot() ) { plotWidget()->insertLegend( m_legendPosition ); diff --git a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp index 3d681c30c8..f9a151d94b 100644 --- a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp @@ -1306,6 +1306,39 @@ std::vector> RiuQwtPlotWidget::highlightedCurves() return m_highlightedCurves; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuQwtPlotWidget::isCurveOrderConsistentWith( const std::vector& expectedOrder ) const +{ + std::map expectedIndex; + for ( size_t i = 0; i < expectedOrder.size(); i++ ) + { + expectedIndex[expectedOrder[i]] = i; + } + + // Plot items are sorted by z-value, and items with equal z-value are kept in attach order + bool hasPrevious = false; + double previousZ = 0.0; + size_t previousIdx = 0; + for ( const QwtPlotItem* plotItem : m_plot->itemList() ) + { + auto* riuPlotCurve = dynamic_cast( plotItem ); + if ( !riuPlotCurve ) continue; + + auto it = expectedIndex.find( riuPlotCurve->ownerRimCurve() ); + if ( it == expectedIndex.end() ) continue; + + if ( hasPrevious && plotItem->z() == previousZ && it->second < previousIdx ) return false; + + hasPrevious = true; + previousZ = plotItem->z(); + previousIdx = it->second; + } + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h index 963d6d49a0..ee9742eb07 100644 --- a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h @@ -167,6 +167,9 @@ public: void resetPlotItemHighlighting( bool doUpdateCurveOrder = true ); std::vector> highlightedCurves() const; + // True if curves with equal z-value are attached in the same relative order as in the given list + bool isCurveOrderConsistentWith( const std::vector& expectedOrder ) const; + // Highlights the plot item closest to the given position, given in widget coordinates. Unlike a left-click, this // only applies the visual highlight and does not change the project tree / selection manager selection. void highlightClosestPlotItemAtPosition( const QPoint& widgetPos );