Skip to content

ENH : add function to add displayhook #4091

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 79 commits into from
May 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
96d3605
ENH : add function to add displayhook for IPython
tacaswell Feb 9, 2015
d9f9d2a
ENH : greatly simplified last commit
tacaswell Feb 10, 2015
76a87fe
ENH : special case IPython display hook
tacaswell Feb 10, 2015
fb994e9
ENH : hook into IPython better
tacaswell Feb 10, 2015
51f08cd
MNT : install the replhook by default
tacaswell Mar 3, 2015
28dcf3c
ENH : move draw_all to Gcf class method
tacaswell Mar 3, 2015
f9ac8d0
ENH : add dirty flag
tacaswell Mar 16, 2015
6a6f8d9
ENH : add force logic to draw_all
tacaswell Mar 16, 2015
b8bd396
ENH : first pass at making Line2D objects dirty-aware
tacaswell Mar 16, 2015
17c4461
ENH : add dirty flag to missed Line2D.set_* methods
tacaswell Mar 16, 2015
46af65a
MNT : only set the figure call back if figure is not None
tacaswell Mar 16, 2015
ef08aa1
MNT : rename dirty -> stale
tacaswell Mar 31, 2015
a8865f8
ENH : add stale flag to all set_* methods in Artist
tacaswell Mar 31, 2015
495b5a0
STY : don't re-define variables
tacaswell Apr 15, 2015
234cc9c
ENH : add stale flags to Collection
tacaswell Apr 21, 2015
771977f
ENH : add stale flag to _CollectionWithSizes
tacaswell Apr 21, 2015
1aaae20
ENH : add stale flag to PathCollection
tacaswell Apr 21, 2015
729ada7
ENH : add stale flag to PolyCollection
tacaswell Apr 21, 2015
fa5cb4d
ENH : add stale flag to EventCollection
tacaswell Apr 21, 2015
9cec66f
ENH : add stale flag to QuadMesh
tacaswell Apr 21, 2015
fb3562b
ENH : add stale flag to Figure
tacaswell Apr 27, 2015
6060a4c
ENH : add stale flag to *Image* classes
tacaswell Apr 28, 2015
bd4bd0b
DOC : fix axis -> axes typo in comment
tacaswell Apr 28, 2015
72fae28
ENH : add stale flag to Legend
tacaswell Apr 29, 2015
b2df645
ENH : add stale flag to Offsetbox
tacaswell Apr 30, 2015
7780821
ENH : add stale flag to PaddedBox
tacaswell Apr 30, 2015
cae51d3
ENH : add stale flag to DrawingArea
tacaswell Apr 30, 2015
ebf7b91
ENH : add stale flag to TextArea
tacaswell Apr 30, 2015
c5df792
ENH : add stale flag to AuxTransformBox
tacaswell Apr 30, 2015
74ebf82
STY : remove excessive indets
tacaswell Apr 30, 2015
e0e0039
ENH : add stale flag to AnchoredOffsetbox
tacaswell Apr 30, 2015
cb0a22f
ENH : add stale flag to OffsetImage
tacaswell Apr 30, 2015
15451c7
ENH : add stale flag to AnnotationBbox
tacaswell Apr 30, 2015
fb3181b
ENH : add stale flag to Patch
tacaswell Apr 30, 2015
8f8dba5
ENH : add stale flag to Rectangle
tacaswell Apr 30, 2015
cb82a85
ENH : add stale flag to Polygon
tacaswell Apr 30, 2015
77450ac
ENH : add stale flag to Wedge
tacaswell Apr 30, 2015
9c954e8
ENH : add stale flag to FancyBboxPatch
tacaswell Apr 30, 2015
da78f69
ENH : add stale flag to FancyArrowPatch
tacaswell Apr 30, 2015
1939831
ENH : add stale flag to FancyArrowPatch
tacaswell Apr 30, 2015
d8d52d8
ENH : add stale flag to QuiverKey
tacaswell Apr 30, 2015
013e1a7
ENH : add stale flag to Quiver
tacaswell Apr 30, 2015
406e8ce
ENH : add stale flag to Barb
tacaswell Apr 30, 2015
3290982
FIX : fix order of operation in __init__ functions
tacaswell May 4, 2015
c541248
FIX : use canonical linestyles kwarg in contour
tacaswell May 5, 2015
30d1060
MNT : remove unneeded call to set_linestyles
tacaswell May 5, 2015
c1de4dd
FIX : fix init order in AnnotationBbox
tacaswell May 5, 2015
79d971d
FIX : reorder __init__ of OffsetBox
tacaswell May 5, 2015
2c10dcb
ENH : add stale flag to Spines
tacaswell May 5, 2015
cd70834
ENH : add stale flag to Cell
tacaswell May 5, 2015
3f3ef10
ENH : add stale flag to CustumCell
tacaswell May 5, 2015
21c677f
ENH : add stale flag to Table
tacaswell May 5, 2015
e9aa714
ENH : add stale flag to Text
tacaswell May 5, 2015
3eeb64d
ENH : add stale flag to TextWithDash
tacaswell May 5, 2015
9706cc0
MNT : remove stale flags from Axes.draw
tacaswell May 5, 2015
16bcbdf
DOC : add whats new entry
tacaswell May 5, 2015
f824578
FIX : add missing stale flag to Line2D
tacaswell May 6, 2015
8112b43
MNT : use draw_idle not draw in Gcf.draw_all
tacaswell May 16, 2015
05f6426
ENH : add stale flag to Axes.cla
tacaswell May 16, 2015
d29be28
ENH : add stale flag to mplot3D.art3D.*
tacaswell May 16, 2015
2970d30
ENH : add stale flag to Axes3D
tacaswell May 16, 2015
83aafff
ENH : add stale flag to mplot3d.Axis
tacaswell May 16, 2015
a555475
DOC : fix docstrings which were lies
tacaswell May 16, 2015
f4efac1
MNT : add guards to only register repl hook once
tacaswell May 16, 2015
f41ae9e
DOC : added docstring to install_repl_displayhook
tacaswell May 16, 2015
096d714
ENH : added uninstall for repl displayhook
tacaswell May 16, 2015
17d9ada
FIX : order of operation is Poly3DCollection init
tacaswell May 16, 2015
54da8cc
ENH : integrate repl hook with is_interactive
tacaswell May 16, 2015
a26831d
FIX : logic for IPython hook registration
tacaswell May 16, 2015
1c99420
MNT : move repl install above boilerplate fold
tacaswell May 16, 2015
a9faf4b
ENH : add stale flag to Tick, XTick, YTick
tacaswell May 16, 2015
e3fb850
ENH : add stale flag to Axis, XAxis, YAxis
tacaswell May 16, 2015
2beb5f9
ENH : add stale flag to _AxesBase
tacaswell May 18, 2015
f15c871
MNT : hackily make boilerplate PY3 compatable
tacaswell May 16, 2015
b2fbae7
MNT : remove draw_if_interactive from boilerplate
tacaswell May 16, 2015
89923a6
MNT : remove non-boilerplate `draw_if_interactive`
tacaswell May 18, 2015
38f00af
MNT : make rcdefaults redraw all figures
tacaswell May 18, 2015
9724f3d
ENH : add stale flag to ColorbarBase and Colorbar
tacaswell May 24, 2015
0abbcf6
DOC: clearified whats new entry
tacaswell May 24, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions boilerplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def %(func)s(%(argspec)s):
%(ax)s.hold(hold)
try:
%(ret)s = %(ax)s.%(func)s(%(call)s)
draw_if_interactive()
finally:
%(ax)s.hold(%(washold)s)
%(mappable)s
Expand All @@ -69,7 +68,6 @@ def %(func)s(%(argspec)s):
@docstring.copy_dedent(Axes.%(func)s)
def %(func)s(%(argspec)s):
%(ret)s = gca().%(func)s(%(call)s)
draw_if_interactive()
return %(ret)s
"""

Expand All @@ -85,7 +83,6 @@ def {name}():

if im is not None:
im.set_cmap(cm.{name})
draw_if_interactive()

"""

