From 16b799320054627246f3b2103560bece53cfc10c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 19 Jan 2026 13:51:40 -0600 Subject: [PATCH 1/3] Implementing blitting for colorbar indicators --- openmc_plotter/plotgui.py | 81 +++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/openmc_plotter/plotgui.py b/openmc_plotter/plotgui.py index 2f4b590..24b6c00 100644 --- a/openmc_plotter/plotgui.py +++ b/openmc_plotter/plotgui.py @@ -47,8 +47,15 @@ def __init__(self, model: PlotModel, parent, main_window): self.colorbar = None self.data_indicator = None self.tally_data_indicator = None + self.tally_colorbar = None + self.tally_image = None self.image = None + self._data_colorbar_bg = None + self._tally_colorbar_bg = None + self._last_tally_indicator_value = None + self._last_data_indicator_value = None + self.menu = QMenu(self) def enterEvent(self, event): @@ -538,6 +545,7 @@ def updatePixmap(self): linewidth=3., color='blue', clip_on=True) + self.data_indicator.set_animated(True) self.colorbar.ax.add_line(self.data_indicator) self.colorbar.ax.margins(0.0, 0.0) self.updateDataIndicatorVisibility() @@ -626,6 +634,7 @@ def updatePixmap(self): linewidth=3., color='blue', clip_on=True) + self.tally_data_indicator.set_animated(True) self.tally_colorbar.ax.add_line(self.tally_data_indicator) self.tally_colorbar.ax.margins(0.0, 0.0) @@ -655,6 +664,9 @@ def updatePixmap(self): self.ax.dataLim.y1 = data_bounds[3] self.draw() + self._cache_colorbar_backgrounds() + self._blit_indicator(self.data_indicator, self.colorbar) + self._blit_indicator(self.tally_data_indicator, self.tally_colorbar) return "Done" def current_view_data_bounds(self): @@ -740,21 +752,63 @@ def parseContoursLine(line): def updateColorbarScale(self): self.updatePixmap() + def _cache_colorbar_backgrounds(self): + """Cache colorbar backgrounds for fast indicator blitting.""" + self._data_colorbar_bg = None + self._tally_colorbar_bg = None + + if self.colorbar and self.data_indicator: + self._data_colorbar_bg = self.copy_from_bbox( + self.colorbar.ax.bbox) + + if self.tally_colorbar and self.tally_data_indicator: + self._tally_colorbar_bg = self.copy_from_bbox( + self.tally_colorbar.ax.bbox) + + def _blit_indicator(self, indicator, colorbar): + """Blit a single indicator line onto its colorbar if possible.""" + if colorbar is None or indicator is None: + return False + + if not indicator.get_visible(): + return False + + if colorbar is self.colorbar: + background = self._data_colorbar_bg + else: + background = self._tally_colorbar_bg + + if background is None: + return False + + self.restore_region(background) + colorbar.ax.draw_artist(indicator) + self.blit(colorbar.ax.bbox) + return True + def updateTallyDataIndicatorValue(self, y_val): cv = self.model.currentView if not cv.tallyDataVisible or not cv.tallyDataIndicator: return - if self.tally_data_indicator is not None: - data = self.tally_data_indicator.get_data() + if self.tally_data_indicator is not None and self.tally_image is not None: # use norm to get axis value if log scale if cv.tallyDataLogScale: y_val = self.tally_image.norm(y_val) + + # If indicator value hasn't changed, skip update + if self._last_tally_indicator_value == y_val: + return + self._last_tally_indicator_value = y_val + + data = self.tally_data_indicator.get_data() self.tally_data_indicator.set_data([data[0], [y_val, y_val]]) dl_color = invert_rgb(self.tally_image.get_cmap()(y_val), True) self.tally_data_indicator.set_c(dl_color) - self.draw() + + if not self._blit_indicator(self.tally_data_indicator, self.tally_colorbar): + self.draw_idle() def updateDataIndicatorValue(self, y_val): cv = self.model.currentView @@ -763,28 +817,39 @@ def updateDataIndicatorValue(self, y_val): not cv.data_indicator_enabled[cv.colorby]: return - if self.data_indicator: - data = self.data_indicator.get_data() + if self.data_indicator and self.image is not None: # use norm to get axis value if log scale if cv.color_scale_log[cv.colorby]: y_val = self.image.norm(y_val) + + # If indicator value hasn't changed, skip update + if self._last_data_indicator_value == y_val: + return + self._last_data_indicator_value = y_val + + data = self.data_indicator.get_data() self.data_indicator.set_data([data[0], [y_val, y_val]]) dl_color = invert_rgb(self.image.get_cmap()(y_val), True) self.data_indicator.set_c(dl_color) - self.draw() + + if not self._blit_indicator(self.data_indicator, self.colorbar): + self.draw_idle() def updateDataIndicatorVisibility(self): cv = self.model.currentView if self.data_indicator and cv.colorby in _MODEL_PROPERTIES: val = cv.data_indicator_enabled[cv.colorby] self.data_indicator.set_visible(val) - self.draw() + if not self._blit_indicator(self.data_indicator, self.colorbar): + self.draw_idle() def updateColorMap(self, colormap_name, property_type): if self.colorbar and property_type == self.model.activeView.colorby: self.image.set_cmap(colormap_name) self.figure.draw_without_rendering() self.draw() + self._cache_colorbar_backgrounds() + self._blit_indicator(self.data_indicator, self.colorbar) def updateColorMinMax(self, property_type): av = self.model.activeView @@ -795,6 +860,8 @@ def updateColorMinMax(self, property_type): (0.0, 0.0)) self.figure.draw_without_rendering() self.draw() + self._cache_colorbar_backgrounds() + self._blit_indicator(self.data_indicator, self.colorbar) class ColorDialog(QDialog): From fbecb92e79141e20c15cfa979ecd01746d53f06e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 23 Jan 2026 10:15:07 -0600 Subject: [PATCH 2/3] Rename attrivute colorbar to property_colorbar for clarity of intent --- openmc_plotter/plotgui.py | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/openmc_plotter/plotgui.py b/openmc_plotter/plotgui.py index 24b6c00..7f0b942 100644 --- a/openmc_plotter/plotgui.py +++ b/openmc_plotter/plotgui.py @@ -44,7 +44,7 @@ def __init__(self, model: PlotModel, parent, main_window): self.x_plot_origin = None self.y_plot_origin = None - self.colorbar = None + self.property_colorbar = None self.data_indicator = None self.tally_data_indicator = None self.tally_colorbar = None @@ -533,21 +533,21 @@ def updatePixmap(self): alpha=cv.domainAlpha) # add colorbar - self.colorbar = self.figure.colorbar(self.image, - anchor=(1.0, 0.0)) - self.colorbar.set_label(cmap_label, - rotation=-90, - labelpad=15) + self.property_colorbar = self.figure.colorbar(self.image, + anchor=(1.0, 0.0)) + self.property_colorbar.set_label(cmap_label, + rotation=-90, + labelpad=15) # draw line on colorbar - dl = self.colorbar.ax.dataLim.get_points() + dl = self.property_colorbar.ax.dataLim.get_points() self.data_indicator = mlines.Line2D(dl[:][0], [0.0, 0.0], linewidth=3., color='blue', clip_on=True) self.data_indicator.set_animated(True) - self.colorbar.ax.add_line(self.data_indicator) - self.colorbar.ax.margins(0.0, 0.0) + self.property_colorbar.ax.add_line(self.data_indicator) + self.property_colorbar.ax.margins(0.0, 0.0) self.updateDataIndicatorVisibility() self.updateColorMinMax(cv.colorby) @@ -665,7 +665,7 @@ def updatePixmap(self): self.draw() self._cache_colorbar_backgrounds() - self._blit_indicator(self.data_indicator, self.colorbar) + self._blit_indicator(self.data_indicator, self.property_colorbar) self._blit_indicator(self.tally_data_indicator, self.tally_colorbar) return "Done" @@ -757,9 +757,9 @@ def _cache_colorbar_backgrounds(self): self._data_colorbar_bg = None self._tally_colorbar_bg = None - if self.colorbar and self.data_indicator: + if self.property_colorbar and self.data_indicator: self._data_colorbar_bg = self.copy_from_bbox( - self.colorbar.ax.bbox) + self.property_colorbar.ax.bbox) if self.tally_colorbar and self.tally_data_indicator: self._tally_colorbar_bg = self.copy_from_bbox( @@ -773,7 +773,7 @@ def _blit_indicator(self, indicator, colorbar): if not indicator.get_visible(): return False - if colorbar is self.colorbar: + if colorbar is self.property_colorbar: background = self._data_colorbar_bg else: background = self._tally_colorbar_bg @@ -832,7 +832,7 @@ def updateDataIndicatorValue(self, y_val): dl_color = invert_rgb(self.image.get_cmap()(y_val), True) self.data_indicator.set_c(dl_color) - if not self._blit_indicator(self.data_indicator, self.colorbar): + if not self._blit_indicator(self.data_indicator, self.property_colorbar): self.draw_idle() def updateDataIndicatorVisibility(self): @@ -840,28 +840,28 @@ def updateDataIndicatorVisibility(self): if self.data_indicator and cv.colorby in _MODEL_PROPERTIES: val = cv.data_indicator_enabled[cv.colorby] self.data_indicator.set_visible(val) - if not self._blit_indicator(self.data_indicator, self.colorbar): + if not self._blit_indicator(self.data_indicator, self.property_colorbar): self.draw_idle() def updateColorMap(self, colormap_name, property_type): - if self.colorbar and property_type == self.model.activeView.colorby: + if self.property_colorbar and property_type == self.model.activeView.colorby: self.image.set_cmap(colormap_name) self.figure.draw_without_rendering() self.draw() self._cache_colorbar_backgrounds() - self._blit_indicator(self.data_indicator, self.colorbar) + self._blit_indicator(self.data_indicator, self.property_colorbar) def updateColorMinMax(self, property_type): av = self.model.activeView - if self.colorbar and property_type == av.colorby: + if self.property_colorbar and property_type == av.colorby: clim = av.getColorLimits(property_type) - self.colorbar.mappable.set_clim(*clim) + self.property_colorbar.mappable.set_clim(*clim) self.data_indicator.set_data(clim[:2], (0.0, 0.0)) self.figure.draw_without_rendering() self.draw() self._cache_colorbar_backgrounds() - self._blit_indicator(self.data_indicator, self.colorbar) + self._blit_indicator(self.data_indicator, self.property_colorbar) class ColorDialog(QDialog): From 66b2c23df3b1dd669e569e79dfb7ed8d907aef2b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 23 Jan 2026 10:22:19 -0600 Subject: [PATCH 3/3] Update property colorbar cache name for consistency --- openmc_plotter/plotgui.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openmc_plotter/plotgui.py b/openmc_plotter/plotgui.py index 7f0b942..04c1025 100644 --- a/openmc_plotter/plotgui.py +++ b/openmc_plotter/plotgui.py @@ -51,7 +51,7 @@ def __init__(self, model: PlotModel, parent, main_window): self.tally_image = None self.image = None - self._data_colorbar_bg = None + self._property_colorbar_bg = None self._tally_colorbar_bg = None self._last_tally_indicator_value = None self._last_data_indicator_value = None @@ -754,11 +754,11 @@ def updateColorbarScale(self): def _cache_colorbar_backgrounds(self): """Cache colorbar backgrounds for fast indicator blitting.""" - self._data_colorbar_bg = None + self._property_colorbar_bg = None self._tally_colorbar_bg = None if self.property_colorbar and self.data_indicator: - self._data_colorbar_bg = self.copy_from_bbox( + self._property_colorbar_bg = self.copy_from_bbox( self.property_colorbar.ax.bbox) if self.tally_colorbar and self.tally_data_indicator: @@ -774,7 +774,7 @@ def _blit_indicator(self, indicator, colorbar): return False if colorbar is self.property_colorbar: - background = self._data_colorbar_bg + background = self._property_colorbar_bg else: background = self._tally_colorbar_bg