我尝试在 Jupyter 实验室和 Jupyter 笔记本中运行此示例 ,并从终端运行脚本,在所有情况下它都是静态的 - 不是交互式的。path_editor.ipynb
path_editor.py
当我从终端运行脚本时,我收到消息:
QWidget::repaint: Recursive repaint detected
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted
我有 matplotlib 版本 3.8.4、Jupyter Lab 版本 4.1.8 和 Jupyter Notebook 版本 7.1.3。
这是该示例的代码(来自上面链接的网站):
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backend_bases import MouseButton
from matplotlib.patches import PathPatch
from matplotlib.path import Path
fig, ax = plt.subplots()
pathdata = [
(Path.MOVETO, (1.58, -2.57)),
(Path.CURVE4, (0.35, -1.1)),
(Path.CURVE4, (-1.75, 2.0)),
(Path.CURVE4, (0.375, 2.0)),
(Path.LINETO, (0.85, 1.15)),
(Path.CURVE4, (2.2, 3.2)),
(Path.CURVE4, (3, 0.05)),
(Path.CURVE4, (2.0, -0.5)),
(Path.CLOSEPOLY, (1.58, -2.57)),
]
codes, verts = zip(*pathdata)
path = Path(verts, codes)
patch = PathPatch(
path, facecolor='green', edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
class PathInteractor:
"""
A path editor.
Press 't' to toggle vertex markers on and off. When vertex markers are on,
they can be dragged with the mouse.
"""
showverts = True
epsilon = 5 # max pixel distance to count as a vertex hit
def __init__(self, pathpatch):
self.ax = pathpatch.axes
canvas = self.ax.figure.canvas
self.pathpatch = pathpatch
self.pathpatch.set_animated(True)
x, y = zip(*self.pathpatch.get_path().vertices)
self.line, = ax.plot(
x, y, marker='o', markerfacecolor='r', animated=True)
self._ind = None # the active vertex
canvas.mpl_connect('draw_event', self.on_draw)
canvas.mpl_connect('button_press_event', self.on_button_press)
canvas.mpl_connect('key_press_event', self.on_key_press)
canvas.mpl_connect('button_release_event', self.on_button_release)
canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
self.canvas = canvas
def get_ind_under_point(self, event):
"""
Return the index of the point closest to the event position or *None*
if no point is within ``self.epsilon`` to the event position.
"""
xy = self.pathpatch.get_path().vertices
xyt = self.pathpatch.get_transform().transform(xy) # to display coords
xt, yt = xyt[:, 0], xyt[:, 1]
d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
ind = d.argmin()
return ind if d[ind] < self.epsilon else None
def on_draw(self, event):
"""Callback for draws."""
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.ax.draw_artist(self.pathpatch)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
def on_button_press(self, event):
"""Callback for mouse button presses."""
if (event.inaxes is None
or event.button != MouseButton.LEFT
or not self.showverts):
return
self._ind = self.get_ind_under_point(event)
def on_button_release(self, event):
"""Callback for mouse button releases."""
if (event.button != MouseButton.LEFT
or not self.showverts):
return
self._ind = None
def on_key_press(self, event):
"""Callback for key presses."""
if not event.inaxes:
return
if event.key == 't':
self.showverts = not self.showverts
self.line.set_visible(self.showverts)
if not self.showverts:
self._ind = None
self.canvas.draw()
def on_mouse_move(self, event):
"""Callback for mouse movements."""
if (self._ind is None
or event.inaxes is None
or event.button != MouseButton.LEFT
or not self.showverts):
return
vertices = self.pathpatch.get_path().vertices
vertices[self._ind] = event.xdata, event.ydata
self.line.set_data(zip(*vertices))
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.pathpatch)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
interactor = PathInteractor(patch)
ax.set_title('drag vertices to update path')
ax.set_xlim(-3, 4)
ax.set_ylim(-3, 4)
plt.show()
有什么办法可以让这个例子发挥作用吗?
编辑
安装后ipympl
,将笔记本分成两个单元(一个用于导入,第二个用于其他所有内容),然后将其放在%matplotlib ipympl
第二个单元的顶部,我现在收到以下错误消息:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\IPython\core\formatters.py:974, in MimeBundleFormatter.__call__(self, obj, include, exclude)
971 method = get_real_method(obj, self.print_method)
973 if method is not None:
--> 974 return method(include=include, exclude=exclude)
975 return None
976 else:
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\ipympl\backend_nbagg.py:336, in Canvas._repr_mimebundle_(self, **kwargs)
333 plaintext = plaintext[:110] + '…'
335 buf = io.BytesIO()
--> 336 self.figure.savefig(buf, format='png', dpi='figure')
338 base64_image = b64encode(buf.getvalue()).decode('utf-8')
339 self._data_url = f'data:image/png;base64,{base64_image}'
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\figure.py:3390, in Figure.savefig(self, fname, transparent, **kwargs)
3388 for ax in self.axes:
3389 _recursively_make_axes_transparent(stack, ax)
-> 3390 self.canvas.print_figure(fname, **kwargs)
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backend_bases.py:2193, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2189 try:
2190 # _get_renderer may change the figure dpi (as vector formats
2191 # force the figure dpi to 72), so we need to set it again here.
2192 with cbook._setattr_cm(self.figure, dpi=dpi):
-> 2193 result = print_method(
2194 filename,
2195 facecolor=facecolor,
2196 edgecolor=edgecolor,
2197 orientation=orientation,
2198 bbox_inches_restore=_bbox_inches_restore,
2199 **kwargs)
2200 finally:
2201 if bbox_inches and restore_bbox:
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backend_bases.py:2043, in FigureCanvasBase._switch_canvas_and_return_print_method.<locals>.<lambda>(*args, **kwargs)
2039 optional_kws = { # Passed by print_figure for other renderers.
2040 "dpi", "facecolor", "edgecolor", "orientation",
2041 "bbox_inches_restore"}
2042 skip = optional_kws - {*inspect.signature(meth).parameters}
-> 2043 print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
2044 *args, **{k: v for k, v in kwargs.items() if k not in skip}))
2045 else: # Let third-parties do as they see fit.
2046 print_method = meth
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backends\backend_agg.py:497, in FigureCanvasAgg.print_png(self, filename_or_obj, metadata, pil_kwargs)
450 def print_png(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
451 """
452 Write the figure to a PNG file.
453
(...)
495 *metadata*, including the default 'Software' key.
496 """
--> 497 self._print_pil(filename_or_obj, "png", pil_kwargs, metadata)
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backends\backend_agg.py:445, in FigureCanvasAgg._print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata)
440 def _print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata=None):
441 """
442 Draw the canvas, then save it using `.image.imsave` (to which
443 *pil_kwargs* and *metadata* are forwarded).
444 """
--> 445 FigureCanvasAgg.draw(self)
446 mpl.image.imsave(
447 filename_or_obj, self.buffer_rgba(), format=fmt, origin="upper",
448 dpi=self.figure.dpi, metadata=metadata, pil_kwargs=pil_kwargs)
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backends\backend_agg.py:388, in FigureCanvasAgg.draw(self)
385 # Acquire a lock on the shared font cache.
386 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
387 else nullcontext()):
--> 388 self.figure.draw(self.renderer)
389 # A GUI class may be need to update a window using this draw, so
390 # don't forget to call the superclass.
391 super().draw()
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\artist.py:95, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
93 @wraps(draw)
94 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 95 result = draw(artist, renderer, *args, **kwargs)
96 if renderer._rasterizing:
97 renderer.stop_rasterizing()
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
69 if artist.get_agg_filter() is not None:
70 renderer.start_filter()
---> 72 return draw(artist, renderer)
73 finally:
74 if artist.get_agg_filter() is not None:
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\figure.py:3164, in Figure.draw(self, renderer)
3161 finally:
3162 self.stale = False
-> 3164 DrawEvent("draw_event", self.canvas, renderer)._process()
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backend_bases.py:1271, in Event._process(self)
1269 def _process(self):
1270 """Process this event on ``self.canvas``, then unset ``guiEvent``."""
-> 1271 self.canvas.callbacks.process(self.name, self)
1272 self._guiEvent_deleted = True
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\cbook.py:303, in CallbackRegistry.process(self, s, *args, **kwargs)
301 except Exception as exc:
302 if self.exception_handler is not None:
--> 303 self.exception_handler(exc)
304 else:
305 raise
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\cbook.py:87, in _exception_printer(exc)
85 def _exception_printer(exc):
86 if _get_running_interactive_framework() in ["headless", None]:
---> 87 raise exc
88 else:
89 traceback.print_exc()
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\cbook.py:298, in CallbackRegistry.process(self, s, *args, **kwargs)
296 if func is not None:
297 try:
--> 298 func(*args, **kwargs)
299 # this does not capture KeyboardInterrupt, SystemExit,
300 # and GeneratorExit
301 except Exception as exc:
Cell In[2], line 73, in PathInteractor.on_draw(self, event)
71 self.ax.draw_artist(self.pathpatch)
72 self.ax.draw_artist(self.line)
---> 73 self.canvas.blit(self.ax.bbox)
File ~\AppData\Local\anaconda3\envs\joe_env\lib\site-packages\matplotlib\backends\backend_webagg_core.py:195, in FigureCanvasWebAggCore.blit(self, bbox)
193 def blit(self, bbox=None):
194 self._png_is_old = True
--> 195 self.manager.refresh_all()
AttributeError: 'NoneType' object has no attribute 'refresh_all'
将这两件事放在一起就可以在评论中找到答案。
在现代 JupyterLab 和 Jupyter Notebook 7+ 中安装
ipympl
和使用,请参阅此处了解更多详细信息。%matplotlib ipympl
注释掉一行以避免有关 的
self.canvas.blit(self.ax.bbox)
错误。AttributeError: 'NoneType' object has no attribute 'refresh_all'
blit()
给出 OP 代码的更新版本为: