Skip to content

Add options for statistics to sidebar - #14040

Merged
MagnusSletten merged 2 commits into
equinor:mainfrom
MagnusSletten:stats-addition
Jul 31, 2026
Merged

Add options for statistics to sidebar#14040
MagnusSletten merged 2 commits into
equinor:mainfrom
MagnusSletten:stats-addition

Conversation

@MagnusSletten

@MagnusSletten MagnusSletten commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Issue
Resolves #14030

Approach
Will add a simplified version of statistics controls to the sidebar, with toggles for different lines, e.g p50/p99.

It also turns out that some of the complications around style defaults and dimensionality was not warranted because 1 dimensional style defaults were in effect never used in the repository. This is simplified in the PR by removing the dimensionality specific styling code.

Visual changes

Added collapsible statistics panel:

image
  • PR title captures the intent of the changes, and is fitting for release notes.
  • Added appropriate release note label
  • Commit history is consistent and clean, in line with the contribution guidelines.
  • Make sure unit tests pass locally after every commit (git rebase -i main --exec 'just rapid-tests')

When applicable

  • When screenshots are changed: Review screenshot-PR in ert-testdata,
    merge screenshot-PR in ert-testdata before merging this PR.
  • When there are user facing changes: Updated documentation
  • New behavior or changes to existing untested code: Ensured that unit tests are added (See Ground Rules).
  • Large PR: Prepare changes in small commits for more convenient review
  • Bug fix: Add regression test for the bug
  • Bug fix: Add backport label to latest release (format: 'backport release-branch-name')

@ertomatic

Copy link
Copy Markdown
Collaborator

Screenshots differ from baselines. A baseline update PR has been prepared: equinor/ert-testdata#70

ertomatic pushed a commit to equinor/ert-testdata that referenced this pull request Jul 29, 2026
@codecov-commenter

codecov-commenter commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.82%. Comparing base (576dcf6) to head (fb84e73).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #14040      +/-   ##
==========================================
- Coverage   91.83%   91.82%   -0.02%     
==========================================
  Files         480      482       +2     
  Lines       33403    33444      +41     
==========================================
+ Hits        30676    30709      +33     
- Misses       2727     2735       +8     
Flag Coverage Δ
cli-tests 36.18% <0.00%> (-0.06%) ⬇️
fuzz 44.10% <45.00%> (+0.02%) ⬆️
gui-tests 58.41% <98.33%> (+0.07%) ⬆️
performance-and-unit-tests 80.38% <100.00%> (-0.08%) ⬇️
test 46.43% <45.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/ert/gui/plotting/plot_window.py 78.58% <100.00%> (+0.14%) ⬆️
src/ert/gui/plotting/utils/plot_config.py 92.51% <100.00%> (+0.12%) ⬆️
src/ert/gui/plotting/utils/qt_creator.py 100.00% <100.00%> (ø)
src/ert/gui/plotting/utils/statistics_style.py 100.00% <100.00%> (ø)
...ert/gui/plotting/widgets/plot_controls/__init__.py 100.00% <100.00%> (ø)
...otting/widgets/plot_controls/statistics_options.py 100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@codspeed-hq

codspeed-hq Bot commented Jul 29, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 36 untouched benchmarks


Comparing MagnusSletten:stats-addition (fb84e73) with main (576dcf6)

Open in CodSpeed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR moves a subset of plot “statistics customization” into the plot window sidebar by introducing explicit toggles (statistics visibility, area-vs-line bands, std-dev multiplier, and distribution connection lines), while removing the legacy plot customization dialog + its undo/redo config-history machinery.

Changes:

  • Add new sidebar control widgets for statistics and distribution options, and apply them when building PlotConfig per update.
  • Replace plot customizer/config-history usage with lightweight in-memory per-key title/x-label/y-label dictionaries.
  • Remove the old customization dialog implementation and related tests, and update imports to use the new plot-controls ColorBox.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/ert/unit_tests/gui/tools/plot/test_plot_window.py Update tests to reflect per-key title/axis-label storage (no PlotCustomizer).