Expand Down Expand Up @@ -219,8 +216,9 @@ def format_value(value):
else:
def_edited = []
for val in defaults:
if isinstance(val, unicode):
val = val.encode('ascii', 'ignore')
if six.PY2:
if isinstance(val, unicode):
val = val.encode('ascii', 'ignore')
def_edited.append(val)
defaults = tuple(def_edited)

Expand Down Expand Up @@ -273,7 +271,7 @@ def format_value(value):

# Since we can't avoid using some function names,
# bail out if they are used as argument names
for reserved in ('gca', 'gci', 'draw_if_interactive'):
for reserved in ('gca', 'gci'):
if reserved in bad:
msg = 'Axes method %s has kwarg named %s' % (func, reserved)
raise ValueError(msg)
Expand Down
38 changes: 38 additions & 0 deletions doc/users/whats_new/2015-05_interactive_OO.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Interactive OO usage
--------------------

All `Artists` now keep track of if their internal state has been
changed but not reflected in the display ('stale') by a call to
``draw``. It is thus possible to pragmatically determine if a given
`Figure` needs to be re-drawn in an interactive session.

To facilitate interactive usage a ``draw_all`` method has been added
to ``pyplot`` which will redraw all of the figures which are 'stale'.

To make this convenient for interactive use matplotlib now registers
a function either with IPython's 'post_execute' event or with the
displayhook in the standard python REPL to automatically call
``plt.draw_all`` just before control is returned to the REPL. This ensures
that the draw command is deferred and only called once.

