在“uv"模式下绘图时获取箭袋箭头(尖端和底部)的坐标 [英] Get coordinates of quiver arrow (tip and bottom) when plotting in 'uv' mode

查看:67
本文介绍了在“uv"模式下绘图时获取箭袋箭头(尖端和底部)的坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做什么

在"uv"模式下进行绘制时,我希望能够获得颤动箭头的坐标,以便重新使用此数据来绘制其他形状(例如椭圆形).

问题

此问题还与

现在,当我切换到"uv"模式(颤抖位置具有不同的单位)时,尽管我尝试使用缩放因子,但无法重现相同的图.下面的代码给了我这个结果:

#------------------------------------# 'uv' 图(变量已在前面定义)#颤动和椭圆图的比例因子scalefac = 2posx1 = np.array(-12.633)posy1 = np.array(57.533)# 阴谋图, ax = plt.subplots(figsize=(8, 8))plt.scatter(posx1,posy1,color='blue')Qv = ax.quiver(posx1,posy1,meanx * scalefac,meany * scalefac,scale = 1,scale_units ='width',颜色='黑色')# 基本椭圆定义椭圆=椭圆((0,0),宽度=ell_radius_x * 2,高度=ell_radius_y * 2,facecolor='无',edgecolor ='红色')#根据外部参数对椭圆进行变换(从各种数据统计中获得)center =(平均值* scalefac + posx1,平均值* scalefac + posy1)transf = transforms.Affine2D()\.rotate_deg(45) \.scale(scale_x * scalefac,scale_y * scalefac)\.translate(* center)ellipse.set_transform(transf + ax.transData)#椭圆图ax.plot(* center,'x',color ='g',markersize = 12)ax.add_patch(椭圆)

Qv._paths 不会返回易于理解的变量:

  print(Qv._paths)[Path(array([[0.00357682,-0.00112643],[-0.03897025,-0.13622912],[-0.03069018, -0.13490515],[-0.05268492, -0.1672941 ],[-0.05215112,-0.12814659],[-0.0461239 , -0.13397627],[-0.00357682, 0.00112643],[ 0.00357682, -0.00112643]]), 无)]

我猜我需要的缩放信息在 Qv._paths 中的某个位置,但是我不清楚该在哪里.想法是要有一个健壮的方法,以便我可以更改与变量 scalefac 相关的缩放比例.有什么建议吗?

解决方案

再看一下文档后,我突然发现了该文档.让我绘制一个虚拟示例,以便于理解.

  fig,ax = plt.subplots(figsize =(8,8))plt.xlim(-12.8,-12.6)plt.ylim(57.2,57.6)x1, y1 = -12.633, 57.533x2,y2 = -12.7,57.4角度= np.arctan((y2-y1)/(x2-x1))D = np.sqrt((x2-x1)** 2 +(y2-y1)** 2)U,V = D * np.cos(角度),D * np.sin(角度)ax.scatter(x2, y2, 标记='x', s=100, color='k')Qv1 = ax.quiver(x1,y1,-U,-V,angles ='uv',scale = 1,scale_units ='xy',color ='black')Qv2 = ax.quiver(x1, y1, -U, -V,angle='xy', scale=1, scale_units='xy', color='red')

考虑(x2,y2)类似于假设椭圆的中心.我们可以使用简单的矢量数学来计算角度和U,V分量.绘制上面给出:

注意 uv 角度的颤动是如何偏离的,与问题中的示例相同.但是,如果您阅读 matplotlib 文档中的文档,它会说:

<块引用>

'uv':箭头轴的长宽比为1,因此,如果U == V,则图中箭头的方向与水平轴逆时针成45度(向右).

在 uv 模式下,箭头的轴独立于 x,y 轴,并且该轴的纵横比为 1.所以很自然地,如果您的绘图的纵横比为 1,箭头应该完美匹配!

  plt.xlim(-12.8,-12.4)plt.ylim(57.2,57.6)

在此xlim和ylim设置下,如果我运行以前的虚拟图,我们将得到:

回到您的示例,您需要将scale_units更改为"xy",并简单地设置纵横比为1的xlim,ylim.

#-------------------------------------# 'uv' 图(变量已在前面定义)# 箭袋和椭圆图的比例因子scalefac = 2posx1 = np.array(-12.633)posy1 = np.array(57.533)# 阴谋图, ax = plt.subplots(figsize=(8, 8))plt.scatter(posx1,posy1,color='blue')Qv = ax.quiver(posx1,posy1,meanx * scalefac,meany * scalefac,角度='uv',比例=1,比例单位='xy',颜色='黑色')#基本椭圆定义椭圆=椭圆((0,0),宽度= ell_radius_x * 2身高= ell_radius_y * 2facecolor='无',edgecolor ='红色')#根据外部参数对椭圆进行变换(从各种数据统计中获得)中心=(meanx*scalefac + posx1,meany*scalefac + posy1)transf = transforms.Affine2D() \.rotate_deg(45)\.scale(scale_x*scalefac, scale_y*scalefac) \.translate(* center)ellipse.set_transform(transf + ax.transData)#椭圆图ax.plot(*center,'x',color='g',markersize=12)ax.add_patch(椭圆)plt.xlim(-13,-12.5)plt.ylim(57.1, 57.6)

也许应该在 matplotlib 文档中添加额外的警告或注释,因为我认为这乍一看并不明显.

What I am trying to do

I would like to be able to get the coordinate of the quiver arrow when plotting in 'uv' mode in order to re-use this data to plot other shapes (e.g. ellipse).

The problem

This issue is also related to this post. In this post, the answers mention using the ._paths quiver variable to get the coordinate of the arrow. However, there are no indications about how to do it.

Does someone have a solution to access the coordinates associated with the top and bottom of the arrow in a ‘uv’ plotting mode? There are plenty of variables in q._paths and I cannot see which one is relevant.

Code for reproduction

The code below work perfectly fine in 'xy' mode:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from matplotlib.patches import Ellipse
import matplotlib.transforms as transforms

#-------------------------------------
# Variable definition
colsec = 'royalblue'
colvec = 'salmon'
colellipse = 'limegreen'
x = np.array([ 0.00789308, -0.0773587 ,  0.03353797, -0.06185714, -0.13095092,
        0.03280368,  0.04775701, -0.08124051, -0.02894444, -0.02834356,
       -0.1457362 , -0.00628834,  0.09627607])
y = np.array([-0.03668553,  0.05931522, -0.04041772, -0.00866234, -0.00539877,
       -0.14787117, -0.21553271, -0.15741139, -0.1417963 , -0.00887117,
        0.02207362, -0.11979755, -0.28635583])
meanx = np.mean(x)
meany = np.mean(y)

# ellipse parameter
ell_radius_x = 0.54
ell_radius_y = 1.30
scale_x = 0.07
scale_y = 0.1

#-------------------------------------
# 'xy' plot

posx1 = 0
posy1 = 0
    
# Plot
fig, ax = plt.subplots(figsize=(8, 8))
plt.scatter(x,y,color='blue')

# Quiver plot
Qv = ax.quiver(posx1, posy1, meanx,  meany,
              angles='xy', scale_units='xy', scale=1,
              color='black')

# Basic ellipse definition
ellipse = Ellipse((0, 0),
        width=ell_radius_x * 2,
        height=ell_radius_y * 2,
        facecolor='none',
        edgecolor='red')

center=(meanx + posx1, meany + posy1)

# Transformation of the ellipse according to external parameters (obtained from various statistics on the data)
transf = transforms.Affine2D() \
        .rotate_deg(45) \
        .scale(scale_x, scale_y) \
        .translate(*center)
ellipse.set_transform(transf + ax.transData)
    
# Plot of the ellipse
ax.plot(*center,'x',color='g',markersize=12)    
    
ax.add_patch(ellipse)

We got the expected outcome:

Now when I switch to 'uv' mode (my quiver position has a different unit), I cannot reproduce the same plot, although I tried playing with scaling factor. The code below gives me this outcome:

#-------------------------------------
# 'uv' plot (variables are defined previously)

# Scale factor for quiver and ellipse plot
scalefac = 2

posx1 = np.array(-12.633)
posy1 = np.array(57.533)

# Plot
fig, ax = plt.subplots(figsize=(8, 8))
plt.scatter(posx1,posy1,color='blue')

Qv = ax.quiver(posx1, posy1, meanx*scalefac,  meany*scalefac,
              scale=1, scale_units='width',
              color='black')

# Basic ellipse definition
ellipse = Ellipse((0, 0),
        width=ell_radius_x * 2,
        height=ell_radius_y * 2,
        facecolor='none',
        edgecolor='red')

