Matplotlib流线图箭头指向错误方向

5
我正在使用matplotlib生成地下水位等高线和流线图。等高线表明许多区域的海拔正在降低,但是地下水流(流线图)指向上坡。我圈出了似乎指向错误方向的箭头。地图底部朝向的箭头似乎指向正确方向。有人知道可能是什么原因吗?
以下是生成此图的大部分代码:
#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)

数据有多精细?你可能会遇到奇怪的混叠效应。 - tacaswell
@tcaswell 数据看起来像这样 http://cl.ly/image/1S0y2z2p3j0X - Nick Woodhams
那看起来真的很稀疏。 - tacaswell
@tcaswell,我能测试或注入一些数据来修复它吗? - Nick Woodhams
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/31126/discussion-between-nickwoodhams-and-tcaswell - Nick Woodhams
显示剩余3条评论
2个回答

19

摘要

我猜测,你的问题可能是由于内在的转置引起的。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()
结果将如下所示: enter image description here 请注意,有很多地方流线不垂直于等值线。这比箭头朝向错误更容易指示出问题。(尽管“垂直”假定绘图的宽高比为1,但这对这些图而言并不完全正确,除非您进行设置。)
解决问题:
如果我们只是改变了这一行
dx, dy = np.gradient(zi)

收件人:

dy, dx = np.gradient(zi)
我们将得到正确的结果: enter image description here

插值建议

另外,对于这种情况,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()

enter image description here

你会注意到由于绘图的宽高比不相等,交点并不完全垂直。然而,如果我们将绘图的宽高比设置为1,所有交点都是90度。

以下是两种方法的并排比较:

enter image description here


你真是救命稻草。交换 dx 和 dy 修复了箭头。看看之前和之后的效果:http://cl.ly/image/1P3G3j1b0j1b - Nick Woodhams
问题是,当深度为正向上时,为什么需要 dy, dx = np.gradient(-zi) - user2742907

1
您可以使用arrowstyle='->'来指定箭头样式。请尝试这两种方式,看看是否适用于您:
plt.streamplot(xi, yi, dx, dy, color='c', density=1, arrowsize=3, 
               arrowstyle='<-')

plt.streamplot(xi, yi, dx, dy, color='c', density=1, arrowsize=3, 
               arrowstyle='->')

我尝试了这两种方法,看起来箭头仍然指向错误的方向。http://cl.ly/image/2q3U3V0q0L2B - Nick Woodhams
我让它们根据 '<''>' 转向不同的方向。 - Mike Müller
我也是这样认为的,但是底部的箭头指向错误,应该是在顶部的箭头。 - Nick Woodhams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接