From 5b086ac9ae0bcedd055749e837313595cbe8066b Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 18 Aug 2026 17:18:16 +0100 Subject: [PATCH 1/5] matplotlib defaults are set when creating export figures --- rascal2/widgets/plot.py | 46 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index a90ce0c5..7e6da378 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -386,9 +386,27 @@ def export(self): """Save the figure to a file.""" filepath, accepted = QtWidgets.QFileDialog.getSaveFileName(self, "Export Plot", filter="Image File (*.png)") if accepted: - sx = self.figure.get_figwidth() * self.figure.dpi - dpi = self.figure.dpi if sx > 1920 else 1920 // self.figure.get_figwidth() - self.figure.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) + temp_fig = self.make_figure() + sx = temp_fig.get_figwidth() * temp_fig.dpi + dpi = temp_fig.dpi if sx > 1920 else 1920 // temp_fig.get_figwidth() + matplotlib.style.use("default") + self.plot_temp_fig(temp_fig) + axes = temp_fig.axes + for ax in axes: + ax.patch.set_facecolor("white") + ax.spines["bottom"].set_color("black") + ax.spines["top"].set_color("black") + ax.spines["right"].set_color("black") + ax.spines["left"].set_color("black") + temp_fig.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) + if get_correct_qt_color_scheme() == QtCore.Qt.ColorScheme.Light: + matplotlib.style.use("default") + else: + matplotlib.style.use("dark_background") + + def plot_temp_fig(self, temp_fig): + """Plot a temporary figure which is a copy of the displayed figure but in matplotlib default settings""" + raise NotImplementedError def changeEvent(self, event): if self.toolbar is not None and event.type() == QtCore.QEvent.Type.PaletteChange: @@ -533,6 +551,20 @@ def plot_event(self, data: ratapi.events.PlotEventData | None = None): ) self.canvas.draw() + def plot_temp_fig(self, temp_fig): + show_legend = self.show_legend.isChecked() if self.current_plot_data.contrastNames else False + ratapi.plotting.plot_ref_sld_helper( + self.current_plot_data, + temp_fig, + delay=False, + linear_x=self.x_axis.currentText() == "Linear", + q4=self.y_axis.currentText() == "Q^4", + show_error_bar=self.show_error_bar.isChecked(), + show_grid=self.show_grid.isChecked(), + show_legend=show_legend, + shift_value=self.slider.value(), + ) + def plot_with_blit(self, data: ratapi.events.PlotEventData | None = None): """Update the ref and SLD plots with blitting. @@ -611,6 +643,14 @@ def draw_plot(self): ) self.canvas.draw() + def plot_temp_fig(self, temp_fig): + ratapi.plotting.plot_ref_sld( + self.project, + self.results, + bayes=int(self.ci_param_box.currentText().strip("%")), + fig=temp_fig, + ) + class AbstractPanelPlotWidget(AbstractPlotWidget): """Abstract base widget for plotting panels of parameters (corner plot, histograms, chains). From 6c0820445ea2ea286bc8e9d5d7ca9dc241d75713 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Tue, 18 Aug 2026 17:44:32 +0100 Subject: [PATCH 2/5] Figures are only adjusted when Dark Theme is active --- rascal2/widgets/plot.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index 7e6da378..e13b80dc 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -386,26 +386,30 @@ def export(self): """Save the figure to a file.""" filepath, accepted = QtWidgets.QFileDialog.getSaveFileName(self, "Export Plot", filter="Image File (*.png)") if accepted: - temp_fig = self.make_figure() - sx = temp_fig.get_figwidth() * temp_fig.dpi - dpi = temp_fig.dpi if sx > 1920 else 1920 // temp_fig.get_figwidth() - matplotlib.style.use("default") - self.plot_temp_fig(temp_fig) - axes = temp_fig.axes - for ax in axes: - ax.patch.set_facecolor("white") - ax.spines["bottom"].set_color("black") - ax.spines["top"].set_color("black") - ax.spines["right"].set_color("black") - ax.spines["left"].set_color("black") - temp_fig.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) - if get_correct_qt_color_scheme() == QtCore.Qt.ColorScheme.Light: - matplotlib.style.use("default") + sx = self.figure.get_figwidth() * self.figure.dpi + dpi = self.figure.dpi if sx > 1920 else 1920 // self.figure.get_figwidth() + scheme = get_correct_qt_color_scheme() + if scheme == QtCore.Qt.ColorScheme.Light: + self.figure.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) else: - matplotlib.style.use("dark_background") + temp_fig = self.make_figure() + matplotlib.style.use("default") + self.plot_temp_fig(temp_fig) + axes = temp_fig.axes + for ax in axes: + ax.patch.set_facecolor("white") + ax.spines["bottom"].set_color("black") + ax.spines["top"].set_color("black") + ax.spines["right"].set_color("black") + ax.spines["left"].set_color("black") + temp_fig.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) + if get_correct_qt_color_scheme() == QtCore.Qt.ColorScheme.Light: + matplotlib.style.use("default") + else: + matplotlib.style.use("dark_background") def plot_temp_fig(self, temp_fig): - """Plot a temporary figure which is a copy of the displayed figure but in matplotlib default settings""" + """Plot a temporary figure which is a copy of the displayed figure but in matplotlib default settings.""" raise NotImplementedError def changeEvent(self, event): From 1c16e0224b98f8770f419f10d98b8efdcb6bce4b Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Wed, 19 Aug 2026 17:38:15 +0100 Subject: [PATCH 3/5] exported plot colours are changed without replottings --- rascal2/widgets/plot.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index e13b80dc..9cc6d70c 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -1,10 +1,11 @@ """The Plot MDI widget.""" - +import copy from abc import abstractmethod from inspect import isclass import matplotlib import ratapi +from cycler import cycler from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT from PyQt6 import QtCore, QtGui, QtWidgets @@ -392,16 +393,38 @@ def export(self): if scheme == QtCore.Qt.ColorScheme.Light: self.figure.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) else: - temp_fig = self.make_figure() + old_colours = matplotlib.rcParams['axes.prop_cycle'].by_key()['color'] + new_colours_cycle = cycler(color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']) + new_colours = new_colours_cycle.by_key()['color'] + colour_converter = dict(zip(old_colours, new_colours)) + temp_fig = copy.deepcopy(self.figure) matplotlib.style.use("default") - self.plot_temp_fig(temp_fig) axes = temp_fig.axes + for ax in axes: + if ax.containers: + for container in ax.containers: + _, __, (vertical_lines,) = container.lines + vertical_lines.set_color(colour_converter[matplotlib.colors.rgb2hex(vertical_lines.get_color(), keep_alpha=False)]) + ax.set_prop_cycle(new_colours_cycle) ax.patch.set_facecolor("white") ax.spines["bottom"].set_color("black") ax.spines["top"].set_color("black") ax.spines["right"].set_color("black") ax.spines["left"].set_color("black") + ax.tick_params(axis='both', color='black', labelcolor='black') + ax.xaxis.label.set_color('black') + ax.yaxis.label.set_color('black') + ax.legend(facecolor='white', labelcolor='black') + legend = ax.get_legend() + for line in legend.get_lines(): + old_line_colour = line.get_color() + line.set_color(colour_converter[old_line_colour]) + lines = ax.get_lines() + for line in lines: + old_line_colour = line.get_color() + line.set_color(colour_converter[old_line_colour]) + temp_fig.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) if get_correct_qt_color_scheme() == QtCore.Qt.ColorScheme.Light: matplotlib.style.use("default") From 09b8347c04b8280f005b17f091bdc2d8f076b730 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Thu, 20 Aug 2026 10:59:28 +0100 Subject: [PATCH 4/5] fixed crashing issue when large number of subplots are in figure --- rascal2/widgets/plot.py | 83 ++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index 9cc6d70c..8393305e 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -1,4 +1,5 @@ """The Plot MDI widget.""" + import copy from abc import abstractmethod from inspect import isclass @@ -393,47 +394,57 @@ def export(self): if scheme == QtCore.Qt.ColorScheme.Light: self.figure.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) else: - old_colours = matplotlib.rcParams['axes.prop_cycle'].by_key()['color'] - new_colours_cycle = cycler(color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']) - new_colours = new_colours_cycle.by_key()['color'] + old_colours = matplotlib.rcParams["axes.prop_cycle"].by_key()["color"] + new_colours_cycle = cycler( + color=[ + "#1f77b4", + "#ff7f0e", + "#2ca02c", + "#d62728", + "#9467bd", + "#8c564b", + "#e377c2", + "#7f7f7f", + "#bcbd22", + "#17becf", + ] + ) + new_colours = new_colours_cycle.by_key()["color"] colour_converter = dict(zip(old_colours, new_colours)) temp_fig = copy.deepcopy(self.figure) - matplotlib.style.use("default") axes = temp_fig.axes - for ax in axes: if ax.containers: for container in ax.containers: - _, __, (vertical_lines,) = container.lines - vertical_lines.set_color(colour_converter[matplotlib.colors.rgb2hex(vertical_lines.get_color(), keep_alpha=False)]) + if isinstance(container, matplotlib.container.ErrorbarContainer): + _, __, (vertical_lines,) = container.lines + vertical_lines.set_color( + colour_converter[ + matplotlib.colors.rgb2hex(vertical_lines.get_color(), keep_alpha=False) + ] + ) ax.set_prop_cycle(new_colours_cycle) ax.patch.set_facecolor("white") ax.spines["bottom"].set_color("black") ax.spines["top"].set_color("black") ax.spines["right"].set_color("black") ax.spines["left"].set_color("black") - ax.tick_params(axis='both', color='black', labelcolor='black') - ax.xaxis.label.set_color('black') - ax.yaxis.label.set_color('black') - ax.legend(facecolor='white', labelcolor='black') - legend = ax.get_legend() - for line in legend.get_lines(): - old_line_colour = line.get_color() - line.set_color(colour_converter[old_line_colour]) - lines = ax.get_lines() - for line in lines: + ax.tick_params(which="both", axis="both", color="black", labelcolor="black") + ax.xaxis.label.set_color("black") + ax.yaxis.label.set_color("black") + title_text = ax.get_title(loc="left") + ax.set_title(title_text, color="black", loc="left") + ax.title.set_color("black") + if ax.get_legend() is not None: + ax.legend(facecolor="white", labelcolor="black") + for line in ax.get_legend().get_lines(): + old_line_colour = line.get_color() + line.set_color(colour_converter[old_line_colour]) + for line in ax.get_lines(): old_line_colour = line.get_color() line.set_color(colour_converter[old_line_colour]) temp_fig.savefig(filepath, facecolor=SETTINGS.export_background_colour, dpi=dpi) - if get_correct_qt_color_scheme() == QtCore.Qt.ColorScheme.Light: - matplotlib.style.use("default") - else: - matplotlib.style.use("dark_background") - - def plot_temp_fig(self, temp_fig): - """Plot a temporary figure which is a copy of the displayed figure but in matplotlib default settings.""" - raise NotImplementedError def changeEvent(self, event): if self.toolbar is not None and event.type() == QtCore.QEvent.Type.PaletteChange: @@ -578,20 +589,6 @@ def plot_event(self, data: ratapi.events.PlotEventData | None = None): ) self.canvas.draw() - def plot_temp_fig(self, temp_fig): - show_legend = self.show_legend.isChecked() if self.current_plot_data.contrastNames else False - ratapi.plotting.plot_ref_sld_helper( - self.current_plot_data, - temp_fig, - delay=False, - linear_x=self.x_axis.currentText() == "Linear", - q4=self.y_axis.currentText() == "Q^4", - show_error_bar=self.show_error_bar.isChecked(), - show_grid=self.show_grid.isChecked(), - show_legend=show_legend, - shift_value=self.slider.value(), - ) - def plot_with_blit(self, data: ratapi.events.PlotEventData | None = None): """Update the ref and SLD plots with blitting. @@ -670,14 +667,6 @@ def draw_plot(self): ) self.canvas.draw() - def plot_temp_fig(self, temp_fig): - ratapi.plotting.plot_ref_sld( - self.project, - self.results, - bayes=int(self.ci_param_box.currentText().strip("%")), - fig=temp_fig, - ) - class AbstractPanelPlotWidget(AbstractPlotWidget): """Abstract base widget for plotting panels of parameters (corner plot, histograms, chains). From 8ee51eb32496735d1e0edf5a166c924b08c0e991 Mon Sep 17 00:00:00 2001 From: Mike Sullivan Date: Thu, 20 Aug 2026 11:28:14 +0100 Subject: [PATCH 5/5] ruff fix --- rascal2/widgets/plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal2/widgets/plot.py b/rascal2/widgets/plot.py index 8393305e..761a3e71 100644 --- a/rascal2/widgets/plot.py +++ b/rascal2/widgets/plot.py @@ -410,7 +410,7 @@ def export(self): ] ) new_colours = new_colours_cycle.by_key()["color"] - colour_converter = dict(zip(old_colours, new_colours)) + colour_converter = dict(zip(old_colours, new_colours, strict=False)) temp_fig = copy.deepcopy(self.figure) axes = temp_fig.axes for ax in axes: