问题
How to build a Contour plot (specifically, topographic map) based on a Scatter plot, so that every scatter dot is converted into a circular area being the highest one in a given radius, i.e., any adjoining area is lower than the original dot’s area?
On the exemplary image, the yellow adjoining area is lower than the highland #6. Note, I am not trying to build a data density plot.
All input scatter dots are higher than the green grass level.
I tried to interpolate the x, y, and z coordinates using matplotlib’s griddata as proposed in question Make contour of scatter. On the second figure you see the original superimposed scatter plot and contour plot generated after interpolation. However, the dot #6 is not the highest one like it is on the first image, and the snow-capped mountain is shifted from the original white dot #1.
Here are my coordinates:
x = [34, 74, 34, 70, 4, 42, 10, 56, 50, 0, 15, 104, 53, 27]
y = [44, 52, 21, 25, 34, 54, 70, 77, 0, 50, 5, 53, 18, 86]
z = [0.9, 0.8, 0.8, 0.8, 0.7, 0.7, 0.7, 0.7, 0.7, 0.6, 0.6, 0.6, 0.6, 0.6]
Any ideas are highly appreciated.
回答1:
I use bivariate_normal
function to get elevation for each point. Here is the working code to try:
import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
# data
x = np.array([34, 74, 34, 70, 4, 42, 10, 56, 50, 0, 15, 104, 53, 27])
y = np.array([44, 52, 21, 25, 34, 54, 70, 77, 0, 50, 5, 53, 18, 86])
z = np.array([0.9, 0.8, 0.8, 0.9, 0.7, 0.7, 0.7, 0.7, 0.7, 0.6, 0.6, 0.6, 0.6, 0.6])
# the radius that needs to specified for each point
# radius = sigmax=sigmay for bivariate_normal
#rad = [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7] # OK
rad = [4, 6, 7, 3, 5, 5, 7, 6, 6, 7, 6, 7, 6, 7] # better
# get limits of plot
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
# some settings
delta = 0.5
# create mesh grid for plotting area
xs = np.arange(xmin-delta, xmax+delta*2, delta)
ys = np.arange(ymin-delta, ymax+delta*2, delta)
XX, YY = np.meshgrid(xs, ys)
# compute elevation Z for each point in the grid mesh
ZZ=0
for mx, my, mz, mr in zip(x, y, z, rad):
sigmax = mr
sigmay = mr
vm = mlab.bivariate_normal(0, 0, sigmax, sigmay, 0, 0) # max value
# mz and vm are used to correct the elevation obtained from bivar-normal
ZZ += mlab.bivariate_normal(XX, YY, sigmax, sigmay, mx, my) * mz / vm
# prep fig, ax
fig = plt.figure(figsize=(9, 9))
ax = fig.add_subplot(111)
# choose cmap as you need
ctf=plt.contourf(XX, YY, ZZ, linewidth=1, cmap=cm.gist_earth_r)
plt.scatter(x, y, s=rad, color='r', zorder=10)
plt.xlim(xmin-delta, xmax+delta)
plt.ylim(ymin-delta, ymax+delta)
plt.colorbar(ctf)
plt.show()
The resulting plot:
来源:https://stackoverflow.com/questions/47275712/convert-scatter-to-contour-every-dot-turns-into-a-highland