@@ -47,8 +47,15 @@ def __init__(self, model: PlotModel, parent, main_window):
4747 self .colorbar = None
4848 self .data_indicator = None
4949 self .tally_data_indicator = None
50+ self .tally_colorbar = None
51+ self .tally_image = None
5052 self .image = None
5153
54+ self ._data_colorbar_bg = None
55+ self ._tally_colorbar_bg = None
56+ self ._last_tally_indicator_value = None
57+ self ._last_data_indicator_value = None
58+
5259 self .menu = QMenu (self )
5360
5461 def enterEvent (self , event ):
@@ -538,6 +545,7 @@ def updatePixmap(self):
538545 linewidth = 3. ,
539546 color = 'blue' ,
540547 clip_on = True )
548+ self .data_indicator .set_animated (True )
541549 self .colorbar .ax .add_line (self .data_indicator )
542550 self .colorbar .ax .margins (0.0 , 0.0 )
543551 self .updateDataIndicatorVisibility ()
@@ -626,6 +634,7 @@ def updatePixmap(self):
626634 linewidth = 3. ,
627635 color = 'blue' ,
628636 clip_on = True )
637+ self .tally_data_indicator .set_animated (True )
629638 self .tally_colorbar .ax .add_line (self .tally_data_indicator )
630639 self .tally_colorbar .ax .margins (0.0 , 0.0 )
631640
@@ -655,6 +664,9 @@ def updatePixmap(self):
655664 self .ax .dataLim .y1 = data_bounds [3 ]
656665
657666 self .draw ()
667+ self ._cache_colorbar_backgrounds ()
668+ self ._blit_indicator (self .data_indicator , self .colorbar )
669+ self ._blit_indicator (self .tally_data_indicator , self .tally_colorbar )
658670 return "Done"
659671
660672 def current_view_data_bounds (self ):
@@ -740,21 +752,63 @@ def parseContoursLine(line):
740752 def updateColorbarScale (self ):
741753 self .updatePixmap ()
742754
755+ def _cache_colorbar_backgrounds (self ):
756+ """Cache colorbar backgrounds for fast indicator blitting."""
757+ self ._data_colorbar_bg = None
758+ self ._tally_colorbar_bg = None
759+
760+ if self .colorbar and self .data_indicator :
761+ self ._data_colorbar_bg = self .copy_from_bbox (
762+ self .colorbar .ax .bbox )
763+
764+ if self .tally_colorbar and self .tally_data_indicator :
765+ self ._tally_colorbar_bg = self .copy_from_bbox (
766+ self .tally_colorbar .ax .bbox )
767+
768+ def _blit_indicator (self , indicator , colorbar ):
769+ """Blit a single indicator line onto its colorbar if possible."""
770+ if colorbar is None or indicator is None :
771+ return False
772+
773+ if not indicator .get_visible ():
774+ return False
775+
776+ if colorbar is self .colorbar :
777+ background = self ._data_colorbar_bg
778+ else :
779+ background = self ._tally_colorbar_bg
780+
781+ if background is None :
782+ return False
783+
784+ self .restore_region (background )
785+ colorbar .ax .draw_artist (indicator )
786+ self .blit (colorbar .ax .bbox )
787+ return True
788+
743789 def updateTallyDataIndicatorValue (self , y_val ):
744790 cv = self .model .currentView
745791
746792 if not cv .tallyDataVisible or not cv .tallyDataIndicator :
747793 return
748794
749- if self .tally_data_indicator is not None :
750- data = self .tally_data_indicator .get_data ()
795+ if self .tally_data_indicator is not None and self .tally_image is not None :
751796 # use norm to get axis value if log scale
752797 if cv .tallyDataLogScale :
753798 y_val = self .tally_image .norm (y_val )
799+
800+ # If indicator value hasn't changed, skip update
801+ if self ._last_tally_indicator_value == y_val :
802+ return
803+ self ._last_tally_indicator_value = y_val
804+
805+ data = self .tally_data_indicator .get_data ()
754806 self .tally_data_indicator .set_data ([data [0 ], [y_val , y_val ]])
755807 dl_color = invert_rgb (self .tally_image .get_cmap ()(y_val ), True )
756808 self .tally_data_indicator .set_c (dl_color )
757- self .draw ()
809+
810+ if not self ._blit_indicator (self .tally_data_indicator , self .tally_colorbar ):
811+ self .draw_idle ()
758812
759813 def updateDataIndicatorValue (self , y_val ):
760814 cv = self .model .currentView
@@ -763,28 +817,39 @@ def updateDataIndicatorValue(self, y_val):
763817 not cv .data_indicator_enabled [cv .colorby ]:
764818 return
765819
766- if self .data_indicator :
767- data = self .data_indicator .get_data ()
820+ if self .data_indicator and self .image is not None :
768821 # use norm to get axis value if log scale
769822 if cv .color_scale_log [cv .colorby ]:
770823 y_val = self .image .norm (y_val )
824+
825+ # If indicator value hasn't changed, skip update
826+ if self ._last_data_indicator_value == y_val :
827+ return
828+ self ._last_data_indicator_value = y_val
829+
830+ data = self .data_indicator .get_data ()
771831 self .data_indicator .set_data ([data [0 ], [y_val , y_val ]])
772832 dl_color = invert_rgb (self .image .get_cmap ()(y_val ), True )
773833 self .data_indicator .set_c (dl_color )
774- self .draw ()
834+
835+ if not self ._blit_indicator (self .data_indicator , self .colorbar ):
836+ self .draw_idle ()
775837
776838 def updateDataIndicatorVisibility (self ):
777839 cv = self .model .currentView
778840 if self .data_indicator and cv .colorby in _MODEL_PROPERTIES :
779841 val = cv .data_indicator_enabled [cv .colorby ]
780842 self .data_indicator .set_visible (val )
781- self .draw ()
843+ if not self ._blit_indicator (self .data_indicator , self .colorbar ):
844+ self .draw_idle ()
782845
783846 def updateColorMap (self , colormap_name , property_type ):
784847 if self .colorbar and property_type == self .model .activeView .colorby :
785848 self .image .set_cmap (colormap_name )
786849 self .figure .draw_without_rendering ()
787850 self .draw ()
851+ self ._cache_colorbar_backgrounds ()
852+ self ._blit_indicator (self .data_indicator , self .colorbar )
788853
789854 def updateColorMinMax (self , property_type ):
790855 av = self .model .activeView
@@ -795,6 +860,8 @@ def updateColorMinMax(self, property_type):
795860 (0.0 , 0.0 ))
796861 self .figure .draw_without_rendering ()
797862 self .draw ()
863+ self ._cache_colorbar_backgrounds ()
864+ self ._blit_indicator (self .data_indicator , self .colorbar )
798865
799866
800867class ColorDialog (QDialog ):
0 commit comments