mpl_gui._promotion 的原始程式碼
"""State and logic to promote a Figure -> a GUI window."""
import threading
import itertools
import matplotlib as mpl
from matplotlib import is_interactive
from matplotlib.cbook import _api
from matplotlib.backend_bases import FigureCanvasBase
from ._manage_backend import current_backend_module
_figure_count = itertools.count()
def _auto_draw_if_interactive(fig, val):
"""
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 (
val
and is_interactive()
and not fig.canvas.is_saving()
and not fig.canvas._is_idle_drawing
):
# Some artists can mark themselves as stale in the middle of drawing
# (e.g. axes position & tick labels being computed at draw time), but
# this shouldn't trigger a redraw because the current redraw will
# already take them into account.
with fig.canvas._idle_draw_cntx():
fig.canvas.draw_idle()
[docs]def promote_figure(fig, *, auto_draw=True):
"""Create a new figure manager instance."""
_backend_mod = current_backend_module()
if (
getattr(_backend_mod.FigureCanvas, "required_interactive_framework", None)
and threading.current_thread() is not threading.main_thread()
):
_api.warn_external(
"Starting a Matplotlib GUI outside of the main thread will likely fail."
)
if fig.canvas.manager is not None:
if not isinstance(fig.canvas.manager, _backend_mod.FigureManager):
raise Exception("Figure already has a manager an it is the wrong type!")
else:
# TODO is this the right behavior?
return fig.canvas.manager
# TODO: do we want to make sure we poison / destroy / decouple the existing
# canavs?
manager = _backend_mod.new_figure_manager_given_figure(next(_figure_count), fig)
if fig.get_label():
manager.set_window_title(fig.get_label())
if auto_draw:
fig.stale_callback = _auto_draw_if_interactive
if is_interactive():
manager.show()
fig.canvas.draw_idle()
# HACK: the callback in backend_bases uses GCF.destroy which misses these
# figures by design!
def _destroy(event):
if event.key in mpl.rcParams["keymap.quit"]:
# grab the manager off the event
mgr = event.canvas.manager
if mgr is None:
raise RuntimeError("Should never be here, please report a bug")
fig = event.canvas.figure
# remove this callback. Callbacks lives on the Figure so survive
# the canvas being replaced.
old_cid = getattr(mgr, "_destroy_cid", None)
if old_cid is not None:
fig.canvas.mpl_disconnect(old_cid)
mgr._destroy_cid = None
# close the window
mgr.destroy()
# disconnect the manager from the canvas
fig.canvas.manager = None
# reset the dpi
fig.dpi = getattr(fig, "_original_dpi", fig.dpi)
# Go back to "base" canvas
# (this sets state on fig in the canvas init)
FigureCanvasBase(fig)
manager._destroy_cid = fig.canvas.mpl_connect("key_press_event", _destroy)
return manager