本文介绍了matplotlib 中的交互式线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 matplotlib 制作一个交互式绘图,该绘图在端点处创建一个带有两个手柄的线段.您可以单击并拖动手柄,线条将刷新以匹配以这种方式指定的位置,与此 matplotlib 示例类似 poly_editor :(如果您看到了示例,请想象我想要同样的东西,但多边形的一个边缘).

I'm trying to make an interactive plot using matplotlib that creates a line segment with two handles at the endpoints. You can click and drag the handles and the line will refresh to match the positions specified in this way, in a similar fashion to this matplotlib example poly_editor: (if you see the example, imagine that I want the same thing but with just one edge of the polygon).

我尝试更改poly_editor代码以仅与Line2D元素一起使用,并且我的程序运行时没有任何错误,只是它根本没有在轴上绘制任何内容.我认为这可能是变量范围内的错误,或者与来自 matplotlib 的绘制调用有关.关于错误的任何指导将不胜感激.

I have tried altering the poly_editor code to work with just the Line2D element, and my program runs without any errors, except that it doesn't draw anything on the axis at all. I think it might be an error in the scope of the variables or something to do with the draw calls from matplotlib. Any guidance as to what the errors are would be greatly appreciated.

我进行了一些进一步的改进,简化了代码,现在我可以用它来绘制线并在epsilon距离内打印最近的顶点的索引,但是该线保持静止并且没有动画.更新后的代码如下

I advanced some more, simplified the code and now I can get it to draw the line and print the index of the nearest vertex within epsilon distance, but the line stays stationary and does not animate. The updated code is bellow

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

class LineBuilder(object):

    epsilon = 0.5

    def __init__(self, line):
        canvas = line.figure.canvas
        self.canvas = canvas
        self.line = line
        self.axes = line.axes
        self.xs = list(line.get_xdata())
        self.ys = list(line.get_ydata())

        self.ind = None

        canvas.mpl_connect('button_press_event', self.button_press_callback)
        canvas.mpl_connect('button_release_event', self.button_release_callback)
        canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)

    def get_ind(self, event):
        x = np.array(self.line.get_xdata())
        y = np.array(self.line.get_ydata())
        d = np.sqrt((x-event.xdata)**2 + (y - event.ydata)**2)
        if min(d) > self.epsilon:
            return None
        if d[0] < d[1]:
            return 0
        else:
            return 1

    def button_press_callback(self, event):
        if event.button != 1:
            return
        self.ind = self.get_ind(event)
        print(self.ind)

        self.line.set_animated(True)
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.line.axes.bbox)

        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)

    def button_release_callback(self, event):
        if event.button != 1:
            return
        self.ind = None
        self.line.set_animated(False)
        self.background = None
        self.line.figure.canvas.draw()

    def motion_notify_callback(self, event):
        if event.inaxes != self.line.axes:
            return
        if event.button != 1:
            return
        if self.ind is None:
            return
        self.xs[self.ind] = event.xdata
        self.ys[self.ind] = event.ydata
        self.line.set_data(self.xs, self.ys)

        self.canvas.restore_region(self.background)
        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)


if __name__ == '__main__':
    fig, ax = plt.subplots()
    line = Line2D([0,1], [0,1], marker='o', markerfacecolor='red')
    ax.add_line(line)

    linebuilder = LineBuilder(line)

    ax.set_title('click to create lines')
    ax.set_xlim(-2,2)
    ax.set_ylim(-2,2)
    plt.show()

提前致谢,凯文.

推荐答案

好的,我解决了这个问题.新代码(上面)实际上有效,但其中有一个错误.运动通知事件的mpl_connect调用具有错误的事件类型,现在可以按预期运行.

Okay, I solved the problem. The new code (above) actually works, there was a mistake in it. The mpl_connect call for the motion notify event had the wrong event type, now it is working as intended.

这篇关于matplotlib 中的交互式线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 13:39