-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
MEP27 Decouple pyplot from backends (refactoring Gcf out of backend code) #4143
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
Changes from all commits
24caf2b
2b05d38
f4fc354
0b31e3a
6fb452e
0a868a2
61ba2b4
f0eb84c
8fe9cd7
494e5f1
ed16178
21b8f58
cf42e3b
f027b16
24b7b73
bc99129
7f7f05e
713abcb
80adaaf
4e5f69d
160ef57
b6d6acc
ecd5038
f8e83fe
c53b79a
34c6b12
8a4268a
44df199
860a8ed
c44e744
2fe9215
3b434ef
490629f
8eb987b
224a4f3
cdbd51b
50e3719
85be519
7edaf5a
8e6e252
72575cb
4a78246
e300707
ee76451
6f0c7ab
ae9bf5b
fb004e0
1d2095b
24e43b3
208c3be
a44ebd9
f8f9cf2
0e09a54
a38b6d7
64f0c61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
toolbar : toolmanager |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
'''This example demonstrates how to: | ||
* Create new toolbars | ||
* Create new windows | ||
Using `matplotlib.backend_managers.ToolManager`, | ||
`matplotlib.backend_bases.WindowBase` and | ||
`matplotlib.backend_bases.ToolContainerBase` | ||
''' | ||
|
||
from __future__ import print_function | ||
import matplotlib | ||
matplotlib.use('GTK3Cairo') | ||
matplotlib.rcParams['toolbar'] = 'toolmanager' | ||
import matplotlib.pyplot as plt | ||
|
||
fig = plt.figure() | ||
|
||
# Shortcuts to FigureManager and ToolManager | ||
manager = fig.canvas.manager | ||
tool_mgr = manager.toolmanager | ||
|
||
# Create a new toolbar | ||
topbar = manager.backend.Toolbar(tool_mgr) | ||
|
||
# Add it to the figure window, we can place it north, east, west and south | ||
manager.window.add_element(topbar, 'north') | ||
|
||
# Remove some tools from the main toolbar and add them to the | ||
# new sidebar | ||
for tool in ('home', 'back', 'forward'): | ||
manager.toolbar.remove_toolitem(tool) | ||
topbar.add_tool(tool, None) | ||
|
||
plt.plot([1, 2, 3]) | ||
|
||
# Add a new window | ||
win = manager.backend.Window('Extra tools') | ||
|
||
# create a sidebar for the new window | ||
sidebar = manager.backend.Toolbar(tool_mgr) | ||
|
||
# add the sidebar to the new window | ||
win.add_element(sidebar, 'west') | ||
|
||
# Add some tools to the new sidebar | ||
for tool in ('home', 'back', 'forward', 'zoom', 'pan'): | ||
sidebar.add_tool(tool, None) | ||
|
||
# show the new window | ||
win.show() | ||
|
||
plt.show() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ | |
import gc | ||
import atexit | ||
|
||
from matplotlib import is_interactive | ||
|
||
|
||
def error_msg(msg): | ||
print(msg, file=sys.stderr) | ||
|
@@ -35,6 +37,16 @@ class Gcf(object): | |
_activeQue = [] | ||
figs = {} | ||
|
||
@classmethod | ||
def add_figure_manager(cls, manager): | ||
cls.figs[manager.num] = manager | ||
try: # TODO remove once all backends converted to use the new manager. | ||
manager.mpl_connect('window_destroy_event', cls.destroy_cbk) | ||
except: | ||
pass | ||
|
||
cls.set_active(manager) | ||
|
||
@classmethod | ||
def get_fig_manager(cls, num): | ||
""" | ||
|
@@ -46,6 +58,56 @@ def get_fig_manager(cls, num): | |
cls.set_active(manager) | ||
return manager | ||
|
||
@classmethod | ||
def show_all(cls, block=None): | ||
""" | ||
Show all figures. If *block* is not None, then | ||
it is a boolean that overrides all other factors | ||
determining whether show blocks by calling mainloop(). | ||
The other factors are: | ||
it does not block if run inside ipython's "%pylab" mode | ||
it does not block in interactive mode. | ||
""" | ||
|
||
managers = cls.get_all_fig_managers() | ||
if not managers: | ||
return | ||
|
||
for manager in managers: | ||
manager.show() | ||
|
||
if block is True: | ||
# Start the mainloop on the last manager, so we don't have a | ||
# mainloop starting for each manager. Not ideal, but works for now. | ||
manager._mainloop() | ||
return | ||
elif block is False: | ||
return | ||
|
||
# Hack: determine at runtime whether we are | ||
# inside ipython in pylab mode. | ||
from matplotlib import pyplot | ||
try: | ||
ipython_pylab = not pyplot.show._needmain | ||
# IPython versions >= 0.10 tack the _needmain | ||
# attribute onto pyplot.show, and always set | ||
# it to False, when in %pylab mode. | ||
ipython_pylab = ipython_pylab and manager.backend_name != 'webagg' | ||
# TODO: The above is a hack to get the WebAgg backend | ||
# working with ipython's `%pylab` mode until proper | ||
# integration is implemented. | ||
except AttributeError: | ||
ipython_pylab = False | ||
|
||
# Leave the following as a separate step in case we | ||
# want to control this behavior with an rcParam. | ||
if ipython_pylab: | ||
return | ||
|
||
# If not interactive we need to block | ||
if not is_interactive() or manager.backend_name == 'webagg': | ||
manager._mainloop() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. huh? if it isn't interactive, then start a mainloop? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of this method I just copy pasted from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably be good to explain that in a comment |
||
|
||
@classmethod | ||
def destroy(cls, num): | ||
""" | ||
|
@@ -68,7 +130,7 @@ def destroy(cls, num): | |
cls._activeQue.append(f) | ||
|
||
del cls.figs[num] | ||
manager.destroy() | ||
manager.destroy() # Unneeded with MEP27 remove later | ||
gc.collect(1) | ||
|
||
@classmethod | ||
|
@@ -137,7 +199,6 @@ def set_active(cls, manager): | |
if m != manager: | ||
cls._activeQue.append(m) | ||
cls._activeQue.append(manager) | ||
cls.figs[manager.num] = manager | ||
|
||
@classmethod | ||
def draw_all(cls, force=False): | ||
|
@@ -149,4 +210,8 @@ def draw_all(cls, force=False): | |
if force or f_mgr.canvas.figure.stale: | ||
f_mgr.canvas.draw_idle() | ||
|
||
@classmethod | ||
def destroy_cbk(cls, event): | ||
cls.destroy(event.figure_manager.num) | ||
|
||
atexit.register(Gcf.destroy_all) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
who is this manager? the last one of managers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because calling mainloop will pause execution here... we only want one to pause it once we have shown all of the managers.