Skip to content

Global curve appearance for summary plots - #14969

Merged
magnesj merged 4 commits into
devfrom
1136-global-curve-appearance
Oct 19, 2026
Merged

magnesj merged 4 commits into
devfrom
1136-global-curve-appearance

Conversation

@magnesj

@magnesj magnesj commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Fixes #12925

Adds a project-wide curve appearance for summary plots. When enabled, curve color and symbol are assigned from selected data dimensions (case, vector, well, group, region, etc.), so the same item looks the same in every plot.

  • Global settings choose the dimension controlling color and the dimension controlling symbol
  • Per-item rules can override the assigned appearance for a specific case, well or other item
  • New Curve Appearance dock window in the plot main window to select dimensions, palette and edit per-item rules
  • Applied to summary curves and ensemble curve sets, also when stepping sources or adding curve sets
  • The appearance before enabling is stored in the project and restored when the global appearance is disabled
  • caf: link support in labels, list and tree selection editor improvements, fix for nested child objects in PdmSettings write, and recreate a field editor when its field was deleted and a new field reused the address
Screen.Recording.2026-10-19.100856.mp4

@magnesj
magnesj marked this pull request as draft October 19, 2026 07:45
@magnesj
magnesj force-pushed the 1136-global-curve-appearance branch from 0cc9249 to 2b439c8 Compare October 19, 2026 07:47
@magnesj
magnesj requested a review from kriben October 19, 2026 07:48
@magnesj magnesj self-assigned this Oct 19, 2026
@magnesj
magnesj marked this pull request as ready for review October 19, 2026 07:48
Comment on lines +62 to +66
CAF_PDM_InitFieldNoDefault( &m_dimension, "Dimension", "Type" );
CAF_PDM_InitFieldNoDefault( &m_itemName, "ItemName", "Name" );

CAF_PDM_InitFieldNoDefault( &m_mode, "Mode", "Assignment" );
// m_mode.uiCapability()->setUiIconFromResourceString( ":/edit.svg" );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to get the names of the variable, display name and pdm-name more consistent to begin with?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also outcommented code. Uncomment or delete.

Comment on lines +479 to +482
return ":/summary/components/images/misc.svg";
case D::WELL:
case D::LGR:
return ":/summary/components/images/well.svg";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange that LGR uses well icon?

QPainter painter( &pixmap );
painter.drawPixmap( 0, 0, QIcon( dimensionIconPath( dimension ) ).pixmap( 16, 16 ) );

const QColor qColor = color ? QColor::fromRgbF( color->r(), color->g(), color->b() ) : QColor( Qt::black );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use RiaColorTools::toQColor?

Comment on lines +810 to +812
if ( rule->dimension() != colorDimension ) continue;
if ( auto overridden = rule->overriddenColor() ) color = overridden;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uncessary continue? && would be clearer?

@kriben kriben left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review (Open Code Review, delegate mode): 38/38 reviewable files reviewed. No critical or high-severity issues; 6 medium and 5 low findings are posted inline.

Checked with no issues: the cafPdmSettings nested-context fix, the findOrCreateFieldEditor same-address fix (~PdmUiItem clears the back-pointer), the switch to the non-abstract XML init macro, and the removal of the CurveAppearanceType AppEnum.

{
if ( auto overrides = project->curveStyleRules() )
{
if ( auto legendColor = overrides->autoLegendColor( colorIndex ) ) return *legendColor;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] The palette choice also changes plots that don't use the global appearance. cycledPaletteColor() always uses curveStyleRules()->autoLegendColor(), so the palette chosen in the Curve Appearance dock also applies to the normal colouring path and to the defaults applied when the global appearance is turned off. rulesChanged() only refreshes plots that use the global appearance, so other plots pick up the new palette later and inconsistently. Suggest only using the legend when useGlobalAppearance() is on, or passing the palette in explicitly.

Comment on lines +206 to +220
// Allow option icons larger than the default icon size
const int smallIcon = m_treeView->style()->pixelMetric( QStyle::PM_SmallIconSize );
QSize iconSize( smallIcon, smallIcon );
for ( const auto& option : options )
{
if ( auto icon = option.icon() )
{
const auto sizes = icon->availableSizes();
for ( const auto& size : sizes )
{
iconSize = iconSize.expandedTo( size );
}
}
}
m_treeView->setIconSize( iconSize );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] Larger icons in all tree-selection and list editors (same change in cafPdmUiListEditor.cpp ~L222). The icon size is set to the largest availableSizes() of any option. Option icons from raster resources larger than 16px (for example Case48x48.png, AppLogo48x48.png, AppendNext.png at 47x40) would make rows bigger across the app. Suggest making this opt-in through an editor attribute, or capping the size.

}
for ( auto plot : plotsToRestyle )
{
plot->updateCurveAppearanceFromGlobalSettings();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] Plots load their data twice. updateCurveAppearanceFromGlobalSettings() calls loadDataAndUpdate(), and the code below calls summaryPlot->loadDataAndUpdate() again for the same plots. Consider a restyle-only function that doesn't reload.

if ( m_dimension == Settings::Dimension::NONE ) return -1;

const auto value = Settings::dimensionValue( m_dimension, address, caseName );
const auto it = std::find( m_universe.begin(), m_universe.end(), value );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] Performance: repeated full address scans and linear lookups.

  • For WELL and non-CASE dimensions, availableNames walks allResultAddresses() of every summary case, including every ensemble member.
  • Outside an AvailableNamesCache scope (applyDefaultCurveAppearances, source stepping, RicNewSummaryEnsembleCurveSetFeature), each plot rescans up to three times (colour, symbol and ensemble indexers).
  • calculateValueOptions(m_currentItemIndex) repeats the scan on every UI refresh, and availableNames(NONE) does a full scan that can only return an empty list.
  • std::find here is O(curves x wells). A std::map<std::string,int> lookup would fix that.

RimStackablePlotCurve::stackingUiOrdering( *stackingGroup );

const auto plot = firstAncestorOrThisOfType<RimSummaryPlot>();
const bool isAppearanceGlobal = plot && plot->useGlobalCurveAppearance() && firstAncestorOrThisOfType<RimSummaryCurveCollection>();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] Curves are read-only even when nothing controls their appearance. The editor locks whenever the global appearance is on. If both dimensions are NONE, or the curve has no value for the selected dimension (a field vector with WELL selected, say), nothing sets the appearance but the user still can't edit it. RimEnsembleCurveSet::appendColorGroup has the same issue when globalColor() returns nothing.

std::set<std::string> values;
if ( dimension == Settings::Dimension::CASE || dimension == Settings::Dimension::WELL )
{
for ( const auto& name : RimCurveStyleRule::availableNames( dimension ) )

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Colours shift when cases or wells are added. CASE and WELL indices are positions in a sorted list of every name in the project. Adding a case or a well moves the index of everything sorted after it, so existing items change colour. That undercuts "same item looks the same in every plot".


for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
{
if ( !restoredPlots.contains( plot ) ) plot->applyDefaultCurveAppearances();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Curves added while the global appearance is on keep the global look after it is turned off, when their plot also has curves with saved appearances. Only plots with nothing saved get default appearances re-applied.

//--------------------------------------------------------------------------------------------------
void RimPlotCurveAppearance::copyFrom( const RimPlotCurveAppearance& other )
{
xmlCapability()->readObjectFromXmlString( other.xmlCapability()->writeObjectToXmlString(), caf::PdmDefaultObjectFactory::instance() );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Slow copy. Copying by writing and re-reading XML runs per curve per rule on every restyle. That is fine for small plots but slow with many curves.

CAF_PDM_InitFieldNoDefault( &m_itemName, "ItemName", "Name" );

CAF_PDM_InitFieldNoDefault( &m_mode, "Mode", "Assignment" );
// m_mode.uiCapability()->setUiIconFromResourceString( ":/edit.svg" );

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Small cleanups:

  • Commented-out code here.
  • Unused #include <QPointer> in RiuPlotMainWindow.cpp.
  • Unused #include <map> and class RimPlotCurve; in RimSummaryPlot.h.
  • The dock comment in RiuPlotMainWindow.cpp says the settings are "application wide", but they are stored in the project.

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RimCurveStyleSettingsTest, DimensionValues )

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Tests. They only cover defaults and dimensionValue. Nothing tests rulesFor ordering, the DimensionIndexer mapping, or saving and restoring appearances when the global appearance is turned on and off.

@magnesj
magnesj force-pushed the 1136-global-curve-appearance branch from aebc603 to d04e109 Compare October 19, 2026 12:53
@magnesj
magnesj merged commit c7473c2 into dev Oct 19, 2026
23 checks passed
@magnesj
magnesj deleted the 1136-global-curve-appearance branch October 19, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Summary Plots: Define curve color (appearance) per simulation case for case comparison

2 participants