The upshot of this is that for interactive backends (including
``%matplotlib notebook``) in interactive mode (with ``plt.ion()``)

.. ipython :: python

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ln, = ax.plot([0, 1, 4, 9, 16])

plt.show()

ln.set_color('g')


will automatically update the plot to be green. Any subsequent
modifications to the ``Artist`` objects will do likewise.

This is the first step of a larger consolidation and simplification of
the pyplot internals.
10 changes: 10 additions & 0 deletions lib/matplotlib/_pylab_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,15 @@ def set_active(cls, manager):
cls._activeQue.append(manager)
cls.figs[manager.num] = manager

@classmethod
def draw_all(cls, force=False):
"""
Redraw all figures registered with the pyplot
state machine.
"""
for f_mgr in cls.get_all_fig_managers():
# TODO add logic to check if figure is stale
if force or f_mgr.canvas.figure.stale:
f_mgr.canvas.draw_idle()

atexit.register(Gcf.destroy_all)
59 changes: 57 additions & 2 deletions lib/matplotlib/artist.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ def draw_wrapper(artist, renderer, *args, **kwargs):
return draw_wrapper


def _stale_figure_callback(self):
self.figure.stale = True


def _stale_axes_callback(self):
self.axes.stale = True


class Artist(object):
"""
Abstract base class for someone who renders into a
Expand All @@ -78,6 +86,7 @@ class Artist(object):
zorder = 0

def __init__(self):
self._stale = True
self._axes = None
self.figure = None

Expand Down Expand Up @@ -210,9 +219,33 @@ def axes(self, new_axes):
"probably trying to re-use an artist "
"in more than one Axes which is not "
"supported")

self._axes = new_axes
if new_axes is not None and new_axes is not self:
self.add_callback(_stale_axes_callback)

return new_axes

@property
def stale(self):
"""
If the artist is 'stale' and needs to be re-drawn for the output to
match the internal state of the artist.
"""
return self._stale

@stale.setter
def stale(self, val):
# only trigger call-back stack on being marked as 'stale'
# when not already stale
# the draw process will take care of propagating the cleaning
# process
if not (self._stale == val):
self._stale = val
# only trigger propagation if marking as stale
if self._stale:
self.pchanged()

def get_window_extent(self, renderer):
"""
Get the axes bounding box in display space.
Expand Down Expand Up @@ -283,6 +316,7 @@ def set_transform(self, t):
self._transform = t
self._transformSet = True
self.pchanged()
self.stale = True