# Transformation of the ellipse according to external parameters (obtained from various statistics on the data)
center=(meanx*scalefac + posx1, meany*scalefac + posy1)
transf = transforms.Affine2D() \
        .rotate_deg(45) \
        .scale(scale_x*scalefac, scale_y*scalefac) \
        .translate(*center)
ellipse.set_transform(transf + ax.transData)
    
# Plot of the ellipse
ax.plot(*center,'x',color='g',markersize=12)    
    
ax.add_patch(ellipse)

Qv._paths doesn't return a variable easy to understand:

print(Qv._paths)
[Path(array([[ 0.00357682, -0.00112643],
       [-0.03897025, -0.13622912],
       [-0.03069018, -0.13490515],
       [-0.05268492, -0.1672941 ],
       [-0.05215112, -0.12814659],
       [-0.0461239 , -0.13397627],
       [-0.00357682,  0.00112643],
       [ 0.00357682, -0.00112643]]), None)]

I guess the scaling information I need is somewhere in Qv._paths but it is not clear to me where. The idea would be to have a robust method so I could change the scaling associated with my variable scalefac. Any suggestions?

解决方案

After taking another look at the doc, I suddenly figured it out. Let me plot a dummy example, for easier understanding.

fig, ax = plt.subplots(figsize=(8, 8))
plt.xlim(-12.8,-12.6)
plt.ylim(57.2,57.6)

x1, y1 = -12.633, 57.533
x2, y2 = -12.7, 57.4
angle = np.arctan((y2-y1)/(x2-x1))
D = np.sqrt((x2-x1)**2 + (y2-y1)**2)
U, V = D*np.cos(angle), D*np.sin(angle)
ax.scatter(x2, y2, marker='x', s=100, color='k')
Qv1 = ax.quiver(x1, y1, -U, -V, angles='uv', scale=1, scale_units='xy', color='black')
Qv2 = ax.quiver(x1, y1, -U, -V, angles='xy', scale=1, scale_units='xy', color='red')

Consider (x2, y2) analogous to the center of a hypothetical ellipse. We can calculate the angle and the U, V components with simple vector math. Plotting the above gives:

Note how the quiver in uv angles is off by just a bit, same as the example in the question. However, if you read the documentation in matplotlib's docs, it says:

'uv': The arrow axis aspect ratio is 1 so that if U == V the orientation of the arrow on the plot is 45 degrees counter-clockwise from the horizontal axis (positive to the right).

The arrow's axis is independent of the x,y axis in uv mode, and this axis has an aspect ratio of 1. So naturally, if your plot has an aspect ratio of 1, the arrow should match perfectly!

plt.xlim(-12.8,-12.4)
plt.ylim(57.2,57.6)

Under this xlim and ylim setting, if I run my previous dummy plot, we'd get:

Going back to your example, you need to change scale_units to 'xy' and simply set an xlim, ylim with an aspect ratio of 1.

#-------------------------------------
# 'uv' plot (variables are defined previously)

# Scale factor for quiver and ellipse plot
scalefac = 2

posx1 = np.array(-12.633)
posy1 = np.array(57.533)

# Plot
fig, ax = plt.subplots(figsize=(8, 8))
plt.scatter(posx1,posy1,color='blue')

Qv = ax.quiver(posx1, posy1, meanx*scalefac,  meany*scalefac,
              angles='uv', scale=1, scale_units='xy',
              color='black')

# Basic ellipse definition
ellipse = Ellipse((0, 0),
        width=ell_radius_x * 2,
        height=ell_radius_y * 2,
        facecolor='none',
        edgecolor='red')

# Transformation of the ellipse according to external parameters (obtained from various statistics on the data)
center=(meanx*scalefac + posx1, meany*scalefac + posy1)
transf = transforms.Affine2D() \
        .rotate_deg(45) \
        .scale(scale_x*scalefac, scale_y*scalefac) \
        .translate(*center)
ellipse.set_transform(transf + ax.transData)
    
# Plot of the ellipse
ax.plot(*center,'x',color='g',markersize=12)    
    
ax.add_patch(ellipse)
plt.xlim(-13,-12.5)
plt.ylim(57.1, 57.6)

Maybe an additional warning or note should be added in the matplotlib docs, because I think this isn't really obvious at first glance.

这篇关于在“uv"模式下绘图时获取箭袋箭头(尖端和底部)的坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