可拖动的行在Matplotlib中相互选择 [英] Draggable lines select one another in Matplotlib

查看:82
本文介绍了可拖动的行在Matplotlib中相互选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用matplotlib处理和拾取来创建一类可拖动的线.目的是在图形上设置不同的阈值和间隔.这是代码:

I'm trying to create a class of draggable lines using matplotlib handling and picking. The aim is to set different thresholds and intervals on a graph. Here is the code:

import matplotlib.pyplot as plt
import matplotlib.lines as lines
import numpy as np

class draggable_lines:

    def __init__(self, ax, kind, XorY):

        self.ax = ax
        self.c = ax.get_figure().canvas
        self.o = kind
        self.XorY = XorY

        if kind == "h":
            x = [-1, 1]
            y = [XorY, XorY]

        elif kind == "v":
            x = [XorY, XorY]
            y = [-1, 1]

        else:
            print("choose h or v line")

        self.line = lines.Line2D(x, y, picker=5)
        self.ax.add_line(self.line)
        self.c.draw()
        sid = self.c.mpl_connect('pick_event', self.clickonline)

    # pick line when I select it 
    def clickonline(self, event):

        self.active_line = event.artist
        print("line selected ", event.artist)
        self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse)
        self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick)

    # The selected line must follow the mouse
    def followmouse(self, event):

        if self.o == "h":
            self.line.set_ydata([event.ydata, event.ydata])
        else:
            self.line.set_xdata([event.xdata, event.xdata])

        self.c.draw()

    # release line on click
    def releaseonclick(self, event):

        if self.o == "h":
            self.XorY = self.line.get_ydata()[0]
        else:
            self.XorY = self.line.get_xdata()[0]

        print (self.XorY)

        self.c.mpl_disconnect(self.releaser)
        self.c.mpl_disconnect(self.follower)


plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
Vline = draggable_lines(ax, "h", 0.5)
Tline = draggable_lines(ax, "v", 0.5)
Tline2 = draggable_lines(ax, "v", 0.1)

行为是我仅使用1行时的预期效果(即使它在我释放行时也通知选择内容).

The behavior is what I expected when using only 1 line (even if it notify the selection also when I release the line).

当我使用多行时,它会同时选择所有这些行!

When I'm using more than one line it selects all of them at the same time!

我认为我误解了事件管理器的功能,但是我无法理解为什么区分不同的对象(如我在 print("line selected",event.artist)中所见)应该选择自己和另一个!

I think I'm misunderstanding the event manager functionality, but I cannot understand why different objects, well distinguished (as I can see in the print("line selected ", event.artist)) should select themselves and another!

推荐答案

人们可能会提出不同的疑问:如果单击其中的任意一个,matplotlib将如何知道要拖动的行?答:不会,因为它具有三个回调,每行一个回调,并将全部执行.

One could ask differently: How would matplotlib know which line to drag if you click on any of them? Answer: it wouldn't, because it has three callbacks, one for each line and will execute them all.

因此,解决方案是首先检查单击的行是否实际上是要在'pick_event'回调中移动的行:

The solution is hence to first check if the line clicked is actually the line to be moved inside the 'pick_event' callback:

if event.artist == self.line:
    # register other callbacks

(换句话说:如果不这么频繁地调用 canvas.draw(),而是调用 canvas.draw_idle(),您会从中受益)

(On a different note: You would benefit from not calling canvas.draw() so often, but instead canvas.draw_idle())

import matplotlib.pyplot as plt
import matplotlib.lines as lines

class draggable_lines:
    def __init__(self, ax, kind, XorY):
        self.ax = ax
        self.c = ax.get_figure().canvas
        self.o = kind
        self.XorY = XorY

        if kind == "h":
            x = [-1, 1]
            y = [XorY, XorY]

        elif kind == "v":
            x = [XorY, XorY]
            y = [-1, 1]
        self.line = lines.Line2D(x, y, picker=5)
        self.ax.add_line(self.line)
        self.c.draw_idle()
        self.sid = self.c.mpl_connect('pick_event', self.clickonline)

    def clickonline(self, event):
        if event.artist == self.line:
            print("line selected ", event.artist)
            self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse)
            self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick)

    def followmouse(self, event):
        if self.o == "h":
            self.line.set_ydata([event.ydata, event.ydata])
        else:
            self.line.set_xdata([event.xdata, event.xdata])
        self.c.draw_idle()

    def releaseonclick(self, event):
        if self.o == "h":
            self.XorY = self.line.get_ydata()[0]
        else:
            self.XorY = self.line.get_xdata()[0]

        print (self.XorY)

        self.c.mpl_disconnect(self.releaser)
        self.c.mpl_disconnect(self.follower)

fig = plt.figure()
ax = fig.add_subplot(111)
Vline = draggable_lines(ax, "h", 0.5)
Tline = draggable_lines(ax, "v", 0.5)
Tline2 = draggable_lines(ax, "v", 0.1)
plt.show()

这篇关于可拖动的行在Matplotlib中相互选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