Skip to content

Remove the plot customization dialog - #14034

Merged
MagnusSletten merged 5 commits into
equinor:mainfrom
MagnusSletten:style-redesign
Jul 29, 2026
Merged

Remove the plot customization dialog#14034
MagnusSletten merged 5 commits into
equinor:mainfrom
MagnusSletten:style-redesign

Conversation

@MagnusSletten

@MagnusSletten MagnusSletten commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Issue
Resolves #14021

Approach
This removes ERT's custom plot customization code, the dialog behind the pencil icon, its per-key config history and copy-between-keys support.

Per-key titles and axis labels move to dicts on the plot window and stay editable.
Statistics temporarily lose more than styling: because selection was expressed through line styles, choosing which statistics are drawn goes away too, along with the std dev multiplier and distribution connection lines.
These return in a follow-up PR as explicit toggles, decoupled from styling.

Visible changes:

No edit icon from customization dialog visiible:

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')

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 redesigns plot styling/customization in the GUI by replacing the old “Customize plot” dialog + per-key PlotConfig history with a new sidebar-based style editor and a refactored, role-based plotting style model.

Changes:

  • Replace the customization dialog workflow with new sidebar controls (StylePlotOptions) and per-key title/label storage in PlotWindow.
  • Refactor plotting styles into RenderMode/StyleRole + a frozen PlotStyle dataclass, and update plotters to consume Matplotlib keyword-style dictionaries.
  • Update/add unit tests for the new style controls and refactored plotting style behavior; remove tests tied to the deleted customization dialog/history.

Reviewed changes

Copilot reviewed 33 out of 34 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/ert/unit_tests/gui/tools/plot/test_plot_window.py Adjusts plot-window tests to work with new per-key plot text storage (title/labels).
tests/ert/unit_tests/gui/plotting/widgets/test_style_options.py Adds unit coverage for the new sidebar style options widget (presets, reset, visibility).
tests/ert/unit_tests/gui/plottery/test_plot_style.py Updates tests to validate the new PlotStyle/PlotConfig style-role behavior.
tests/ert/unit_tests/gui/plottery/test_plot_config_history.py Removes tests for PlotConfigHistory (feature removed).
tests/ert/unit_tests/gui/plottery/test_history.py Updates history plotting test assertions for the new style API (StyleRole + linewidth/linestyle fields).
tests/ert/ui_tests/gui/test_plot_customization.py Removes UI test for the old customization dialog (feature removed).
src/ert/gui/plotting/widgets/plot_widget.py Removes the toolbar “Customize” action and related signals.
src/ert/gui/plotting/widgets/plot_controls/style_options.py Introduces the new sidebar style editor widget (line styles, statistics presets, distribution toggles).
src/ert/gui/plotting/widgets/plot_controls/observation_color.py Switches ColorBox import to the new location under plot_controls.
src/ert/gui/plotting/widgets/plot_controls/custom_palette_dialog.py Switches ColorBox import to the new location under plot_controls.
src/ert/gui/plotting/widgets/plot_controls/color_chooser.py Adds the new ColorBox widget implementation under plot_controls.
src/ert/gui/plotting/widgets/plot_controls/init.py Exports StylePlotOptions from the plot_controls package.
src/ert/gui/plotting/widgets/copy_style_to_dialog.py Removes legacy “copy style to other keys” dialog (feature removed).
src/ert/gui/plotting/widgets/init.py Removes CopyStyleToDialog export (file removed).
src/ert/gui/plotting/utils/qt_creator.py Adds a new collapsible group-box helper for the sidebar sections.
src/ert/gui/plotting/utils/plot_style.py Replaces legacy mutable PlotStyle with a frozen dataclass and introduces StyleRole/RenderMode + presets/defaults.
src/ert/gui/plotting/utils/plot_config.py Refactors PlotConfig to be role-based and palette-resolving via style(role).
src/ert/gui/plotting/utils/plot_config_history.py Removes PlotConfigHistory (feature removed).
src/ert/gui/plotting/utils/plot_config_factory.py Removes PlotConfigFactory (feature removed).
src/ert/gui/plotting/utils/init.py Updates exports to match the new style model and removes old factory/history exports.
src/ert/gui/plotting/shared_plots/ensemble.py Updates ensemble plotting to use PlotStyle.line_properties() and StyleRole-based config.
src/ert/gui/plotting/plot_window.py Integrates the new sidebar style options and replaces old PlotCustomizer usage with per-key text + style options.
src/ert/gui/plotting/ert_plots/statistics.py Updates statistics plotting/legends to use StyleRole + RenderMode (area vs line) and Matplotlib keyword dicts.
src/ert/gui/plotting/ert_plots/observations.py Updates observation plotting to use StyleRole and new style field names (linestyle/linewidth/markersize).
src/ert/gui/plotting/ert_plots/history.py Updates history plotting to use StyleRole and line_properties().
src/ert/gui/plotting/ert_plots/histogram.py Updates histogram plotting to fetch the histogram role style via style(StyleRole.HISTOGRAM).
src/ert/gui/plotting/ert_plots/gaussian_kde.py Updates KDE plotting to use style(StyleRole.HISTOGRAM) and new linewidth field name.
src/ert/gui/plotting/ert_plots/distribution.py Updates distribution plotting to use StyleRole.DISTRIBUTION and StyleRole.DISTRIBUTION_LINE styles.
src/ert/gui/plotting/customization_dialog/style_customization_view.py Removes legacy dialog customization view (feature removed).
src/ert/gui/plotting/customization_dialog/style_chooser.py Removes legacy style chooser (feature removed).
src/ert/gui/plotting/customization_dialog/statistics_customization_view.py Removes legacy statistics customization view (feature removed).
src/ert/gui/plotting/customization_dialog/customize_plot_dialog.py Removes legacy customization dialog and PlotCustomizer implementation (feature removed).
src/ert/gui/plotting/customization_dialog/customization_view.py Removes legacy customization base view (feature removed).
src/ert/gui/plotting/customization_dialog/init.py Removes customization_dialog package exports (feature removed).

