@@ -68,6 +68,14 @@ def draw_wrapper(artist, renderer, *args, **kwargs):
6868 return draw_wrapper
6969
7070
71+ def _stale_figure_callback (self ):
72+ self .figure .stale = True
73+
74+
75+ def _stale_axes_callback (self ):
76+ self .axes .stale = True
77+
78+
7179class Artist (object ):
7280 """
7381 Abstract base class for someone who renders into a
@@ -78,6 +86,7 @@ class Artist(object):
7886 zorder = 0
7987
8088 def __init__ (self ):
89+ self ._stale = True
8190 self ._axes = None
8291 self .figure = None
8392
@@ -210,9 +219,33 @@ def axes(self, new_axes):
210219 "probably trying to re-use an artist "
211220 "in more than one Axes which is not "
212221 "supported" )
222+
213223 self ._axes = new_axes
224+ if new_axes is not None and new_axes is not self :
225+ self .add_callback (_stale_axes_callback )
226+
214227 return new_axes
215228
229+ @property
230+ def stale (self ):
231+ """
232+ If the artist is 'stale' and needs to be re-drawn for the output to
233+ match the internal state of the artist.
234+ """
235+ return self ._stale
236+
237+ @stale .setter
238+ def stale (self , val ):
239+ # only trigger call-back stack on being marked as 'stale'
240+ # when not already stale
241+ # the draw process will take care of propagating the cleaning
242+ # process
243+ if not (self ._stale == val ):
244+ self ._stale = val
245+ # only trigger propagation if marking as stale
246+ if self ._stale :
247+ self .pchanged ()
248+
216249 def get_window_extent (self , renderer ):
217250 """
218251 Get the axes bounding box in display space.
@@ -283,6 +316,7 @@ def set_transform(self, t):
283316 self ._transform = t
284317 self ._transformSet = True
285318 self .pchanged ()
319+ self .stale = True
286320
287321 def get_transform (self ):
288322 """
@@ -499,6 +533,7 @@ def set_snap(self, snap):
499533 Only supported by the Agg and MacOSX backends.
500534 """
501535 self ._snap = snap
536+ self .stale = True
502537
503538 def get_sketch_params (self ):
504539 """
@@ -546,13 +581,15 @@ def set_sketch_params(self, scale=None, length=None, randomness=None):
546581 self ._sketch = None
547582 else :
548583 self ._sketch = (scale , length or 128.0 , randomness or 16.0 )
584+ self .stale = True
549585
550586 def set_path_effects (self , path_effects ):
551587 """
552588 set path_effects, which should be a list of instances of
553589 matplotlib.patheffect._Base class or its derivatives.
554590 """
555591 self ._path_effects = path_effects
592+ self .stale = True
556593
557594 def get_path_effects (self ):
558595 return self ._path_effects
@@ -572,7 +609,10 @@ def set_figure(self, fig):
572609 ACCEPTS: a :class:`matplotlib.figure.Figure` instance
573610 """
574611 self .figure = fig
575- self .pchanged ()
612+ if self .figure and self .figure is not self :
613+ self .add_callback (_stale_figure_callback )
614+ self .pchanged ()
615+ self .stale = True
576616
577617 def set_clip_box (self , clipbox ):
578618 """
@@ -582,6 +622,7 @@ def set_clip_box(self, clipbox):
582622 """
583623 self .clipbox = clipbox
584624 self .pchanged ()
625+ self .stale = True
585626
586627 def set_clip_path (self , path , transform = None ):
587628 """
@@ -634,8 +675,10 @@ def set_clip_path(self, path, transform=None):
634675 if not success :
635676 print (type (path ), type (transform ))
636677 raise TypeError ("Invalid arguments to set_clip_path" )
637-
678+ # this may result in the callbacks being hit twice, but grantees they
679+ # will be hit at least once
638680 self .pchanged ()
681+ self .stale = True
639682
640683 def get_alpha (self ):
641684 """
@@ -684,7 +727,10 @@ def set_clip_on(self, b):
684727 ACCEPTS: [True | False]
685728 """
686729 self ._clipon = b
730+ # This may result in the callbacks being hit twice, but ensures they
731+ # are hit at least once
687732 self .pchanged ()
733+ self .stale = True
688734
689735 def _set_gc_clip (self , gc ):
690736 'Set the clip properly for the gc'
@@ -723,11 +769,13 @@ def set_agg_filter(self, filter_func):
723769
724770 """
725771 self ._agg_filter = filter_func
772+ self .stale = True
726773
727774 def draw (self , renderer , * args , ** kwargs ):
728775 'Derived classes drawing method'
729776 if not self .get_visible ():
730777 return
778+ self .stale = False
731779
732780 def set_alpha (self , alpha ):
733781 """
@@ -738,6 +786,7 @@ def set_alpha(self, alpha):
738786 """
739787 self ._alpha = alpha
740788 self .pchanged ()
789+ self .stale = True
741790
742791 def set_visible (self , b ):
743792 """
@@ -747,6 +796,7 @@ def set_visible(self, b):
747796 """
748797 self ._visible = b
749798 self .pchanged ()
799+ self .stale = True
750800
751801 def set_animated (self , b ):
752802 """
@@ -756,6 +806,7 @@ def set_animated(self, b):
756806 """
757807 self ._animated = b
758808 self .pchanged ()
809+ self .stale = True
759810
760811 def update (self , props ):
761812 """
@@ -778,6 +829,7 @@ def update(self, props):
778829 self .eventson = store
779830 if changed :
780831 self .pchanged ()
832+ self .stale = True
781833
782834 def get_label (self ):
783835 """
@@ -796,6 +848,7 @@ def set_label(self, s):
796848 else :
797849 self ._label = None
798850 self .pchanged ()
851+ self .stale = True
799852
800853 def get_zorder (self ):
801854 """
@@ -812,6 +865,7 @@ def set_zorder(self, level):
812865 """
813866 self .zorder = level
814867 self .pchanged ()
868+ self .stale = True
815869
816870 def update_from (self , other ):
817871 'Copy properties from *other* to *self*.'
@@ -826,6 +880,7 @@ def update_from(self, other):
826880 self ._sketch = other ._sketch
827881 self ._path_effects = other ._path_effects
828882 self .pchanged ()
883+ self .stale = True
829884
830885 def properties (self ):
831886 """
0 commit comments