Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfce2a6d

Browse files
committed
Merge pull request#4091 from tacaswell/repl_hook
ENH : add function to add displayhook
2 parents2ac9ac2 +0abbcf6 commitfce2a6d

23 files changed

+617
-208
lines changed

‎boilerplate.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ def %(func)s(%(argspec)s):
5656
%(ax)s.hold(hold)
5757
try:
5858
%(ret)s = %(ax)s.%(func)s(%(call)s)
59-
draw_if_interactive()
6059
finally:
6160
%(ax)s.hold(%(washold)s)
6261
%(mappable)s
@@ -69,7 +68,6 @@ def %(func)s(%(argspec)s):
6968
@docstring.copy_dedent(Axes.%(func)s)
7069
def %(func)s(%(argspec)s):
7170
%(ret)s = gca().%(func)s(%(call)s)
72-
draw_if_interactive()
7371
return %(ret)s
7472
"""
7573

@@ -85,7 +83,6 @@ def {name}():
8583
8684
if im is not None:
8785
im.set_cmap(cm.{name})
88-
draw_if_interactive()
8986
9087
"""
9188

@@ -219,8 +216,9 @@ def format_value(value):
219216
else:
220217
def_edited= []
221218
forvalindefaults:
222-
ifisinstance(val,unicode):
223-
val=val.encode('ascii','ignore')
219+
ifsix.PY2:
220+
ifisinstance(val,unicode):
221+
val=val.encode('ascii','ignore')
224222
def_edited.append(val)
225223
defaults=tuple(def_edited)
226224

@@ -273,7 +271,7 @@ def format_value(value):
273271

274272
# Since we can't avoid using some function names,
275273
# bail out if they are used as argument names
276-
forreservedin ('gca','gci','draw_if_interactive'):
274+
forreservedin ('gca','gci'):
277275
ifreservedinbad:
278276
msg='Axes method %s has kwarg named %s'% (func,reserved)
279277
raiseValueError(msg)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Interactive OO usage
2+
--------------------
3+
4+
All `Artists` now keep track of if their internal state has been
5+
changed but not reflected in the display ('stale') by a call to
6+
``draw``. It is thus possible to pragmatically determine if a given
7+
`Figure` needs to be re-drawn in an interactive session.
8+
9+
To facilitate interactive usage a ``draw_all`` method has been added
10+
to ``pyplot`` which will redraw all of the figures which are 'stale'.
11+
12+
To make this convenient for interactive use matplotlib now registers
13+
a function either with IPython's 'post_execute' event or with the
14+
displayhook in the standard python REPL to automatically call
15+
``plt.draw_all`` just before control is returned to the REPL. This ensures
16+
that the draw command is deferred and only called once.
17+
18+
The upshot of this is that for interactive backends (including
19+
``%matplotlib notebook``) in interactive mode (with ``plt.ion()``)
20+
21+
.. ipython :: python
22+
23+
import matplotlib.pyplot as plt
24+
25+
fig, ax = plt.subplots()
26+
27+
ln, = ax.plot([0, 1, 4, 9, 16])
28+
29+
plt.show()
30+
31+
ln.set_color('g')
32+
33+
34+
will automatically update the plot to be green. Any subsequent
35+
modifications to the ``Artist`` objects will do likewise.
36+
37+
This is the first step of a larger consolidation and simplification of
38+
the pyplot internals.

‎lib/matplotlib/_pylab_helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,15 @@ def set_active(cls, manager):
139139
cls._activeQue.append(manager)
140140
cls.figs[manager.num]=manager
141141

142+
@classmethod
143+
defdraw_all(cls,force=False):
144+
"""
145+
Redraw all figures registered with the pyplot
146+
state machine.
147+
"""
148+
forf_mgrincls.get_all_fig_managers():
149+
# TODO add logic to check if figure is stale
150+
ifforceorf_mgr.canvas.figure.stale:
151+
f_mgr.canvas.draw_idle()
142152

143153
atexit.register(Gcf.destroy_all)

‎lib/matplotlib/artist.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ def draw_wrapper(artist, renderer, *args, **kwargs):
6868
returndraw_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+
7179
classArtist(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+
ifnew_axesisnotNoneandnew_axesisnotself:
225+
self.add_callback(_stale_axes_callback)
226+
214227
returnnew_axes
215228

229+
@property
230+
defstale(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+
returnself._stale
236+
237+
@stale.setter
238+
defstale(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+
ifnot (self._stale==val):
244+
self._stale=val
245+
# only trigger propagation if marking as stale
246+
ifself._stale:
247+
self.pchanged()
248+
216249
defget_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
defget_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
defget_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,lengthor128.0,randomnessor16.0)
584+
self.stale=True
549585

550586
defset_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
defget_path_effects(self):
558595
returnself._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+
ifself.figureandself.figureisnotself:
613+
self.add_callback(_stale_figure_callback)
614+
self.pchanged()
615+
self.stale=True
576616

577617
defset_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
defset_clip_path(self,path,transform=None):
587628
"""
@@ -634,8 +675,10 @@ def set_clip_path(self, path, transform=None):
634675
ifnotsuccess:
635676
print(type(path),type(transform))
636677
raiseTypeError("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
defget_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
defdraw(self,renderer,*args,**kwargs):
728775
'Derived classes drawing method'
729776
ifnotself.get_visible():
730777
return
778+
self.stale=False
731779

732780
defset_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
defset_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
defset_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
defupdate(self,props):
761812
"""
@@ -778,6 +829,7 @@ def update(self, props):
778829
self.eventson=store
779830
ifchanged:
780831
self.pchanged()
832+
self.stale=True
781833

782834
defget_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
defget_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
defupdate_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
defproperties(self):
831886
"""

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp