From 0f1dbc5f9eaa99aed2f01a6166f2b16dfda1d58d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 8 Jun 2015 08:45:20 -0400 Subject: [PATCH 1/6] MNT: rename function to be more accurate The IPython hook we use in post_execute, not display. --- lib/matplotlib/pyplot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 2de9711df408..61c998c4ac5e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -136,18 +136,18 @@ class _NotIPython(Exception): if _IP_REGISTERED: return - def displayhook(): + def post_execute(): if matplotlib.is_interactive(): draw_all() # IPython >= 2 try: - ip.events.register('post_execute', displayhook) + ip.events.register('post_execute', post_execute) except AttributeError: # IPython 1.x - ip.register_post_execute(displayhook) + ip.register_post_execute(post_execute) - _IP_REGISTERED = displayhook + _IP_REGISTERED = post_execute # import failed or ipython is not running except (ImportError, _NotIPython): From 1b83af386e31e881c3703d87d2cf2fc8bd27e9b5 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 8 Jun 2015 08:52:05 -0400 Subject: [PATCH 2/6] STY: remove linebreak for readability --- lib/matplotlib/pyplot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 61c998c4ac5e..99b545442344 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -507,8 +507,7 @@ def figure(num=None, # autoincrement if None, else integer from 1-N if figManager is None: max_open_warning = rcParams['figure.max_open_warning'] - if (max_open_warning >= 1 and - len(allnums) >= max_open_warning): + if (max_open_warning >= 1 and len(allnums) >= max_open_warning): warnings.warn( "More than %d figures have been opened. Figures " "created through the pyplot interface " From 494e4c7bda2e0e4c76c4a80ac518558d07519c93 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 8 Jun 2015 09:10:34 -0400 Subject: [PATCH 3/6] ENH: redraw callback on Figure in base repl If we do not have IPython, then the only hook I know of in the repl is the display hook which is called when ever something is going to be displayed, not after the execution of the last command has finished (the reason it exists is to give users a chance to intercept and change the display of the output, not as a generic call back as we were trying to use it). In this case register a callback on the `Figure` artist at creation time to call `draw_idle` on the canvas if the Figure is stale. We are guaranteed to see this at least once when stale is flipped to True, but may see it more than once if other paths call `pchanged()`. Fortunately, `pchanged` is not widely used in the internal code base and even if `draw_idle` is called multiple times, we should be able to count on the backends handling multiple draw_idle commands correctly. Closes #4504 --- lib/matplotlib/pyplot.py | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 99b545442344..4e46d9cd6535 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -108,9 +108,8 @@ def _backend_selection(): from matplotlib.backends import pylab_setup _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() -_BASE_DH = None _IP_REGISTERED = None - +_INSTALL_FIG_OBSERVER = False def install_repl_displayhook(): """ @@ -119,8 +118,8 @@ def install_repl_displayhook(): This works with both IPython terminals and vanilla python shells. """ - global _BASE_DH global _IP_REGISTERED + global _INSTALL_FIG_OBSERVER class _NotIPython(Exception): pass @@ -148,21 +147,11 @@ def post_execute(): ip.register_post_execute(post_execute) _IP_REGISTERED = post_execute + _INSTALL_FIG_OBSERVER = False # import failed or ipython is not running except (ImportError, _NotIPython): - - if _BASE_DH is not None: - return - - dh = _BASE_DH = sys.displayhook - - def displayhook(*args): - dh(*args) - if matplotlib.is_interactive(): - draw_all() - - sys.displayhook = displayhook + _INSTALL_FIG_OBSERVER = True def uninstall_repl_displayhook(): @@ -181,8 +170,8 @@ def uninstall_repl_displayhook(): function was there when matplotlib installed it's displayhook, possibly discarding your changes. """ - global _BASE_DH global _IP_REGISTERED + global _INSTALL_FIG_OBSERVER if _IP_REGISTERED: from IPython import get_ipython ip = get_ipython() @@ -193,9 +182,8 @@ def uninstall_repl_displayhook(): "in IPython < 2.0") _IP_REGISTERED = None - if _BASE_DH: - sys.displayhook = _BASE_DH - _BASE_DH = None + if _INSTALL_FIG_OBSERVER: + _INSTALL_FIG_OBSERVER = False draw_all = _pylab_helpers.Gcf.draw_all @@ -541,6 +529,11 @@ def make_active(event): _pylab_helpers.Gcf.set_active(figManager) figManager.canvas.figure.number = num + if _INSTALL_FIG_OBSERVER: + def auto_draw(fig): + if fig.stale and matplotlib.is_interactive(): + fig.canvas.draw_idle() + figManager.canvas.figure.add_callback(auto_draw) return figManager.canvas.figure From 57bfa346b5f44095611b0a8a761f9e364e497aa4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 8 Jun 2015 09:26:03 -0400 Subject: [PATCH 4/6] PRF: only draw in `plt.pause` if stale Avoids a possibly un-needed re-draw. --- lib/matplotlib/pyplot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 4e46d9cd6535..08dfb1a1917d 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -276,7 +276,8 @@ def pause(interval): figManager = _pylab_helpers.Gcf.get_active() if figManager is not None: canvas = figManager.canvas - canvas.draw() + if canvas.figure.stale: + canvas.draw() show(block=False) canvas.start_event_loop(interval) return From 1d66b42ecbd0cbd8d3b182a8f77ad93adbd87e95 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 8 Jun 2015 16:43:03 -0400 Subject: [PATCH 5/6] FIX: use toplevel function so pickle works --- lib/matplotlib/pyplot.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 08dfb1a1917d..3fef645f524f 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -530,15 +530,27 @@ def make_active(event): _pylab_helpers.Gcf.set_active(figManager) figManager.canvas.figure.number = num + if _INSTALL_FIG_OBSERVER: - def auto_draw(fig): - if fig.stale and matplotlib.is_interactive(): - fig.canvas.draw_idle() - figManager.canvas.figure.add_callback(auto_draw) + figManager.canvas.figure.add_callback(_auto_draw_if_interactive) return figManager.canvas.figure +def _auto_draw_if_interactive(fig): + """ + This is an internal helper function for making sure that auto-redrawing + works as intended in the plain python repl. + + Parameters + ---------- + fig : Figure + A figure object which is assumed to be associated with a canvas + """ + if fig.stale and matplotlib.is_interactive(): + fig.canvas.draw_idle() + + def gcf(): "Get a reference to the current figure." @@ -548,6 +560,7 @@ def gcf(): else: return figure() + def fignum_exists(num): return _pylab_helpers.Gcf.has_fignum(num) or num in get_figlabels() From a0737fdc171a7ef41213d27811029379d58e2a93 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 15 Jun 2015 21:23:42 -0400 Subject: [PATCH 6/6] MNT: remove plt.ion() from demos --- examples/mplot3d/rotate_axes3d_demo.py | 1 - examples/mplot3d/wire3d_animation_demo.py | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/mplot3d/rotate_axes3d_demo.py b/examples/mplot3d/rotate_axes3d_demo.py index 55ec41177dea..1c715478a7b7 100644 --- a/examples/mplot3d/rotate_axes3d_demo.py +++ b/examples/mplot3d/rotate_axes3d_demo.py @@ -2,7 +2,6 @@ import matplotlib.pyplot as plt import numpy as np -plt.ion() fig = plt.figure() ax = fig.add_subplot(111, projection='3d') diff --git a/examples/mplot3d/wire3d_animation_demo.py b/examples/mplot3d/wire3d_animation_demo.py index 47c55b6d8d73..c030d95509ed 100644 --- a/examples/mplot3d/wire3d_animation_demo.py +++ b/examples/mplot3d/wire3d_animation_demo.py @@ -12,7 +12,6 @@ def generate(X, Y, phi): R = 1 - np.sqrt(X**2 + Y**2) return np.cos(2 * np.pi * X + phi) * R -plt.ion() fig = plt.figure() ax = fig.add_subplot(111, projection='3d')