英文:
Matploltib quiver plot: argument order
问题
给定一个二维数组,其中包含方位值(如由高程模型的方位导数表示的罗盘方位),我正在使用matplotlib创建一个箭头图。这个箭头图被放置在一个彩色的方位值矩阵上,以充当检查。
问题: 尽管matplotlib.pyplot.quiver()
期望的参数顺序是quiver([X, Y], U, V, [C], **kw)
,但为什么我的代码只在使用quiver([X, Y], V, U)
(即U和V的顺序相反)时才得到预期的答案?
顺便说一下,在绘图时,我已将plt.imshow
的原点移动到lower
(如这里所讨论)。我认为问题与我的索引等相关。
以下是Python 3.5和matplotlib v3.x的代码:
import numpy as np
import matplotlib.pyplot as plt
def compassBearing_to_standardPosition__degrees_counterClockwise(bearing_deg):
"""Vector magnitude and direction calculations assume angle is relative to the x axis
i.e. 0 degrees north is at 3 o'clock
Adjust compass bearings to be relative to standard position
"""
std_pos = (450 - bearing_deg) % 360
return std_pos
def calculate_U_and_V__vector_magnitude_and_direction(angle_degrees, magnitude=1):
"""Calculates the components of a vector given in magnitude (U) and direction (V) form
angle: Expected that angles are in standard position
i.e. relative to the x axis or where 3 o'clock is zero and not the compass bearing
where 12 o'clock is 0
magnitude: defaults to 1
"""
angle_rad = np.deg2rad(angle_degrees)
x = magnitude * np.cos(angle_rad) # change in x == U
y = magnitude * np.sin(angle_rad) # change in y == V
return x, y
def array_indices(arr, indexing='xy'):
"""Calculates index positions of each cell in array
These can be used to map to e.g. when creating a quiver plot
indexing: Giving the string 'ij' returns a meshgrid with
matrix indexing, while 'xy' returns a meshgrid with Cartesian indexing.
In the 2-D case with inputs of length M and N, the outputs are of shape
(N, M) for 'xy' indexing and (M, N) for 'ij' indexing.
"""
nrows, ncols = arr.shape
nx = 1
ny = 1
x = np.linspace(0, ncols-1, ncols)
y = np.linspace(0, nrows-1, nrows)
xi, yi = np.meshgrid(x, y, indexing=indexing)
return xi, yi
# 创建一个方位角度网格(北方为0度)
aspect_grid = np.array([[216, 226, 151],
[74, 323, 268],
[177, 204, 84]])
# 获取数组索引
x, y = array_indices(aspect_grid, indexing='xy')
# 获取U和V
x_change, y_change = calculate_U_and_V__vector_magnitude_and_direction(aspect_grid.flatten())
# 在imshow上绘制quiver
cmap = 'twilight_shifted' # 这需要matplotlib v3.x
plt.imshow(np.floor(aspect_grid), cmap=cmap, origin='lower')
plt.colorbar(label="Aspect (degrees N)")
plt.quiver(x, y, y_change, x_change, pivot='middle') # <<< 为什么不是x、y、x_change、y_change?
plt.title("Surface aspect values")
plt.show()
英文:
Given a 2D array of aspect values (compass bearings e.g. as represented by the aspect derivative of an elevation model), I'm creating a quiver plot using matplotlib. This is being placed over a coloured matrix of the aspect values to act as a check.
The code is working in that it creates what I want but only where the arguments are opposite to what I expect. I'm making a simple mistake but can't spot it.
QUESTION: Although matplotlib.pyplot.quiver()
expects quiver([X, Y], U, V, [C], **kw)
, why does my code only give the expected answer where quiver([X, Y], V, U)
(i.e. U and V are the other way around) is used?
Incidentally, when plotting, I've shifted the origin of plt.imshow
to lower
(as discussed here). I think the problem lies somewhere related to my indexing etc.
Code below (using python 3.5 and matplotlib v3.x):
import numpy as np
import matplotlib.pyplot as plt
def compassBearing_to_standardPosition__degrees_counterClockwise(bearing_deg):
"""Vector magnitude and direction calculations assume angle is relative to the x axis
i.e. 0 degrees north is at 3 o'clock
Adjust compass bearings to be relative to standard position
"""
std_pos=(450 - bearing_deg) % 360
return(std_pos)
def calculate_U_and_V__vector_magnitude_and_direction(angle_degrees, magnitude=1):
"""Calculates the components of a vector given in magnitude (U) and direction (V) form
angle: Expected that angles are in standard position
i.e. relative to the x axis or where 3 o'clock is zero and not the compass bearing
where 12 o'clock is 0
magnitude: defaults to 1
"""
angle_rad=np.deg2rad(angle_degrees)
x = magnitude * np.cos(angle_rad) # change in x == U
y = magnitude * np.sin(angle_rad) # change in y == V
return(x,y)
def array_indices(arr, indexing='xy'):
"""Calculates index positions of each cell in array
These can be used to map to e.g. when creating a quiver plot
indexing: Giving the string 'ij' returns a meshgrid with
matrix indexing, while 'xy' returns a meshgrid with Cartesian indexing.
In the 2-D case with inputs of length M and N, the outputs are of shape
(N, M) for 'xy' indexing and (M, N) for 'ij' indexing.
"""
nrows, ncols = arr.shape
nx = 1
ny = 1
x = np.linspace(0, ncols-1, ncols)
y = np.linspace(0, nrows-1, nrows)
#y = np.linspace(nrows-1, 0, nrows) # note that the largest vlue is first
xi, yi = np.meshgrid(x, y, indexing=indexing)
return(xi, yi)
#Create a toy aspect grid (degrees North)
aspect_grid=np.array([[ 216, 226, 151],
[ 74, 323, 268],
[ 177, 204, 84]])
#Get the array indices
x,y=array_indices(aspect_grid, indexing='xy')
#Get U and V
x_change,y_change=calculate_U_and_V__vector_magnitude_and_direction(aspect_grid.flatten())
#Plot quiver over imshow
cmap = 'twilight_shifted' # this will expect matplotlib v3.x
plt.imshow(np.floor(aspect_grid), cmap=cmap, origin='lower')
plt.colorbar(label="Aspect (degrees N)")
plt.quiver(x, y, y_change, x_change, pivot='middle') # <<< why not x,y,x_change,y_change?
plt.title("Surface aspect values")
plt.show()
答案1
得分: 1
When you pass your aspect_grid
array into calculate_U_and_V__vector_magnitude_and_direction
, you aren't converting them from absolute bearing to counterclockwise degrees since compassBearing_to_standardPosition__degrees_counterClockwise
is not being called in calculate_U_and_V__vector_magnitude_and_direction
. Due to the 90-degree misalignment of the two conventions, this leads cos(angle)
to correspond to the y
component and sin(angle)
to correspond to the x
component (due to the property cos(x - pi/2) == sin(x)
). In order to correct this, you simply need to use the conversion you have set up (which does correctly convert from bearing to standard position) by doing something like:
#...
angle_degrees = compassBearing_to_standardPosition__degrees_counterClockwise(angle_degrees)
angle_rad = np.deg2rad(angle_degrees)
#...
in calculate_U_and_V__vector_magnitude_and_direction
. This will then allow you to use:
plt.quiver(x, y, x_change, y_change, pivot='middle')
and get the correct result.
英文:
When you pass your aspect_grid
array into calculate_U_and_V__vector_magnitude_and_direction
you aren't converting them from absolute bearing to counterclockwise degrees since compassBearing_to_standardPosition__degrees_counterClockwise
is not being called in calculate_U_and_V__vector_magnitude_and_direction
. Due to the 90-degree misalignment of the two conventions this leads cos(angle)
to correspond to the y
component and sin(angle)
to correspond to the x
component (due to the property cos(x - pi/2) == sin(x)
). In order to correct this you simply need to use the conversion you have set up (which does correctly convert from bearing to standard position) by doing something like
#...
angle_degrees = compassBearing_to_standardPosition__degrees_counterClockwise(angle_degrees)
angle_rad=np.deg2rad(angle_degrees)
#...
in calculate_U_and_V__vector_magnitude_and_direction
. This will then allow you to use
plt.quiver(x, y, x_change, y_change, pivot='middle')
and get the correct result:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论