I have some Python code that plots a large number of non-regular polygons using matplotlib from some ocean model data.
I do this by creating 4 numpy arrays of shape (N,2) defining the corners of each patch, where N is a large number (say 500,000)
I then create matplotlib Patch object for each set of corners and add it to a list. Finally, I create a matplotlib PatchCollection object from the list of Patches.
The problem is that the Patch generation is slow because it is in a for loop. I've been trying to think of a way to speed this up with numpy broadcasting, but can't quite crack it.
Here's some example code, with a small test dataset (which is obviously fast to run).
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)
Is there a way I can speed this up?
What about to create collection by matplolib.collections
instead of creating every polygon (or patch)?
Look at the examples here: http://matplotlib.org/examples/api/collections_demo.html
And read matplotlib documentation: http://matplotlib.org/api/collections_api.html?highlight=polycollection#matplotlib.collections.PolyCollection
This example code add 200,000 polygons for ~10s:
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With