Matplotlib streamplot箭头指向错误的方式

时间:2013-06-03 13:13:07

标签: python matplotlib contour

我在matplotlib中生成地下水高程轮廓和streamplot

轮廓表明许多地区的海拔正在下降,但地下水流(streamplot)指向上坡。我已经盘旋了似乎指向错误方向的箭头。

指向地图底部的箭头似乎指向正确的方向。有谁知道为什么会这样?

enter image description here

以下是生成此图的大部分代码:

#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)

2 个答案:

答案 0 :(得分:18)

摘要

我猜,但你的问题可能是因为你有一个固有的转置。 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

答案 1 :(得分: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='->')