Draw polygons more efficiently with matplotlib
-
07-07-2021 - |
Pregunta
I have a dateset of around 60000 shapes (with lat/lon coordinates of each corner) which I want to draw on a map using matplotlib and basemap.
This is the way I am doing it at the moment:
for ii in range(len(data)):
lons = np.array([data['lon1'][ii],data['lon3'][ii],data['lon4'][ii],data['lon2'][ii]],'f2')
lats = np.array([data['lat1'][ii],data['lat3'][ii],data['lat4'][ii],data['lat2'][ii]],'f2')
x,y = m(lons,lats)
poly = Polygon(zip(x,y),facecolor=colorval[ii],edgecolor='none')
plt.gca().add_patch(poly)
However, this takes around 1.5 minutes on my machine and I was thinking whether it is possible to speed things up a little. Is there a more efficient way to draw polygons and add them to the map?
Solución
You could consider creating Collections of polygons instead of individual polygons.
The relevant docs can be found here: http://matplotlib.org/api/collections_api.html With a example worth picking appart here: http://matplotlib.org/examples/api/collections_demo.html
As an example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
import matplotlib as mpl
# Generate data. In this case, we'll make a bunch of center-points and generate
# verticies by subtracting random offsets from those center-points
numpoly, numverts = 100, 4
centers = 100 * (np.random.random((numpoly,2)) - 0.5)
offsets = 10 * (np.random.random((numverts,numpoly,2)) - 0.5)
verts = centers + offsets
verts = np.swapaxes(verts, 0, 1)
# In your case, "verts" might be something like:
# verts = zip(zip(lon1, lat1), zip(lon2, lat2), ...)
# If "data" in your case is a numpy array, there are cleaner ways to reorder
# things to suit.
# Color scalar...
# If you have rgb values in your "colorval" array, you could just pass them
# in as "facecolors=colorval" when you create the PolyCollection
z = np.random.random(numpoly) * 500
fig, ax = plt.subplots()
# Make the collection and add it to the plot.
coll = PolyCollection(verts, array=z, cmap=mpl.cm.jet, edgecolors='none')
ax.add_collection(coll)
ax.autoscale_view()
# Add a colorbar for the PolyCollection
fig.colorbar(coll, ax=ax)
plt.show()
HTH,
Otros consejos
I adjusted my code and now it is working flawlessly :)
Here is the working example:
lons = np.array([data['lon1'],data['lon3'],data['lon4'],data['lon2']])
lats = np.array([data['lat1'],data['lat3'],data['lat4'],data['lat2']])
x,y = m(lons,lats)
pols = zip(x,y)
pols = np.swapaxes(pols,0,2)
pols = np.swapaxes(pols,1,2)
coll = PolyCollection(pols,facecolor=colorval,cmap=jet,edgecolor='none',zorder=2)
plt.gca().add_collection(coll)