我正在matplotlib中生成地下水高程等值线和流图
轮廓线表明,许多地区的海拔高度都在降低,但地下水流(水流图)却指向上坡。我已经圈了圈箭头,这些箭头似乎指向了错误的方向。
指向 map 底部的箭头似乎指向正确的方向。有谁知道为什么会这样吗?
这是生成此绘图的大多数代码:
#create empty arrays to fill up!
x_values = []
y_values = []
z_values = []
#iterate over wells and fill the arrays with well data
for well in well_arr:
x_values.append(well['xpos'])
y_values.append(well['ypos'])
z_values.append(well['value'])
#initialize numpy array as required for interpolation functions
x = np.array(x_values, dtype=np.float)
y = np.array(y_values, dtype=np.float)
z = np.array(z_values, dtype=np.float)
#create a list of x, y coordinate tuples
points = zip(x, y)
#create a grid on which to interpolate data
xi, yi = np.linspace(0, image['width'], image['width']),
np.linspace(0, image['height'], image['height'])
xi, yi = np.meshgrid(xi, yi)
#interpolate the data with the matlab griddata function
zi = griddata(x, y, z, xi, yi, interp='nn')
#create a matplotlib figure and adjust the width and heights
fig = plt.figure(figsize=(image['width']/72, image['height']/72))
#create a single subplot, just takes over the whole figure if only one is specified
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
#create the contours
kwargs = {}
if groundwater_contours:
kwargs['colors'] = 'b'
CS = plt.contour(xi, yi, zi, linewidths=linewidth, **kwargs)
#add a streamplot
dx, dy = np.gradient(zi)
plt.streamplot(xi, yi, dx, dy, color='c', density=1, arrowsize=3)
最佳答案
概括
我正在猜测,但是您的问题可能是因为您正在进行内在的移调。 2D numpy数组索引为行,列。 “x,y”索引是列,行。在这种情况下,numpy.gradient
基本上将返回dy,dx而不是dx,dy。
尝试更改行:
dx, dy = np.gradient(zi)
至:
dy, dx = np.gradient(zi)
另外,如果您将深度定义为向上,则应为:
dy, dx = np.gradient(-zi)
但是,我假设您具有从下至上的深度约定,因此我将在下面的示例中保留该部分。 (因此,在下面的示例数据中,较高的值被假定为较高/较低,并且水将流向较高的值。)
重现问题
例如,如果我们修改您提供的代码以使用随机数据并填写一些来自代码示例范围之外的变量(因此这是一个独立的示例):
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
# Generate some reproducible but random data
np.random.seed(1981)
width, height = 200, 300
x, y, z = np.random.random((3,10))
x *= width
y *= height
#create a list of x, y coordinate tuples
points = zip(x, y)
#create a grid on which to interpolate data
xi, yi = np.linspace(0, width, width), np.linspace(0, height, height)
xi, yi = np.meshgrid(xi, yi)
#interpolate the data with the matlab griddata function
zi = griddata(x, y, z, xi, yi, interp='nn')
#create a matplotlib figure and adjust the width and heights
fig = plt.figure()
#create a single subplot, just takes over the whole figure if only one is specified
ax = fig.add_subplot(111, frameon=False, xticks=[], yticks=[])
#create the contours
CS = plt.contour(xi, yi, zi, linewidths=1, colors='b')
#add a streamplot
dx, dy = np.gradient(zi)
plt.streamplot(xi, yi, dx, dy, color='c', density=1, arrowsize=3)
plt.show()
结果将如下所示:
请注意,在很多地方流线不垂直于轮廓。这比错误的箭头方向更容易指示。 (尽管“垂直”假定该图的宽高比为1,但除非您进行设置,否则对于这些图来说并不是完全正确的。)
解决问题
如果我们只是换行
dx, dy = np.gradient(zi)
至:
dy, dx = np.gradient(zi)
我们会得到正确的结果:
插值建议
另外,在这种情况下,
griddata
是一个糟糕的选择。首先,它不是“平滑”插值方法。它使用delaunay三角剖分法,在三角形边界处形成“尖锐”的山脊。这会导致这些位置出现异常梯度。
其次,它将插值限制为数据点的凸包,这可能是一个好选择,也可能不是一个好选择。
径向基函数(或任何其他平滑插值)是插值的更好选择。
例如,如果我们修改您的代码段以使用RBF:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import Rbf
# Generate data
np.random.seed(1981)
width, height = 200, 300
x, y, z = np.random.random((3,10))
x *= width
y *= height
#create a grid on which to interpolate data
xi, yi = np.mgrid[0:width:1j*width, 0:height:1j*height]
#interpolate the data with the matlab griddata function
interp = Rbf(x, y, z, function='linear')
zi = interp(xi, yi)
#create a matplotlib figure and adjust the width and heights
fig, ax = plt.subplots(subplot_kw=dict(frameon=False, xticks=[], yticks=[]))
#create the contours and streamplot
CS = plt.contour(xi, yi, zi, linewidths=1, colors='b')
dy, dx = np.gradient(zi.T)
plt.streamplot(xi[:,0], yi[0,:], dx, dy, color='c', density=1, arrowsize=3)
plt.show()
(由于图的纵横比不相等,您会注意到相交点不太垂直。但是,如果将图的纵横比设置为1,则它们都是90度。)
作为两种方法的并排比较:
关于python - Matplotlib streamplot箭头指向错误的方向,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16897585/