@@ -68,6 +68,14 @@ def draw_wrapper(artist, renderer, *args, **kwargs):
68
68
return draw_wrapper
69
69
70
70
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
+
71
79
class Artist (object ):
72
80
"""
73
81
Abstract base class for someone who renders into a
@@ -78,6 +86,7 @@ class Artist(object):
78
86
zorder = 0
79
87
80
88
def __init__ (self ):
89
+ self ._stale = True
81
90
self ._axes = None
82
91
self .figure = None
83
92
@@ -210,9 +219,33 @@ def axes(self, new_axes):
210
219
"probably trying to re-use an artist "
211
220
"in more than one Axes which is not "
212
221
"supported" )
222
+
213
223
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
+
214
227
return new_axes
215
228
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
+
216
249
def get_window_extent (self , renderer ):
217
250
"""
218
251
Get the axes bounding box in display space.
@@ -283,6 +316,7 @@ def set_transform(self, t):
283
316
self ._transform = t
284
317
self ._transformSet = True
285
318
self .pchanged ()
319
+ self .stale = True
286
320
287
321
def get_transform (self ):
288
322
"""
@@ -499,6 +533,7 @@ def set_snap(self, snap):
499
533
Only supported by the Agg and MacOSX backends.
500
534
"""
501
535
self ._snap = snap
536
+ self .stale = True
502
537
503
538
def get_sketch_params (self ):
504
539
"""
@@ -546,13 +581,15 @@ def set_sketch_params(self, scale=None, length=None, randomness=None):
546
581
self ._sketch = None
547
582
else :
548
583
self ._sketch = (scale , length or 128.0 , randomness or 16.0 )
584
+ self .stale = True
549
585
550
586
def set_path_effects (self , path_effects ):
551
587
"""
552
588
set path_effects, which should be a list of instances of
553
589
matplotlib.patheffect._Base class or its derivatives.
554
590
"""
555
591
self ._path_effects = path_effects
592
+ self .stale = True
556
593
557
594
def get_path_effects (self ):
558
595
return self ._path_effects
@@ -572,7 +609,10 @@ def set_figure(self, fig):
572
609
ACCEPTS: a :class:`matplotlib.figure.Figure` instance
573
610
"""
574
611
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
576
616
577
617
def set_clip_box (self , clipbox ):
578
618
"""
@@ -582,6 +622,7 @@ def set_clip_box(self, clipbox):
582
622
"""
583
623
self .clipbox = clipbox
584
624
self .pchanged ()
625
+ self .stale = True
585
626
586
627
def set_clip_path (self , path , transform = None ):
587
628
"""
@@ -634,8 +675,10 @@ def set_clip_path(self, path, transform=None):
634
675
if not success :
635
676
print (type (path ), type (transform ))
636
677
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
638
680
self .pchanged ()
681
+ self .stale = True
639
682
640
683
def get_alpha (self ):
641
684
"""
@@ -684,7 +727,10 @@ def set_clip_on(self, b):
684
727
ACCEPTS: [True | False]
685
728
"""
686
729
self ._clipon = b
730
+ # This may result in the callbacks being hit twice, but ensures they
731
+ # are hit at least once
687
732
self .pchanged ()
733
+ self .stale = True
688
734
689
735
def _set_gc_clip (self , gc ):
690
736
'Set the clip properly for the gc'
@@ -723,11 +769,13 @@ def set_agg_filter(self, filter_func):
723
769
724
770
"""
725
771
self ._agg_filter = filter_func
772
+ self .stale = True
726
773
727
774
def draw (self , renderer , * args , ** kwargs ):
728
775
'Derived classes drawing method'
729
776
if not self .get_visible ():
730
777
return
778
+ self .stale = False
731
779
732
780
def set_alpha (self , alpha ):
733
781
"""
@@ -738,6 +786,7 @@ def set_alpha(self, alpha):
738
786
"""
739
787
self ._alpha = alpha
740
788
self .pchanged ()
789
+ self .stale = True
741
790
742
791
def set_visible (self , b ):
743
792
"""
@@ -747,6 +796,7 @@ def set_visible(self, b):
747
796
"""
748
797
self ._visible = b
749
798
self .pchanged ()
799
+ self .stale = True
750
800
751
801
def set_animated (self , b ):
752
802
"""
@@ -756,6 +806,7 @@ def set_animated(self, b):
756
806
"""
757
807
self ._animated = b
758
808
self .pchanged ()
809
+ self .stale = True
759
810
760
811
def update (self , props ):
761
812
"""
@@ -778,6 +829,7 @@ def update(self, props):
778
829
self .eventson = store
779
830
if changed :
780
831
self .pchanged ()
832
+ self .stale = True
781
833
782
834
def get_label (self ):
783
835
"""
@@ -796,6 +848,7 @@ def set_label(self, s):
796
848
else :
797
849
self ._label = None
798
850
self .pchanged ()
851
+ self .stale = True
799
852
800
853
def get_zorder (self ):
801
854
"""
@@ -812,6 +865,7 @@ def set_zorder(self, level):
812
865
"""
813
866
self .zorder = level
814
867
self .pchanged ()
868
+ self .stale = True
815
869
816
870
def update_from (self , other ):
817
871
'Copy properties from *other* to *self*.'
@@ -826,6 +880,7 @@ def update_from(self, other):
826
880
self ._sketch = other ._sketch
827
881
self ._path_effects = other ._path_effects
828
882
self .pchanged ()
883
+ self .stale = True
829
884
830
885
def properties (self ):
831
886
"""
0 commit comments