Comment on lines 6 to 10
from ert.gui.plotting.utils.logging_utils import log_plot_option_usage_once
from ert.gui.plotting.utils.plot_config import PlotConfig
from ert.gui.plotting.widgets.plot_controls.color_chooser import ColorBox

logger = logging.getLogger(__name__)
Comment on lines 13 to 17
from ert.gui.plotting.utils.logging_utils import log_plot_option_usage_once
from ert.gui.plotting.utils.plot_color_palettes import MINIMUM_COLOR_CYCLE_LENGTH
from ert.gui.plotting.widgets.plot_controls.color_chooser import ColorBox

logger = logging.getLogger(__name__)

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.

@MagnusSletten is this relevant still?

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.

Nope, not making any changes to the colorbox usage at this point. It's probably from an earlier state of the PR where it was larger redesign.

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 33 out of 34 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/ert/gui/plotting/widgets/plot_controls/style_options.py:408

  • StylePlotOptions only creates the statistics/distribution widgets when is_everest is False, but methods/properties like set_statistics_styles_visible(), set_distribution_styles_visible(), std_dev_factor, and distribution_lines_checkbox_state assume those attributes always exist. If any caller accesses these on an Everest instance, it will raise AttributeError at runtime (easy footgun since the class is exported publicly). Consider guarding these APIs and returning sensible defaults when the sections are not present.
    def set_statistics_styles_visible(self, visible: bool) -> None:
        self._statistics_options.setVisible(visible)

    def set_distribution_styles_visible(self, visible: bool) -> None:
        self._distribution_options.setVisible(visible)

    def styles(self) -> PlotStyles:
        return {role: row.style() for role, row in self._rows.items()}

    @property
    def std_dev_factor(self) -> int:
        return self._std_dev_factor.value()

    @property
    def distribution_lines_checkbox_state(self) -> bool:
        return self._toggle_distribution_lines.isChecked()

@MagnusSletten
MagnusSletten force-pushed the style-redesign branch 2 times, most recently from 416c766 to 08021d3 Compare July 28, 2026 12:40
@MagnusSletten MagnusSletten changed the title Style redesign Redesign plot style handling Jul 28, 2026
@ertomatic

Copy link
Copy Markdown
Collaborator

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

@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.83333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.78%. Comparing base (7a55556) to head (69bf6af).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/ert/gui/plotting/plot_window.py 95.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #14034      +/-   ##
==========================================
+ Coverage   91.52%   91.78%   +0.25%     
==========================================
  Files         488      480       -8     
  Lines       34092    33437     -655     
==========================================
- Hits        31204    30689     -515     
+ Misses       2888     2748     -140     
Flag Coverage Δ
cli-tests 36.80% <0.00%> (+0.70%) ⬆️
fuzz 44.03% <25.00%> (+0.30%) ⬆️
gui-tests 58.30% <54.16%> (-0.41%) ⬇️
performance-and-unit-tests 80.15% <95.83%> (+0.04%) ⬆️
test 46.35% <25.00%> (+0.34%) ⬆️

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

