I have a list of coordinates:
y,x
445.92,483.156
78.273,321.512
417.311,204.304
62.047,235.216
87.24,532.1
150.863,378.184
79.981,474.14
258.894,87.74
56.496,222.336
85.105,454.176
80.408,411.672
90.656,433.568
378.027,441.296
433.964,290.6
453.606,317.648
383.578,115.432
128.232,312.496
116.276,93.536
94.072,222.336
52.226,327.308
321.663,187.56
392.972,279.008
I would like to plot a density map (or heat map) based on these points, using matplotlib. I am using pcolormesh and contourf. My problem is that pcolormesh is not having same size of the pitch:
This is the code:
x, y = np.genfromtxt('pogba_t1314.csv', delimiter=',', unpack=True)
#print(x[1], y[1])
y = y[np.logical_not(np.isnan(y))]
x = x[np.logical_not(np.isnan(x))]
k = gaussian_kde(np.vstack([x, y]))
xi, yi = np.mgrid[x.min():x.max():x.size**0.5*1j,y.min():y.max():y.size**0.5*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
fig = plt.figure(figsize=(9,10))
ax1 = fig.add_subplot(211)
ax1.pcolormesh(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax1.plot(y,x, "o")
ax1.set_xlim(0, 740)
ax1.set_ylim(515, 0)
#overlay soccer field
im = plt.imread('statszone_football_pitch.png')
ax1.imshow(im, extent=[0, 740, 0, 515], aspect='auto')
fig.savefig('pogba1516.png')
Here it is a link for the csv file: https://dl.dropboxusercontent.com/u/12348226/pogba_t1314.csv
One common map type for this is a density map, also called a heatmap. Tableau creates density maps by grouping overlaying marks and color-coding them based on the number of marks in the group. Density maps help you identify locations with greater or fewer numbers of data points.
What is a heatmap? A heatmap is a two-dimensional graphical representation of data where the individual values that are contained in a matrix are represented as colours. The Seaborn package allows the creation of annotated heatmaps which can be tweaked using Matplotlib tools as per the creator's requirement.
This will hopefully get you started on the right track, but I would definitely recommend reading the docs for pcolor
and pcolormesh
.
You have commented # Plot the density map using nearest-neighbor interpolation
, but since Z
is a 1D array, you don't have any 2D density data for a density map. Density maps are most easily created through the use of np.histogram2d
as I'll show below using your data.
Z, xedges, yedges = np.histogram2d(x, y)
Z
is now a 2D array that has information about the distribution of your x, y coordinates. This distribution can be plotted with pcolormesh
like so
plt.pcolormesh(xedges, yedges, Z.T)
Sort of a ways to go before you obtain an image like the one you posted, but it should explain your error and help get you on the right track.
Update: For nicer, smoother density maps
Assuming you have two 1D arrays, x
and y
you can use a kernel density estimate to obtain much nicer heatmaps in the following way [reference],
from scipy.stats.kde import gaussian_kde
k = gaussian_kde(np.vstack([x, y]))
xi, yi = np.mgrid[x.min():x.max():x.size**0.5*1j,y.min():y.max():y.size**0.5*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
Now you can plot the Gaussian KDE with either pcolormesh
or contourf
depending on what kind of effect/aesthetics you're after
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(7,8))
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
# alpha=0.5 will make the plots semitransparent
ax1.pcolormesh(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax2.contourf(xi, yi, zi.reshape(xi.shape), alpha=0.5)
ax1.set_xlim(x.min(), x.max())
ax1.set_ylim(y.min(), y.max())
ax2.set_xlim(x.min(), x.max())
ax2.set_ylim(y.min(), y.max())
# you can also overlay your soccer field
im = plt.imread('soccerPitch.jpg')
ax1.imshow(im, extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
ax2.imshow(im, extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
I get this image:
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