tests/ert/unit_tests/gui/plottery/test_plot_config_history.py Remove tests for deleted PlotConfigHistory.
tests/ert/ui_tests/gui/test_plot_customization.py Remove UI test tied to the deleted customization dialog.
src/ert/gui/plotting/widgets/plot_widget.py Remove customization-trigger plumbing from the plot widget/toolbar.
src/ert/gui/plotting/widgets/plot_controls/statistics_options.py New sidebar widget for toggling statistics lines/bands + std-dev factor.
src/ert/gui/plotting/widgets/plot_controls/observation_color.py Switch ColorBox import to new plot-controls module.
src/ert/gui/plotting/widgets/plot_controls/distribution_options.py New sidebar widget for distribution connection lines toggle.
src/ert/gui/plotting/widgets/plot_controls/custom_palette_dialog.py Switch ColorBox import to new plot-controls module.
src/ert/gui/plotting/widgets/plot_controls/color_chooser.py New ColorBox implementation used by sidebar palette/observation color UI.
src/ert/gui/plotting/widgets/plot_controls/init.py Export new StatisticsOptions and DistributionOptions.
src/ert/gui/plotting/widgets/copy_style_to_dialog.py Delete dialog tied to legacy customization/copy workflow.
src/ert/gui/plotting/widgets/init.py Stop exporting removed CopyStyleToDialog.
src/ert/gui/plotting/utils/qt_creator.py Add collapsible group box + spinbox/labeled-row helpers for sidebar UI.
src/ert/gui/plotting/utils/plot_config_history.py Delete PlotConfigHistory implementation.
src/ert/gui/plotting/utils/init.py Stop exporting removed PlotConfigHistory.
src/ert/gui/plotting/plot_window.py Wire new sidebar options into PlotConfig creation and remove PlotCustomizer usage.
src/ert/gui/plotting/customization_dialog/style_customization_view.py Delete legacy customization dialog view.
src/ert/gui/plotting/customization_dialog/style_chooser.py Delete legacy style chooser.
src/ert/gui/plotting/customization_dialog/statistics_customization_view.py Delete legacy statistics customization view.
src/ert/gui/plotting/customization_dialog/customize_plot_dialog.py Delete legacy customization dialog + PlotCustomizer.
src/ert/gui/plotting/customization_dialog/customization_view.py Delete legacy customization dialog base view code.
src/ert/gui/plotting/customization_dialog/init.py Remove customization_dialog package exports.

Comment thread src/ert/gui/plotting/plot_window.py Outdated
Comment thread src/ert/gui/plotting/widgets/plot_controls/statistics_options.py Outdated
Comment thread src/ert/gui/plotting/widgets/plot_controls/distribution_options.py Outdated
Comment thread src/ert/gui/plotting/widgets/plot_widget.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

src/ert/gui/plotting/widgets/plot_controls/statistics_options.py:92

  • StatisticsOptions.apply_to introduces new behavior (mapping checkboxes to PlotConfig statistics styles, area-vs-lines behavior, and std dev multiplier), but there are currently no unit tests asserting that these controls actually update PlotConfig as intended. Adding focused tests for apply_to (e.g. enabling/disabling a statistic changes its line_style visibility, the Area toggle switches band line_style between "--" and "#", and the spinbox sets the standard deviation factor) would help prevent regressions.
    def apply_to(self, plot_config: PlotConfig) -> None:
        """Enable or disable each statistic according to its checkbox."""
        plot_config.set_standard_deviation_factor(self._std_dev_factor.value())
        fill_area = self._area_toggle.isChecked()
        for statistic, checkbox in self._toggles.items():
            style = plot_config.get_statistics_style(statistic)
            if not checkbox.isChecked():
                style.line_style = ""
                style.marker = ""
            elif statistic in _BAND_STATISTICS:
                style.line_style = _AREA_LINE_STYLE if fill_area else _BAND_LINE_STYLE
                style.marker = ""
            elif not style.is_visible():
                style.line_style = _LINE_STYLE_WHEN_ENABLED[statistic]
                style.marker = ""
            plot_config.set_statistics_style(statistic, style)

src/ert/gui/plotting/widgets/plot_controls/distribution_options.py:39

  • DistributionOptions.apply_to adds new plot behavior (toggling PlotConfig.set_distribution_line_enabled), but there is no corresponding unit test coverage for this new control. Please add a small test that toggling the checkbox results in the expected PlotConfig.is_distribution_line_enabled() value after apply_to.
    def apply_to(self, plot_config: PlotConfig) -> None:
        plot_config.set_distribution_line_enabled(
            self._connection_lines_toggle.isChecked()
        )

src/ert/gui/plotting/widgets/plot_controls/statistics_options.py:30

  • The default toggle states in _STATISTICS hard-code which statistics are shown (e.g. std defaults to False, p10-p90 defaults to True). This duplicates/overrides PlotConfigFactory’s dimensionality-based defaults (e.g. PlotConfigFactory enables std for 1D keys and p10-p90 for 2D keys), which can change the default plot output for 1D data and makes the factory defaults effectively irrelevant once these options are applied. Consider making a single source of truth for the defaults (either align these initial_checked values with PlotConfigFactory, or move the default-selection logic into apply_to based on the incoming PlotConfig/key dimensionality).
# (statistic, label, tooltip, checked by default)
_STATISTICS = [
    ("mean", "Mean", "Show or hide the mean", True),
    ("p50", "P50", "Show or hide the P50 line", False),
    ("std", "Std dev", "Show or hide the standard deviation band", False),
    ("min-max", "Min/Max", "Show or hide the min/max band", False),
    ("p10-p90", "P10-P90", "Show or hide the P10-P90 band", True),
    ("p33-p67", "P33-P67", "Show or hide the P33-P67 band", False),
]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

