【问题标题】:Redrawing figure in matplotlib eventually crashes python.exe在 matplotlib 中重绘图形最终会导致 python.exe 崩溃
【发布时间】:2017-05-18 12:52:08
【问题描述】:

我是matplotlib 的新手,所以请耐心等待我解释。

我正在使用matplotlib 绘制一个包含一些形状的二维图形。你可以看到下面的代码和输出图:

from random import randint
import matplotlib.path as path
import matplotlib.pyplot as plt
import matplotlib.patches as patches

from matplotlib.pyplot import plot, ion, show
import numpy


box_a_midd_x = 200
box_a_midd_y = -300
box_a_width = 100
box_a_height = 400
box_a_x = box_a_midd_x - box_a_width / 2
box_a_y = box_a_midd_y - box_a_height / 2
box_a = path.Path([(box_a_x, box_a_y), (box_a_x, box_a_y + box_a_height), (box_a_x + box_a_height, box_a_y + box_a_height), (box_a_x + box_a_height, box_a_y)])

box_b_midd_x = 700
box_b_midd_y = 100
box_b_width = 200
box_b_height = 400
box_b_x = box_b_midd_x - box_b_width / 2
box_b_y = box_b_midd_y - box_b_height / 2
box_b = path.Path([(box_b_x, box_b_y), (box_b_x, box_b_y + box_b_height), (box_b_x + box_b_height, box_b_y + box_b_height), (box_b_x + box_b_height, box_b_y)])

box_c_midd_x = 700
box_c_midd_y = 700
box_c_width = 200
box_c_height = 400
box_c_x = box_c_midd_x - box_c_width / 2
box_c_y = box_c_midd_y - box_c_height / 2
box_c = path.Path([(box_c_x, box_c_y), (box_c_x, box_c_y + box_c_height), (box_c_x + box_c_height, box_c_y + box_c_height), (box_c_x + box_c_height, box_c_y)])    

box_d_midd_x = 700
box_d_midd_y = 1400
box_d_width = 200
box_d_height = 400
box_d_x = box_d_midd_x - box_d_width / 2
box_d_y = box_d_midd_y - box_d_height / 2
box_d = path.Path([(box_d_x, box_d_y), (box_d_x, box_d_y + box_d_height), (box_d_x + box_d_height, box_d_y + box_d_height), (box_d_x + box_d_height, box_d_y)])    

monitor_box = path.Path([(35, 1677), (11, -213), (652, -220), (500, 1734)])

print "A: " + str(box_a)
print "B: " + str(box_b)
print "C: " + str(box_c)
print "D: " + str(box_d)

#plt.plot([], [])
#ion()
fig = plt.figure()
ax = fig.add_subplot(111)
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
patch_a = patches.PathPatch(box_a, facecolor='orange', lw=2)
patch_b = patches.PathPatch(box_b, facecolor='orange', lw=2)
patch_c = patches.PathPatch(box_c, facecolor='orange', lw=2)
patch_d = patches.PathPatch(box_d, facecolor='orange', lw=2)
ax.add_patch(patch)
ax.add_patch(patch_a)
ax.add_patch(patch_b)
ax.add_patch(patch_c)
ax.add_patch(patch_d)
ax.set_xlim(-2000,2000)
ax.set_ylim(-2000,2000)
plt.gca().invert_yaxis()
#plt.plot([1], [1], 'ro')
#plt.draw()
#plt.show(block=False)
#plt.show()
plt.ion()
xs = [0]
ys = [0]
line, = plt.plot([xs[0], ys[0]], 'ro')
line.set_data(xs, ys)
plt.show()
plt.draw()
plt.pause(0.001)


def update_line(hl, new_data):
    hl.set_xdata(numpy.append(hl.get_xdata(), new_data))
    hl.set_ydata(numpy.append(hl.get_ydata(), new_data))
    plt.draw()



