如何快速绘制数千个圆圈?

时间:2015-09-07 18:05:49

标签: python performance object matplotlib

我试图绘制几个(数千个)圆形对象 - 我没有多少使用python的经验。我对指定位置,半径和颜色很感兴趣。有没有更有效的方法来实现相同的结果?:

import matplotlib.pyplot as plt

xvals = [0,.1,.2,.3]
yvals = [0,.1,.2,.3]
rvals = [0,.1,.1,.1]

c1vals = [0,.1,0..1]
c2vals = [.1,0,.1,0]
c3vals = [.1,.1,.1,.1]

for q in range(0,4):
    circle1=plt.Circle((xvals[q], yvals[q]), rvals[q], color=[0,0,0])
    plt.gcf().gca().add_artist(circle1)

4 个答案:

答案 0 :(得分:10)

这里的关键是使用Collection。在您的情况下,您想要制作PatchCollection

Matplotlib通过使用集合优化绘制许多类似的艺术家。它比单独绘制每一个要快得多。此外,该剧情不会包含数千名个人艺术家,只有一个系列。这样可以加速每次绘制情节时需要对每位艺术家进行操作的许多其他操作。

scatter实际上 比当前方法更快,因为它会添加一个集合而不是单独的艺术家。但是,它还会绘制尺寸不在数据坐标中的标记。

要解决这个问题,您可以使用相同的方法scatter,但手动创建集合。

举个例子:

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

num = 5000
sizes = 0.2 * np.random.random(num)
xy = 50 * np.random.random((num, 2))

# Note that the patches won't be added to the axes, instead a collection will
patches = [plt.Circle(center, size) for center, size in zip(xy, sizes)]

fig, ax = plt.subplots()

coll = matplotlib.collections.PatchCollection(patches, facecolors='black')
ax.add_collection(coll)

ax.margins(0.01)
plt.show()

enter image description here

这对我来说非常顺利。只是为了证明圆圈在数据坐标中,请注意如果我们放大一个窄矩形会发生什么(注意:这假设绘图的方面设置为auto):

enter image description here

如果您真的专注于速度,可以使用EllipseCollection作为@tcaswell建议。

EllipseCollection只会生成一个路径,但会在绘制时缩放并将其翻译为您指定的地点/尺寸。

缺点是,虽然大小可以在数据坐标中,但圆圈将始终为圆形,即使绘图的宽高比不是1.(即圆圈不会延伸为他们在上图中做了。)

优点是速度快。

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

num = 5000
sizes = 0.4 * np.random.random(num)
xy = 50 * np.random.random((num, 2))

fig, ax = plt.subplots()

coll = matplotlib.collections.EllipseCollection(sizes, sizes,
                                                np.zeros_like(sizes),
                                                offsets=xy, units='x',
                                                transOffset=ax.transData,
                                                **kwargs)
ax.add_collection(coll)
ax.margins(0.01)
plt.show()

enter image description here

当我们放大与第二个数字类似的区域时,请注意差异。圆圈变大(尺寸在数据坐标中),但保持圆圈而不是变长。它们并不是数据"中的圆圈的准确表示。空间。

enter image description here

为了对时差有所了解,现在是时候使用三种方法中的每种方法创建和绘制具有相同5000个圆圈的图形:

In [5]: %timeit time_plotting(circles)
1 loops, best of 3: 3.84 s per loop

In [6]: %timeit time_plotting(patch_collection)
1 loops, best of 3: 1.37 s per loop

In [7]: %timeit time_plotting(ellipse_collection)
1 loops, best of 3: 228 ms per loop

答案 1 :(得分:3)

scatter对你来说可能比plt.Circle更好,尽管它不会让任何事情变得更快。

for i in range(4):
    mp.scatter(xvals[i], yvals[i], s=rvals[i])

如果你可以处理相同大小的圈子,那么mp.plot(xvals[i], yvals[i], marker='o')会更高效。

但这可能是matplotlib限制,而不是语言限制。有很好的JavaScript库可以有效地绘制数千个数据点(d3.js)。也许有人会知道你可以从Python调用的那个。

答案 2 :(得分:1)

您肯定希望将...gca()移到循环之外。您也可以使用列表理解。

fig = plt.figure()
ax = plt.gcf().gca()

[ax.add_artist(plt.Circle((xvals[q],yvals[q]),rvals[q],color=[0,0,0])) 
 for q in xrange(4)]  # range(4) for Python3

以下是使用各种方法生成4,000个圆圈的一些测试:

xvals = [0,.1,.2,.3] * 1000
yvals = [0,.1,.2,.3] * 1000
rvals = [0,.1,.1,.1] * 1000

%%timeit -n5 fig = plt.figure(); ax = plt.gcf().gca()
for q in range(4000):
    circle1=plt.Circle((xvals[q], yvals[q]), rvals[q], color=[0,0,0])
    plt.gcf().gca().add_artist(circle1)
5 loops, best of 3: 792 ms per loop

%%timeit -n5 fig = plt.figure(); ax = plt.gcf().gca()
for q in xrange(4000):
    ax.add_artist(plt.Circle((xvals[q],yvals[q]),rvals[q],color=[0,0,0]))
5 loops, best of 3: 779 ms per loop

%%timeit -n5 fig = plt.figure(); ax = plt.gcf().gca()
[ax.add_artist(plt.Circle((xvals[q],yvals[q]),rvals[q],color=[0,0,0])) for q in xrange(4000)]
5 loops, best of 3: 730 ms per loop

答案 3 :(得分:1)

不确定您的确想要做什么,或者您的问题或疑虑是什么,但这是一种完全不同的绘制圆圈的方法...制作一个SVG这样的文件并将其称为{{1 }}

circles.svg

并将其传递给ImageMagick,使其成为<?xml version="1.0" standalone="no"?> <svg width="500" height="300" version="1.1" xmlns="http://www.w3.org/2000/svg"> <circle cx="100" cy="175" r="200" stroke="lime" fill="coral" stroke-width="28"/> <circle cx="25" cy="75" r="80" stroke="red" fill="yellow" stroke-width="5"/> <circle cx="400" cy="280" r="20" stroke="black" fill="blue" stroke-width="10"/> </svg> 文件,如下所示:

PNG

enter image description here