Files with missing lines Coverage Δ
src/ert/gui/plotting/utils/__init__.py 100.00% <ø> (ø)
src/ert/gui/plotting/widgets/__init__.py 100.00% <ø> (ø)
...ui/plotting/widgets/plot_controls/color_chooser.py 83.60% <ø> (ø)
...ing/widgets/plot_controls/custom_palette_dialog.py 100.00% <100.00%> (ø)
...lotting/widgets/plot_controls/observation_color.py 100.00% <100.00%> (ø)
src/ert/gui/plotting/widgets/plot_widget.py 88.15% <100.00%> (-0.87%) ⬇️
src/ert/gui/plotting/plot_window.py 78.34% <95.00%> (-1.17%) ⬇️

... and 4 files with indirect coverage changes

@MagnusSletten
MagnusSletten requested a review from eilskra July 28, 2026 13:05
@eilskra
eilskra requested a review from eqbech July 28, 2026 13:11
ertomatic pushed a commit to equinor/ert-testdata that referenced this pull request Jul 28, 2026
@MagnusSletten MagnusSletten changed the title Redesign plot style handling Remove the plot customization dialog Jul 28, 2026
@MagnusSletten
MagnusSletten requested a review from Copilot July 29, 2026 06:27
ertomatic pushed a commit to equinor/ert-testdata that referenced this pull request Jul 29, 2026

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 17 out of 18 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/ert/gui/plotting/plot_window.py:271

  • EnsembleSelectionWidget is initialized with len(TABLEAU_10_COLOR_CYCLE) (10), but the palette selector offers palettes with more colors (e.g. Color Brewer has 12). With the current hardcoded value, the extra colors can never be assigned to ensembles, so selecting a 12-color palette won’t actually use all available colors.
            self._ensemble_selection_widget = EnsembleSelectionWidget(
                plot_case_objects,
                len(TABLEAU_10_COLOR_CYCLE),
            )

The plot window previously copied its PlotConfig from PlotCustomizer.
This also maintained a PlotConfigHistory for each key, allowing styling,
titles, and axis labels to be edited and undone through ERT's
customization dialog.

After removing that dialog, only titles and axis labels require per-key
state. Store these overrides directly on the plot window in three
dictionaries keyed by plot key. A missing title falls back to the key
name, while missing axis labels remain None so each plotter can provide
its own defaults.

Rebuild the PlotConfig from PlotConfigFactory on every redraw. This
preserves the existing statistics defaults for each plot dimensionality.
@eilskra

eilskra commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Havent had time to review yet, but if I remember correctly from the meeting yesterday, did we not conclude to not opt-in for the matplotlib customization tool and keep it repressed as it lacked something/introduced some issue? @eqbech do you remember?

@MagnusSletten

MagnusSletten commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Havent had time to review yet, but if I remember correctly from the meeting yesterday, did we not conclude to not opt-in for the matplotlib customization tool and keep it repressed as it lacked something/introduced some issue? @eqbech do you remember?

It lacks proper handling of categories for lines and so the line customization is mostly useless. I can remove it. Title/axis labels is already handled by our implementation as well.

ERT replaced Matplotlib's Customize toolbar action with a gear button
opening its own dialog. With that dialog gone the gear no longer does
anything, so remove it. Matplotlib's own action is removed alongside it,
leaving no customization entry in the toolbar until the sidebar controls
land.
ertomatic pushed a commit to equinor/ert-testdata that referenced this pull request Jul 29, 2026
ertomatic pushed a commit to equinor/ert-testdata that referenced this pull request Jul 29, 2026
@MagnusSletten
MagnusSletten marked this pull request as ready for review July 29, 2026 07:15
@eilskra
eilskra requested a review from Copilot July 29, 2026 08:28
@eilskra eilskra added the release-notes:skip If there should be no mention of this in release notes label Jul 29, 2026

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 17 out of 18 changed files in this pull request and generated no new comments.

@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.

Looks very good, just a few comments for clarifications 👍 Outside of that, some considerations:

  • Have you ensure that the deleted files did not have any unforeseen other usage?
  • Does change observation color etc work as normal?
  • Bar unit-testing, has there been any manual testing of heat_equation and snake_oil to ensure that things work as intended?
  • Is Everest unaffected?

Comment on lines 13 to 17
from ert.gui.plotting.utils.logging_utils import log_plot_option_usage_once
from ert.gui.plotting.utils.plot_color_palettes import MINIMUM_COLOR_CYCLE_LENGTH
from ert.gui.plotting.widgets.plot_controls.color_chooser import ColorBox

logger = logging.getLogger(__name__)

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.

@MagnusSletten is this relevant still?