while(True):
    app_x = randint(0,2000)
    app_y = randint(0,2000)

    isInsideA = box_a.contains_points([(app_x,app_y)])
    isInsideB = box_b.contains_points([(app_x,app_y)])
    isInsideC = box_c.contains_points([(app_x,app_y)])
    isInsideD = box_d.contains_points([(app_x,app_y)])
    whichBox = ""
    if isInsideA:
        whichBox = "A"
    elif isInsideB:
        whichBox = "B"
    elif isInsideC:
        whichBox = "C"
    elif isInsideD:
        whichBox = "D"
    else:
        whichBox = "..."

    print ("X: " + str(int(app_x)) + "\t Y: " + str(int(app_y)) + " \t" + str(whichBox))
    xs[0] = int(app_x)
    ys[0] = int(app_y)
    line.set_data(xs, ys)
    plt.show()
    plt.draw()

输出图看起来像这样(真的没什么特别的)。

问题是图表在几秒钟(30-40 秒,而且看起来很随机)后崩溃(Not responsing)。 当图形窗口挂起时,您仍然可以看到 python 代码仍在运行,并且打印了新值,但图形中不再发生任何事情。 我不知道从哪里继续。 请运行上面完整的最小示例,希望您能看到问题。

我在 Windows 7 机器上运行 Python 2.7.8。 更具体地说是 Python 2.7.8(默认,2014 年 6 月 30 日,16:03:49)[MSC v.1500 32 位(英特尔)] 在 win32 上。

【问题讨论】:

标签: python python-2.7 animation matplotlib leap-motion


【解决方案1】:

def myfunc(x): 返回 hasattr(x, 'set_color')

for o in fig.findobj(myfunc):
    o.set_color('blue')

import matplotlib.text as text

for o in fig.findobj(text.Text):
    o.set_fontstyle('italic')

【讨论】:

    【解决方案2】:

    您为每次迭代创建一个新图。 最好使用 set_data() 并附加到 x 和 y 坐标列表:

    plt.ion()
    xs = [random.randint(-1000, 1000)]
    ys = [random.randint(-1000, 1000)]
    line, = plt.plot([xs[0], ys[0]], 'ro')
    for _ in range(1000):
        xs.append(random.randint(-1000, 1000))
        ys.append(random.randint(-1000, 1000))
        line.set_data(xs, ys)
        plt.show()
        plt.draw()
        plt.pause(0.001)
    plt.ioff()
    plt.show()
    

    这是两个列表,每个列表都有一个随机数:

    xs = [random.randint(-1000, 1000)]
    ys = [random.randint(-1000, 1000)]
    

    现在,使用这些列表创建一个绘图:

    line, = plt.plot([xs[0], ys[0]], 'ro')
    

    在循环中,模拟从 LeapMotion 设备获得的新 x 和 y 值并将它们附加到您的坐标:

    xs.append(random.randint(-1000, 1000))
    ys.append(random.randint(-1000, 1000))
    

    用新坐标更新你的情节:

    line.set_data(xs, ys)
    

    【讨论】:

    • 我在我的代码中加入了您的建议(不同之处在于我的代码几乎永远在 for 循环中并继续绘制最新点)。大约 1 分钟后,图表仍然挂起(不响应)。有什么想法吗?
    • 您需要用您的逻辑替换 for 循环以获取新的 x 和 y 值。当您每次执行 line.set_data(xs, ys)追加 不同的 x 和 y 到 xsys 时,您应该会看到不同位置的点。循环结束后,plt.ioff() 停止动画。将 for _ in range(1000): 增加到 for _ in range(100000): 以获得更长的动画。
    • 我一次只显示一个点,像这样self.xs[0] = int(app_x) self.ys[0] = int(app_y) self.line.set_data(self.xs, self.ys),一段时间后图表仍然崩溃
    • 可能是 Windows 导致的崩溃。还有一种更复杂的方法。最好添加一个Minimal, Complete, and Verifiable example,即我可以在没有 USB 设备的情况下运行和测试的东西。
    • 请查看更新。我添加了一个最小、完整且可运行的示例。
    猜你喜欢
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    相关资源
    最近更新 更多