def get_transform(self):
"""
Expand Down Expand Up @@ -499,6 +533,7 @@ def set_snap(self, snap):
Only supported by the Agg and MacOSX backends.
"""
self._snap = snap
self.stale = True

def get_sketch_params(self):
"""
Expand Down Expand Up @@ -546,13 +581,15 @@ def set_sketch_params(self, scale=None, length=None, randomness=None):
self._sketch = None
else:
self._sketch = (scale, length or 128.0, randomness or 16.0)
self.stale = True

def set_path_effects(self, path_effects):
"""
set path_effects, which should be a list of instances of
matplotlib.patheffect._Base class or its derivatives.
"""
self._path_effects = path_effects
self.stale = True

def get_path_effects(self):
return self._path_effects
Expand All @@ -572,7 +609,10 @@ def set_figure(self, fig):
ACCEPTS: a :class:`matplotlib.figure.Figure` instance
"""
self.figure = fig
self.pchanged()
if self.figure and self.figure is not self:
self.add_callback(_stale_figure_callback)
self.pchanged()
self.stale = True

def set_clip_box(self, clipbox):
"""
Expand All @@ -582,6 +622,7 @@ def set_clip_box(self, clipbox):
"""
self.clipbox = clipbox
self.pchanged()
self.stale = True

def set_clip_path(self, path, transform=None):
"""
Expand Down Expand Up @@ -634,8 +675,10 @@ def set_clip_path(self, path, transform=None):
if not success:
print(type(path), type(transform))
raise TypeError("Invalid arguments to set_clip_path")

# this may result in the callbacks being hit twice, but grantees they
# will be hit at least once
self.pchanged()
self.stale = True

def get_alpha(self):
"""
Expand Down Expand Up @@ -684,7 +727,10 @@ def set_clip_on(self, b):
ACCEPTS: [True | False]
"""
self._clipon = b
# This may result in the callbacks being hit twice, but ensures they
# are hit at least once
self.pchanged()
self.stale = True

def _set_gc_clip(self, gc):
'Set the clip properly for the gc'
Expand Down Expand Up @@ -723,11 +769,13 @@ def set_agg_filter(self, filter_func):

"""
self._agg_filter = filter_func
self.stale = True

def draw(self, renderer, *args, **kwargs):
'Derived classes drawing method'
if not self.get_visible():
return
self.stale = False

def set_alpha(self, alpha):
"""
Expand All @@ -738,6 +786,7 @@ def set_alpha(self, alpha):
"""
self._alpha = alpha
self.pchanged()
self.stale = True

def set_visible(self, b):
"""
Expand All @@ -747,6 +796,7 @@ def set_visible(self, b):
"""
self._visible = b
self.pchanged()
self.stale = True

def set_animated(self, b):
"""
Expand All @@ -756,6 +806,7 @@ def set_animated(self, b):
"""
self._animated = b
self.pchanged()
self.stale = True

def update(self, props):
"""
Expand All @@ -778,6 +829,7 @@ def update(self, props):
self.eventson = store
if changed:
self.pchanged()
self.stale = True

def get_label(self):
"""
Expand All @@ -796,6 +848,7 @@ def set_label(self, s):
else:
self._label = None
self.pchanged()
self.stale = True

def get_zorder(self):
"""
Expand All @@ -812,6 +865,7 @@ def set_zorder(self, level):
"""
self.zorder = level
self.pchanged()
self.stale = True

def update_from(self, other):
'Copy properties from *other* to *self*.'
Expand All @@ -826,6 +880,7 @@ def update_from(self, other):
self._sketch = other._sketch
self._path_effects = other._path_effects
self.pchanged()
self.stale = True

def properties(self):
"""
Expand Down
Loading