matplotlib - Matplotlib:在绘图中插入图像并能够用鼠标拖动它
问题描述
我写了一个脚本,灵感来自这里的可拖动矩形练习,它让我可以绘制多边形,目前是矩形和三角形,可以用鼠标拖动。
这是代码:
import numpy as np
import matplotlib.pyplot as plt
from abc import ABCMeta, abstractmethod
import logging
#
# Create and set logger
#
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
class Polygon:
__metaclass__ = ABCMeta
_lock = None # only one can be animated at a time
@abstractmethod
def compute_edges(self):
raise NotImplementedError("Implemented in child classes")
def __init__(self, center, height, width, orientation, id_, type_,
**kwargs):
self.center = center
self.height = height
self.width = width
if not "radian" in orientation:
orientation["radian"] = orientation["degree"] / 180. * np.pi
self.orientation = orientation
self.polygon = plt.Polygon(self.compute_edges(), **kwargs)
self.press = None
self.background = None
self.id_ = id_
self.type_ = type_
def connect(self):
'connect to all the events we need'
self.cidpress = self.polygon.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.polygon.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.polygon.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
self.cidscroll = self.polygon.figure.canvas.mpl_connect(
'scroll_event', self.on_scroll)
def on_press(self, event):
'on button press we will see if the mouse is over us and store some data'
if event.inaxes != self.polygon.axes:
return
if Polygon._lock is not None:
return
contains, attrd = self.polygon.contains(event)
if not contains:
return
self.press = np.copy(self.polygon.xy), event.xdata, event.ydata
Polygon._lock = self
logger.debug("Pressed polygon (%s, %d) at (%f, %f)", self.type_,
self.id_, event.xdata, event.ydata)
# draw everything but the selected polygon and store the pixel buffer
canvas = self.polygon.figure.canvas
axes = self.polygon.axes
self.polygon.set_animated(True)
canvas.draw()
self.background = canvas.copy_from_bbox(self.polygon.axes.bbox)
# now redraw just the polygon
axes.draw_artist(self.polygon)
# and blit just the redrawn area
canvas.blit(axes.bbox)
def on_scroll(self, event):
if event.inaxes != self.polygon.axes:
return
if Polygon._lock is not None:
return
contains, attrd = self.polygon.contains(event)
if not contains:
return
def on_motion(self, event):
'on motion we will move the rect if the mouse is over us'
if Polygon._lock is not self:
return
if event.inaxes != self.polygon.axes:
return
xy, xpress, ypress = self.press
dx = event.xdata - xpress
dy = event.ydata - ypress
self.polygon.xy[:, 0] = xy[:, 0] + dx
self.polygon.xy[:, 1] = xy[:, 1] + dy
self.center = self.polygon.xy.mean(axis=0)
logger.debug("Move polygon (%s, %d) to (%f, %f)", self.type_, self.id_,
self.center[0], self.center[1])
canvas = self.polygon.figure.canvas
axes = self.polygon.axes
# restore the background region
canvas.restore_region(self.background)
# redraw just the current polygon
axes.draw_artist(self.polygon)
# blit just the redrawn area
canvas.blit(axes.bbox)
#plt.gcf().savefig("test.png")
def on_release(self, event):
'on release we reset the press data'
if Polygon._lock is not self:
return
self.press = None
Polygon._lock = None
logger.debug("Release polygon (%s, %d) at (%f, %f)", self.type_,
self.id_, self.center[0], self.center[1])
# turn off the polygon animation property and reset the background
self.polygon.set_animated(False)
self.background = None
# redraw the full figure
self.polygon.figure.canvas.draw()
def disconnect(self):
'disconnect all the stored connection ids'
self.polygon.figure.canvas.mpl_disconnect(self.cidpress)
self.polygon.figure.canvas.mpl_disconnect(self.cidrelease)
self.polygon.figure.canvas.mpl_disconnect(self.cidmotion)
self.polygon.figure.canvas.mpl_disconnect(self.cidscroll)
class Triangle(Polygon):
_id = 0
def compute_edges(self):
self.orientation["cos"] = np.cos(self.orientation["radian"])
self.orientation["sin"] = np.sin(self.orientation["radian"])
return np.array(
[[
self.center[0] + 2 * self.height * self.orientation["cos"] / 3,
self.center[1] + 2 * self.height * self.orientation["sin"] / 3
],
[
self.center[0] - self.width * 0.5 * self.orientation["sin"] -
self.height / 3. * self.orientation["cos"],
self.center[1] + self.width * 0.5 * self.orientation["cos"] -
self.height / 3. * self.orientation["sin"]
],
[
self.center[0] + self.width * 0.5 * self.orientation["sin"] -
self.height / 3. * self.orientation["cos"],
self.center[1] - self.width * 0.5 * self.orientation["cos"] -
self.height / 3. * self.orientation["sin"]
]])
def __init__(self, center, height, width, orientation, **kwargs):
Polygon.__init__(self, center, height, width, orientation,
Triangle._id, "target", **kwargs)
Triangle._id += 1
class Rectangle(Polygon):
_id = 0
def compute_edges(self):
self.orientation["cos"] = np.cos(self.orientation["radian"])
self.orientation["sin"] = np.sin(self.orientation["radian"])
return np.array(
[[
self.center[0] + 0.5 * self.height * self.orientation["cos"] +
0.5 * self.width * self.orientation["sin"],
self.center[1] + 0.5 * self.height * self.orientation["sin"] -
0.5 * self.width * self.orientation["cos"]
],
[
self.center[0] + 0.5 * self.height * self.orientation["cos"] -
0.5 * self.width * self.orientation["sin"],
self.center[1] + 0.5 * self.height * self.orientation["sin"] +
0.5 * self.width * self.orientation["cos"]
],
[
self.center[0] - 0.5 * self.height * self.orientation["cos"] -
0.5 * self.width * self.orientation["sin"],
self.center[1] - 0.5 * self.height * self.orientation["sin"] +
0.5 * self.width * self.orientation["cos"]
],
[
self.center[0] - 0.5 * self.height * self.orientation["cos"] +
0.5 * self.width * self.orientation["sin"],
self.center[1] - 0.5 * self.height * self.orientation["sin"] -
0.5 * self.width * self.orientation["cos"]
]])
def __init__(self, center, height, width, orientation, **kwargs):
Polygon.__init__(self, center, height, width, orientation,
Rectangle._id, "launcher", **kwargs)
Rectangle._id += 1
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(xmax=20)
ax.set_ylim(ymax=20)
ax.set_aspect("equal")
polygons = [
Triangle([2, 6], 2, 1, {"degree": 30.}, color="red"),
Triangle([6, 3], 2, 1, {"degree": 200.}, color="red"),
Rectangle([2, 2], 2, 1, {"degree": 60.}, color="blue"),
Rectangle([10, 2], 2, 1, {"degree": 60.}, color="blue")
]
for pol in polygons:
ax.add_patch(pol.polygon)
pol.connect()
plt.show()
我想做同样的事情,但使用图像(png、jpg 或 svg),也就是说用文件中的图像替换多边形。
我在 matplotlib 或与此相关的其他地方找不到任何示例。
你认为有可能吗?我该怎么办?
我想我首先必须将图像加载到一个补丁中,然后将其添加到绘图轴,但目前尚不清楚如何拖动这个可能与多边形属性不同的补丁。
问候
解决方案
推荐阅读
- javascript - 使用 location.replace 时,我可以打开应用程序的特定选项卡/将数据传递给应用程序吗?
- json - 从选择查询到 json 存储数据
- kubernetes - kind“网关”和“虚拟服务”没有匹配项
- powershell - 如何通过 PowerShell 处理远程服务器消息?
- arrays - 在 TypeScript 中获取类子类化数组的类名?
- postgresql - Prisma migrate dev:连接到数据库时运行命令?
- jenkins - 多作业参数
- c# - 从 C# 中的 OAuthAuthorizationServer 注册后生成访问令牌
- python - 如何在python中编辑字符串并添加引号
- file - Sharepoint 共享链接在过期日期后仍然可用