src/ert/gui/plotting/utils/qt_creator.py:118

  • Same issue as for checkboxes: QSpinBox.valueChanged emits the new integer value, and when the connection point is PlotWindow.update_plot this value is treated as the layer index. Changing the std-dev multiplier can therefore jump layers unexpectedly. Connect via a wrapper that discards the emitted value.
    spinbox.valueChanged.connect(connection_point)

src/ert/gui/plotting/utils/qt_creator.py:98

  • These sidebar controls connect Qt signals that emit values (e.g. 0/2 for checkboxes) directly to PlotWindow.update_plot. Since update_plot interprets its optional positional argument as the plot layer index, toggling a checkbox can unintentionally change the active layer (and fetch/std-dev data for the wrong layer) instead of just refreshing the plot. Wrap the connection point so the signal arguments are ignored.

This issue also appears on line 118 of the same file.

    checkbox.stateChanged.connect(connection_point)

@MagnusSletten
MagnusSletten force-pushed the stats-addition branch 3 times, most recently from 2ab52bf to cf5789f Compare July 31, 2026 07:00
@MagnusSletten
MagnusSletten marked this pull request as ready for review July 31, 2026 07:01
@@ -0,0 +1,26 @@
from __future__ import annotations

STATISTIC_LABELS = {

@eilskra eilskra Jul 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not important, but could this be simplified along the lines of outline below?

STATISTICS = {
    "mean": ("Mean", "-")
    "p50": ("P50", "--")
    "std": ("Std dev", "--")
....

Edit: highlighted that this is a question

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Named tuple looks quite nice here. Whole file becomes:

class StatisticStyle(NamedTuple):
    label: str
    line_style: str
    is_band: bool

STATISTICS = {
    "mean": StatisticStyle("Mean", "-", is_band=False),
    "p50": StatisticStyle("P50", "--", is_band=False),
    "std": StatisticStyle("Std dev", ":", is_band=True),
    "min-max": StatisticStyle("Min/Max", ":", is_band=True),
    "p10-p90": StatisticStyle("P10-P90", "--", is_band=True),
    "p33-p67": StatisticStyle("P33-P67", "-.", is_band=True),
}

BAND_AREA_STYLE = "#"

DEFAULT_ENABLED_STATISTICS = {"mean", "p10-p90"}

Comment on lines +18 to +24
"mean": "-",
"p50": "--",
"std": "--",
"min-max": "--",
"p10-p90": "--",
"p33-p67": "--",
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we include more styles? e.g .- etc

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Different defaults here is an improvement, I agree. For instance

STATISTICS_LINE_STYLES = {
    "mean": "-",
    "p50": "--",
    "std": ":",
    "min-max": ":",
    "p10-p90": "--",
    "p33-p67": "-.",
}

Comment thread src/ert/gui/plotting/utils/qt_creator.py Outdated
@MagnusSletten
MagnusSletten force-pushed the stats-addition branch 2 times, most recently from 19ad595 to 97c80da Compare July 31, 2026 10:09
@MagnusSletten
MagnusSletten requested a review from eilskra July 31, 2026 10:11

@eilskra eilskra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One curiosity and one potential simplification suggestion, they do not matter, so no need to implement. LGTM 👍

"p33-p67": PlotStyle("P33-P67", line_style=""),
"std": PlotStyle("Std dev", line_style=""),
statistic: PlotStyle(style.label, line_style="")
for statistic, style in STATISTICS.items()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is this needed? could we not in line 85 just do:

for statistic, style, _ in n STATISTICS.items():

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's shorthand for:

self._statistics_style = {}

for statistic, style in STATISTICS.items():
    self._statistics_style[statistic] = PlotStyle(
        style.label,
        line_style="",
    )

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I meant more, why do we need self._statistics_style = {}, could we not just use STATISTICS.items()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

statistics_style are the mutable style elements in the config file which is changed by the options.

STATISTICS.items() are just the defaults styles and the rules.

At least the line styles are changed with the band option. On/off switches as well.

Comment thread src/ert/gui/plotting/plot_window.py Outdated
elif fill_bands and STATISTICS[statistic].is_band:
style.line_style = BAND_AREA_STYLE
else:
style.line_style = STATISTICS[statistic].line_style

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This was the section I meant why we couldn't use STATISTICS.items() directly, but I see now it overwrites

Statistics styles were derived from the plot dimensionality, but they
are only read by the statistics plotter, which is always
dimensionality 2. The remaining branches were dead code.

Replace the coupling with an explicit selection of which statistics to
draw. This also simplifies statistics styling in general: each
statistic has a fixed style and is only turned on or off. The default
selection reproduces the previous appearance.
The statistics customization tab disappeared with the plot
customization dialog, leaving no way to choose which statistics to
show. Reintroduce the controls in the plot sidebar, letting the user
select statistics and whether bands are filled.
@MagnusSletten
MagnusSletten merged commit 810d16b into equinor:main Jul 31, 2026
35 checks passed
@MagnusSletten MagnusSletten added the improvement Something nice to have, that will make life easier for developers or users or both. label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Something nice to have, that will make life easier for developers or users or both.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move statistics customization to sidebar

5 participants