gpt4 book ai didi

python - 如何将 matplotlib 包含限制为一个对象?

转载 作者:行者123 更新时间:2023-11-28 17:25:35 25 4
gpt4 key购买 nike

我正在开发一个带有可拖动线条的简单 GUI,以允许用户以可视化方式显示一些绘制的数据。

使用 matplotlib's event handling documentation我已经能够实现可拖动窗口行的初始版本:

import numpy as np
import matplotlib.pyplot as plt

class DraggableLine:
def __init__(self, orientation, ax, position):
if orientation.lower() == 'horizontal':
self.myline, = ax.plot(ax.get_xlim(), np.array([1, 1])*position)
self.orientation = orientation.lower()
elif orientation.lower() == 'vertical':
self.myline, = ax.plot(np.array([1, 1])*position, ax.get_ylim())
self.orientation = orientation.lower()
else:
# throw an error
pass

self.parentfig = self.myline.figure.canvas
self.parentax = ax

self.clickpress = self.parentfig.mpl_connect('button_press_event', self.on_click) # Execute on mouse click
self.clicked = False

def on_click(self, event):
# Executed on mouse click
if event.inaxes != self.parentax: return # See if the mouse is over the parent axes object

# See if the click is on top of this line object
contains, attrs = self.myline.contains(event)
if not contains: return

self.mousemotion = self.parentfig.mpl_connect('motion_notify_event', self.on_motion)
self.clickrelease = self.parentfig.mpl_connect('button_release_event', self.on_release)
self.clicked = True

def on_motion(self, event):
# Executed on mouse motion
if not self.clicked: return # See if we've clicked yet
if event.inaxes != self.parentax: return # See if we're moving over the parent axes object

if self.orientation == 'vertical':
self.myline.set_xdata(np.array([1, 1])*event.xdata)
self.myline.set_ydata(self.parentax.get_ylim())
elif self.orientation == 'horizontal':
self.myline.set_xdata(self.parentax.get_xlim())
self.myline.set_ydata(np.array([1, 1])*event.ydata)

self.parentfig.draw()

def on_release(self, event):
self.clicked = False

self.parentfig.mpl_disconnect(self.mousemotion)
self.parentfig.mpl_disconnect(self.clickrelease)
self.parentfig.draw()

生成的行符合预期:

fig = plt.figure()
ax = fig.add_subplot(111)

vl1 = DraggableLine('vertical', ax, 3)
vl2 = DraggableLine('vertical', ax, 6)

ax.set_xlim([0, 10])
plt.show()

但是,当线条堆叠时,移动单条线的能力就会丢失,因为 matplotlib.lines.Line2D.contains() 不知道一个对象被另一个对象遮挡。所以我们只能拖着一大块物体四处走动,直到情节结束。

是否有已经实现的方法来缓解此问题?如果没有,我认为一种方法是在鼠标释放时查询父轴的子轴以获取 DraggableLine 类的实例,检查它们的位置,然后连接/断开 'button_press_event' 必要时。我不确定这在时间上是否最有意义。

最佳答案

一种方法可能是检查轴的子项以查找将触发其各自“移动”回调的对象,查看哪个对象呈现在最顶部,然后仅移动该对象。

对于上面的例子,我定义了一个额外的方法:

def shouldthismove(self, event):
# Check to see if this object has been clicked on
contains, attrs = self.myline.contains(event)
if not contains:
# We haven't been clicked
timetomove = False
else:
# See how many draggable objects contains this event
firingobjs = []
for child in self.parentax.get_children():
if child._label == 'dragobj':
contains, attrs = child.contains(event)
if contains:
firingobjs.append(child)

# Assume the last child object is the topmost rendered object, only move if we're it
if firingobjs[-1] == self.myline:
timetomove = True
else:
timetomove = False

return timetomove

重新定义了我的 on_click 方法:

def on_click(self, event):
# Executed on mouse click
if event.inaxes != self.parentax: return # See if the mouse is over the parent axes object

# Check for overlaps, make sure we only fire for one object per click
timetomove = self.shouldthismove(event)
if not timetomove: return

self.mousemotion = self.parentfig.canvas.mpl_connect('motion_notify_event', self.on_motion)
self.clickrelease = self.parentfig.canvas.mpl_connect('button_release_event', self.on_release)
self.clicked = True

并在 __init__ 中为我的线对象添加了一个通用标签,以加快稍后对轴子项的过滤:

self.myline._label = 'dragobj'

关于python - 如何将 matplotlib 包含限制为一个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39276925/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com