self._plot_customizer = PlotCustomizer(self, self._key_definitions)
self._plot_customizer.settingsChanged.connect(self.keySelected)
self._titles: dict[str, str] = {}
self._x_labels: dict[str, str | None] = {}

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.

Iirc the previous default was "Unnamed". Unsure if this is something we should keep or change. Thoughts?

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.

The default is "Unnamed" from the finalize_plots method itself but it's never actually used. All the finalize_plots calls use custom ones passed as parameters, e.g:

 default_x_label = "Date" if plot_context.is_date_support_active() else "Index"
        ...
        PlotTools.finalizePlot(
            plot_context,
            figure,
            axes,
            default_x_label=default_x_label,
            default_y_label="Value",
        )

So there's currently no change in behaviour when the labels are None.

Comment on lines +673 to +675
key_def = self.getSelectedKey()
if key_def is None:
return

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.

Can key_def ever be None?

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.

(method) def getSelectedKey(self: Self@PlotWindow) -> (PlotApiKeyDefinition | None)

At least according to the declared typing. I can check this behaviour though. The none-checks was also there prior to this PR.

else:
plot_config.set_y_label(new_label)
self._plot_customizer.update_plot_config(plot_config)
labels[key_def.key] = new_label

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.

Do we set it as None to trigger the default name?

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.

Yep!

Essentially because of this code in plot_tools.py:

if config.x_label() is None:
    config.set_x_label(default_x_label)

self.update_plot()

def _edit_title(self) -> None:
key_def = self.getSelectedKey()

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.

Similar question as on R673-675, if needed, should be extracted since repeated code

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.

Early return here cannot easily be extracted. The extraction would also take more lines of code than having the repeats of None-checks here. It can be shorter though, e.g

if (key_def := self.getSelectedKey()) is None:
    return

plot_config = plot_window._plot_customizer.get_plot_config()
plot_config.set_title("Custom title")
plot_window._plot_customizer.update_plot_config(plot_config)
plot_window._titles["some_key"] = "Custom title"

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.

Why are we not using the plot_config to set title here? Why are we overwriting the dictionary?

@MagnusSletten MagnusSletten Jul 29, 2026

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.

There's currently no reachable plot_config after the removal of plot_customizer. The dict is what persists titles/labels for each key. I think we can improve on plot_config handling in another PR.

@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:style-redesign (69bf6af) with main (697e484)

Open in CodSpeed

@eqbech eqbech 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.

Looks good, tested locally using poly_example. I did however notice that the legend option under general options did not toggle legends under the histogram plot? Has it always been that way or is that something introduced here?

@MagnusSletten

Copy link
Copy Markdown
Contributor Author

Have you ensure that the deleted files did not have any unforeseen other usage?

Prior to this PR the only use-case for it was the style customization for the elements still in the customizer. If per-key configuration of plots is wanted again in the future, this code would be useful, but that's still recoverable from history. It's probably better to rewrite it at that point as well.

Deleted:

customization_view.py - purely visual builder for customize_plot_dialog
customize_plot_dialog.py - customization widget + plotcustomizer class which held per key plotconfig-history
statistics_customization_view.py -- The one important, but temporary regression due to the toggles
style_chooser.py -- the line-style/marker/width/alpha picker widget used by the tabs above.
style_customization_view.py -- the style tab in the customization widget
plot_config_history.py -- only relevance was toggling between style states, also the sole caller of PlotConfig.copy_config_from
and create_copy, which are now dead, copy_style_to_dialog.py -- for the copy style buttons. Not used.

The one larger consequence is temporary and that's the lack of statistics customization.

Does change observation color etc work as normal?

Yep!

Bar unit-testing, has there been any manual testing of heat_equation and snake_oil to ensure that things work as intended?

Very frequent manual testing in snake_oil, but it does not hurt to have another manual test here if you want to quickly do it.

@MagnusSletten

MagnusSletten commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Looks good, tested locally using poly_example. I did however notice that the legend option under general options did not toggle legends under the histogram plot? Has it always been that way or is that something introduced here?

Happens on main as well @eqbech. There's some custom legend handling there, but that whole class is getting completely changed by upcoming pr #13985

@MagnusSletten
MagnusSletten requested a review from eilskra July 29, 2026 11:37

@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.

LGTM ✅

MagnusSletten pushed a commit to equinor/ert-testdata that referenced this pull request Jul 29, 2026
@MagnusSletten
MagnusSletten merged commit ae2f9f1 into equinor:main Jul 29, 2026
68 of 69 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-notes:skip If there should be no mention of this in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove line style customization

6 participants