matplotlib - 直接在画布上绘图

时间:2014-03-13 10:58:22

标签: python matplotlib

由于动态更新的性能问题,我需要在画布上直接绘制很多矩形作为非常低的级别,也就是说不使用matplotlib.patches,因为我们必须使用经典的GUI。 / p>

更确切地说,我想只绘制一个矩形,而不仅仅是绘制所有图形。

有可能吗?

这是我使用Joe Kington提供的链接的测试代码。

#!/usr/bin/env python3

from random import randint, choice
import time

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.colors as colors
import matplotlib

back_color = "black"
colors     = ['red', 'green', 'cyan', 'yellow']

width  = 16
height = 16

ax     = plt.subplot(111)
canvas = ax.figure.canvas

ax.set_xlim([0, width])
ax.set_ylim([0, height])

def update():
    global ax, canvas, colors, width, height

    x = randint(0, width - 1)
    y = randint(0, height - 1)

    rect = mpatches.Rectangle(
        (x, y), 1, 1,
        facecolor = choice(colors),
        edgecolor = back_color
    )

    start = time.time()
    ax.draw_artist(rect)
    canvas.blit(ax.bbox)
    print("draw >>>", time.time() - start)

timer = canvas.new_timer(interval = 1)
timer.add_callback(update)
timer.start()

plt.show()

在Mac O $下,我收到以下消息。

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/matplotlib/backend_bases.py", line 1203, in _on_timer
    ret = func(*args, **kwargs)
  File "/Users/xxx/test.py", line 86, in update
    ax.draw_artist(rect)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/matplotlib/axes.py", line 2100, in draw_artist
    a.draw(self._cachedRenderer)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/matplotlib/artist.py", line 56, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/matplotlib/patches.py", line 393, in draw
    gc = renderer.new_gc()
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages/matplotlib/backends/backend_macosx.py", line 97, in new_gc
    self.gc.save()
RuntimeError: CGContextRef is NULL

对于Maverick用户

对于想要使用以下代码以及动画的Mac用户,我有一个好消息。我在没有任何软件的情况下在我的Mac上重新安装了Maverick OS,这称为干净安装,然后我安装了Anaconda和XQuark(see this)。

要使动画生效,只需在任何其他matplotlib导入之前使用以下两行。

import matplotlib
matplotlib.use('TkAgg')

我认为这适用于Anaconda支持的任何Mac OS。只有Maverick才需要使用XQuark。

1 个答案:

答案 0 :(得分:1)

您当前的代码存在两个问题。

  1. 你没有先画画布,试图搞砸。你得到的错误是后端特定的,但基本上,它说的是画布的渲染器还没有被初始化。
  2. 您没有将矩形艺术家添加到轴中。因此,您不会使用ax.draw_artist(rect)
  3. 来绘制它

    这是一个有效的例子:

    from random import randint, choice
    import time
    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    
    back_color = "black"
    colors     = ['red', 'green', 'cyan', 'yellow']
    width, height = 16, 16
    
    fig, ax = plt.subplots()
    ax.set(xlim=[0, width], ylim=[0, height]) # Or use "ax.axis([x0,x1,y0,y1])"
    
    # Be sure to draw the canvas once before we start blitting. Otherwise
    # a) the renderer doesn't exist yet, and b) there's noting to blit onto
    fig.canvas.draw()
    
    def update():
        x = randint(0, width - 1)
        y = randint(0, height - 1)
    
        rect = mpatches.Rectangle(
            (x, y), 1, 1,
            facecolor = choice(colors),
            edgecolor = back_color
        )
        ax.add_artist(rect)
    
        start = time.time()
        ax.draw_artist(rect)
        fig.canvas.blit(ax.bbox)
        print("draw >>>", time.time() - start)
    
    timer = fig.canvas.new_timer(interval=1)
    timer.add_callback(update)
    timer.start()
    
    plt.show()
    

    但是,在这一点上,每次添加新艺术家都会更有意义。相反,添加初始矩形并每次更新它。例如:

    from random import randint, choice
    import time
    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    
    back_color = "black"
    colors     = ['red', 'green', 'cyan', 'yellow']
    
    width, height = 16, 16
    
    fig, ax = plt.subplots()
    ax.set(xlim=[0, width], ylim=[0, height]) # Or use "ax.axis([x0,x1,y0,y1])"
    
    rect = mpatches.Rectangle(
        (0, 0), 1, 1,
        facecolor = choice(colors),
        edgecolor = back_color
    )
    ax.add_artist(rect)
    
    # Be sure to draw the canvas once before we start blitting. Otherwise
    # a) the renderer doesn't exist yet, and b) there's noting to blit onto
    fig.canvas.draw()
    
    def update():
        x = randint(0, width - 1)
        y = randint(0, height - 1)
        rect.set(xy=[x,y], facecolor=choice(colors))
    
        start = time.time()
        ax.draw_artist(rect)
        fig.canvas.blit(ax.bbox)
        print("draw >>>", time.time() - start)
    
    timer = fig.canvas.new_timer(interval=1)
    timer.add_callback(update)
    timer.start()
    
    plt.show()