matplotlib:创建大量Patch对象的有效方法

时间:2016-06-01 15:46:02

标签: python numpy matplotlib

我有一些Python代码,它使用来自某些海洋模型数据的matplotlib绘制了大量非正规多边形。

我这样做是通过创建4个numpy形状的阵列(N,2)来定义每个补丁的角落,其中N是一个大数字(比如500,000)

然后我为每组角创建matplotlib Patch对象并将其添加到列表中。最后,我从Patches列表中创建了一个matplotlib PatchCollection对象。

问题是补丁生成很慢,因为它处于for循环中。我一直试图想出一种通过numpy广播来加快速度的方法,但不能完全破解它。

这是一些示例代码,带有一个小的测试数据集(显然可以快速运行)。

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


# Cell lat/lon centers:
lons = np.array([ 323.811,  323.854,  323.811,  323.723, 324.162,  324.206,  323.723,  324.162, 323.635,  323.679])
lats = np.array([-54.887, -54.887, -54.858, -54.829, -54.829, -54.829, -54.799, -54.799, -54.770, -54.770])

# Cell size scaling factors:
cx = np.array([1,1,1,2,2,2,4,1,2,1]) 
cy = np.array([1,1,1,1,2,2,2,1,2,1])

# Smallest cell sizes:
min_dlon = 0.0439453  
min_dlat = 0.0292969 

# Calculate cell sizes based on cell scaling factor and smallest cell size
dlon = cx * min_dlon
dlat = cy * min_dlat

# calculate cell extnets....
x1 = lons - 0.5 * dlon
x2 = lons + 0.5 * dlon
y1 = lats - 0.5 * dlat
y2 = lats + 0.5 * dlat

# ... and corners
c1 = np.array([x1,y1]).T
c2 = np.array([x2,y1]).T
c3 = np.array([x2,y2]).T
c4 = np.array([x1,y2]).T

# Now loop over cells and create Patch objects from the cell corners.
# This is the bottleneck as it using a slow Python loop instead of 
# fast numpy broadcasting. How can I speed this up?
ncel = np.alen(lons)
patches = []
for i in np.arange(ncel):
    verts = np.vstack([c1[i], c2[i], c3[i], c4[i]])
    p = plt.Polygon(verts)
    patches.append(p)

# Create patch collection from list of Patches
p = PatchCollection(patches, match_original=True)

有没有办法可以加快速度呢?

2 个答案:

答案 0 :(得分:3)

如何通过matplolib.collections创建集合而不是创建每个多边形(或补丁)? 请看这里的示例:http://matplotlib.org/examples/api/collections_demo.html

阅读matplotlib文档:http://matplotlib.org/api/collections_api.html?highlight=polycollection#matplotlib.collections.PolyCollection

此示例代码为~10s添加200,000个多边形:

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

npol, nvrts = 200000, 5
cnts = 100 * (np.random.random((npol,2)) - 0.5)
offs = 10 * (np.random.random((nvrts,npol,2)) - 0.5)
vrts = cnts + offs
vrts = np.swapaxes(vrts, 0, 1)
z = np.random.random(npol) * 500

fig, ax = plt.subplots()
coll = PolyCollection(vrts, array=z, cmap=matplotlib.cm.jet)
ax.add_collection(coll)
ax.autoscale()
plt.show()

enter image description here

答案 1 :(得分:1)

也可以使用

创建

patches

cc=np.stack((c1,c2,c3,c4),1)
patches = [plt.Polygon(verts) for verts in cc]

这仍然涉及一个循环,但是将堆栈移出循环(np.stack是新函数;如果版本没有它,我可以重写它。)

我不知道这是否会节省很多时间。