##// END OF EJS Templates
use get_ipython API function, not builtin injection, to detect IPython.
MinRK -
Show More
@@ -1,153 +1,151 b''
1 """A matplotlib backend for publishing figures via display_data"""
1 """A matplotlib backend for publishing figures via display_data"""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2011 The IPython Development Team
3 # Copyright (C) 2011 The IPython Development Team
4 #
4 #
5 # Distributed under the terms of the BSD License. The full license is in
5 # Distributed under the terms of the BSD License. The full license is in
6 # the file COPYING, distributed as part of this software.
6 # the file COPYING, distributed as part of this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Imports
10 # Imports
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 # Third-party imports
14 # Third-party imports
15 import matplotlib
15 import matplotlib
16 from matplotlib.backends.backend_agg import FigureCanvasAgg
16 from matplotlib.backends.backend_agg import FigureCanvasAgg
17 from matplotlib._pylab_helpers import Gcf
17 from matplotlib._pylab_helpers import Gcf
18
18
19 # Local imports
19 # Local imports
20 from IPython.core.getipython import get_ipython
20 from IPython.core.getipython import get_ipython
21 from IPython.core.display import display
21 from IPython.core.display import display
22
22
23 from .config import InlineBackend
23 from .config import InlineBackend
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Functions
26 # Functions
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 def show(close=None):
29 def show(close=None):
30 """Show all figures as SVG/PNG payloads sent to the IPython clients.
30 """Show all figures as SVG/PNG payloads sent to the IPython clients.
31
31
32 Parameters
32 Parameters
33 ----------
33 ----------
34 close : bool, optional
34 close : bool, optional
35 If true, a ``plt.close('all')`` call is automatically issued after
35 If true, a ``plt.close('all')`` call is automatically issued after
36 sending all the figures. If this is set, the figures will entirely
36 sending all the figures. If this is set, the figures will entirely
37 removed from the internal list of figures.
37 removed from the internal list of figures.
38 """
38 """
39 if close is None:
39 if close is None:
40 close = InlineBackend.instance().close_figures
40 close = InlineBackend.instance().close_figures
41 try:
41 try:
42 for figure_manager in Gcf.get_all_fig_managers():
42 for figure_manager in Gcf.get_all_fig_managers():
43 display(figure_manager.canvas.figure)
43 display(figure_manager.canvas.figure)
44 finally:
44 finally:
45 show._to_draw = []
45 show._to_draw = []
46 if close:
46 if close:
47 matplotlib.pyplot.close('all')
47 matplotlib.pyplot.close('all')
48
48
49
49
50 # This flag will be reset by draw_if_interactive when called
50 # This flag will be reset by draw_if_interactive when called
51 show._draw_called = False
51 show._draw_called = False
52 # list of figures to draw when flush_figures is called
52 # list of figures to draw when flush_figures is called
53 show._to_draw = []
53 show._to_draw = []
54
54
55
55
56 def draw_if_interactive():
56 def draw_if_interactive():
57 """
57 """
58 Is called after every pylab drawing command
58 Is called after every pylab drawing command
59 """
59 """
60 # signal that the current active figure should be sent at the end of
60 # signal that the current active figure should be sent at the end of
61 # execution. Also sets the _draw_called flag, signaling that there will be
61 # execution. Also sets the _draw_called flag, signaling that there will be
62 # something to send. At the end of the code execution, a separate call to
62 # something to send. At the end of the code execution, a separate call to
63 # flush_figures() will act upon these values
63 # flush_figures() will act upon these values
64 manager = Gcf.get_active()
64 manager = Gcf.get_active()
65 if manager is None:
65 if manager is None:
66 return
66 return
67 fig = manager.canvas.figure
67 fig = manager.canvas.figure
68
68
69 # Hack: matplotlib FigureManager objects in interacive backends (at least
69 # Hack: matplotlib FigureManager objects in interacive backends (at least
70 # in some of them) monkeypatch the figure object and add a .show() method
70 # in some of them) monkeypatch the figure object and add a .show() method
71 # to it. This applies the same monkeypatch in order to support user code
71 # to it. This applies the same monkeypatch in order to support user code
72 # that might expect `.show()` to be part of the official API of figure
72 # that might expect `.show()` to be part of the official API of figure
73 # objects.
73 # objects.
74 # For further reference:
74 # For further reference:
75 # https://github.com/ipython/ipython/issues/1612
75 # https://github.com/ipython/ipython/issues/1612
76 # https://github.com/matplotlib/matplotlib/issues/835
76 # https://github.com/matplotlib/matplotlib/issues/835
77
77
78 if not hasattr(fig, 'show'):
78 if not hasattr(fig, 'show'):
79 # Queue up `fig` for display
79 # Queue up `fig` for display
80 fig.show = lambda *a: display(fig)
80 fig.show = lambda *a: display(fig)
81
81
82 # If matplotlib was manually set to non-interactive mode, this function
82 # If matplotlib was manually set to non-interactive mode, this function
83 # should be a no-op (otherwise we'll generate duplicate plots, since a user
83 # should be a no-op (otherwise we'll generate duplicate plots, since a user
84 # who set ioff() manually expects to make separate draw/show calls).
84 # who set ioff() manually expects to make separate draw/show calls).
85 if not matplotlib.is_interactive():
85 if not matplotlib.is_interactive():
86 return
86 return
87
87
88 # ensure current figure will be drawn, and each subsequent call
88 # ensure current figure will be drawn, and each subsequent call
89 # of draw_if_interactive() moves the active figure to ensure it is
89 # of draw_if_interactive() moves the active figure to ensure it is
90 # drawn last
90 # drawn last
91 try:
91 try:
92 show._to_draw.remove(fig)
92 show._to_draw.remove(fig)
93 except ValueError:
93 except ValueError:
94 # ensure it only appears in the draw list once
94 # ensure it only appears in the draw list once
95 pass
95 pass
96 # Queue up the figure for drawing in next show() call
96 # Queue up the figure for drawing in next show() call
97 show._to_draw.append(fig)
97 show._to_draw.append(fig)
98 show._draw_called = True
98 show._draw_called = True
99
99
100
100
101 def flush_figures():
101 def flush_figures():
102 """Send all figures that changed
102 """Send all figures that changed
103
103
104 This is meant to be called automatically and will call show() if, during
104 This is meant to be called automatically and will call show() if, during
105 prior code execution, there had been any calls to draw_if_interactive.
105 prior code execution, there had been any calls to draw_if_interactive.
106
106
107 This function is meant to be used as a post_execute callback in IPython,
107 This function is meant to be used as a post_execute callback in IPython,
108 so user-caused errors are handled with showtraceback() instead of being
108 so user-caused errors are handled with showtraceback() instead of being
109 allowed to raise. If this function is not called from within IPython,
109 allowed to raise. If this function is not called from within IPython,
110 then these exceptions will raise.
110 then these exceptions will raise.
111 """
111 """
112 if not show._draw_called:
112 if not show._draw_called:
113 return
113 return
114
114
115 if InlineBackend.instance().close_figures:
115 if InlineBackend.instance().close_figures:
116 # ignore the tracking, just draw and close all figures
116 # ignore the tracking, just draw and close all figures
117 try:
117 try:
118 return show(True)
118 return show(True)
119 except Exception as e:
119 except Exception as e:
120 # safely show traceback if in IPython, else raise
120 # safely show traceback if in IPython, else raise
121 try:
121 ip = get_ipython()
122 get_ipython
122 if ip is None:
123 except NameError:
124 raise e
123 raise e
125 else:
124 else:
126 get_ipython().showtraceback()
125 ip.showtraceback()
127 return
126 return
128 try:
127 try:
129 # exclude any figures that were closed:
128 # exclude any figures that were closed:
130 active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
129 active = set([fm.canvas.figure for fm in Gcf.get_all_fig_managers()])
131 for fig in [ fig for fig in show._to_draw if fig in active ]:
130 for fig in [ fig for fig in show._to_draw if fig in active ]:
132 try:
131 try:
133 display(fig)
132 display(fig)
134 except Exception as e:
133 except Exception as e:
135 # safely show traceback if in IPython, else raise
134 # safely show traceback if in IPython, else raise
136 try:
135 ip = get_ipython()
137 get_ipython
136 if ip is None:
138 except NameError:
139 raise e
137 raise e
140 else:
138 else:
141 get_ipython().showtraceback()
139 ip.showtraceback()
142 break
140 return
143 finally:
141 finally:
144 # clear flags for next round
142 # clear flags for next round
145 show._to_draw = []
143 show._to_draw = []
146 show._draw_called = False
144 show._draw_called = False
147
145
148
146
149 # Changes to matplotlib in version 1.2 requires a mpl backend to supply a default
147 # Changes to matplotlib in version 1.2 requires a mpl backend to supply a default
150 # figurecanvas. This is set here to a Agg canvas
148 # figurecanvas. This is set here to a Agg canvas
151 # See https://github.com/matplotlib/matplotlib/pull/1125
149 # See https://github.com/matplotlib/matplotlib/pull/1125
152 FigureCanvas = FigureCanvasAgg
150 FigureCanvas = FigureCanvasAgg
153
151
General Comments 0
You need to be logged in to leave comments. Login now