Skip to content
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

Enh python repl rd2 #4506

Merged
merged 6 commits into from Jul 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion examples/mplot3d/rotate_axes3d_demo.py
Expand Up @@ -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')
Expand Down
1 change: 0 additions & 1 deletion examples/mplot3d/wire3d_animation_demo.py
Expand Up @@ -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')

Expand Down
58 changes: 32 additions & 26 deletions lib/matplotlib/pyplot.py
Expand Up @@ -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():
"""
Expand All @@ -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
Expand All @@ -136,33 +135,23 @@ 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
_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():
Expand All @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -288,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
Expand Down Expand Up @@ -507,8 +496,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 "
Expand Down Expand Up @@ -543,9 +531,26 @@ def make_active(event):
_pylab_helpers.Gcf.set_active(figManager)
figManager.canvas.figure.number = num

if _INSTALL_FIG_OBSERVER:
figManager.canvas.figure.add_callback(_auto_draw_if_interactive)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why limit this to figures created by pyplot? As far as I see it this takes us quite some distance towards implementing MEP26 (Dynamic Artist Style Sheets).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is a possibly annoying feature for people embedding mpl into larger applications. They should be able control on what rep-cycle they trigger re-draws. They now have an easy way to tell if they need to, but we should not impose on them re-draws they do not want. Ex setting a timed call back to every .05s check if anything is stale and if so trigger a re-draw of just that figure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay... but could we control that by an rcParam or something?


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():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why limit this only to interactive backends?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because if we are not interactive the user does not get updates? This is just mimicking the existing pyplot behavior of draw_if_interactive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"does not get updates" = "cannot update"? Well if we assume that, then we just add an unnecessary check....

However consider tools, if we add a tool that calls my_line2d.set_color('purple'), this line means you need to add a canvas.draw_idle() after that in the tool, but if you run in interactive mode, you don't need it. This feels like inconsistent behaviour... but happy to get persuaded why we don't/may not want that.

fig.canvas.draw_idle()


def gcf():
"Get a reference to the current figure."

Expand All @@ -555,6 +560,7 @@ def gcf():
else:
return figure()


def fignum_exists(num):
return _pylab_helpers.Gcf.has_fignum(num) or num in get_figlabels()

Expand Down