【问题标题】:How to plot 2d vectors with matplotlib automatically setting axes?如何使用 matplotlib 自动设置轴绘制二维向量?
【发布时间】:2019-12-29 14:25:35
【问题描述】:

我几乎写了一个绘制向量的代码:

a = [2,-1]
b = [1,2]
d = [5,2]

def plot_vectors(**kwargs):
  M = []
  for key, value in kwargs.items():
    M.append(list([key]) + list(value))

  ax = plt.axes()
  ax.grid(b=True, which='major')

  for i in range(len(M)):
    l = 0

    for j in range(1, len(M[i])):
      l += M[i][j]**2

    l = l**0.5
    ax.text(M[i][1]/2, M[i][2]/2, f"{M[i][0]}={l:.2f}", size=14)
    ax.plot([0,M[i][1]], [0,M[i][2]])

  ax.set_aspect('equal', 'box')

plot_vectors(a=a, b=b, d=d)

主要思想不是直接设置ax.set_xlim,而是使用ax.set_aspect('equal', 'box')自动设置。我没有找到如何使用ax.quiverax.arrow。任何人都可以建议如何在此处绘制箭头并将 y 轴值修改为如下所示:

我修改了代码以支持2D numpy数组:

a = [2,-1]
b = [1,2]
d = [5,2]

def plot_vectors(**kwargs):
  M = []
  for key, value in kwargs.items():
    if isinstance(value, np.ndarray):
      value = value.tolist()

    for i, v in enumerate(value):
      if isinstance(v, np.ndarray):
        value[i] = value[i].tolist()

    if not isinstance(value[0], list):
      value = [[0,0], value]

    M.append([key] + value)

  ax = plt.axes()
  ax.grid(b=True, which='major')

  for i in range(len(M)):
    l = 0; pos = []
    for j in range(0, len(M[i][1])):
      pos.append(M[i][2][j] - M[i][1][j])
      l += (pos[j])**2
      pos[j] = pos[j] / 2 + M[i][1][j]

    l = l**0.5
    ax.plot([M[i][1][0], M[i][2][0]], [M[i][1][1], M[i][2][1]])
    ax.text(pos[0], pos[1], f"{M[i][0]}={l:.2f}", size=14)

  ax.set_aspect('equal', 'box')

plot_vectors(a=np.array(a), b=b, d=d, e=[d,np.array(b)])

我对@9​​87654338@的尝试:

a = [2,-1]
b = [1,2]
d = [5,2]

def plot_vectors(**kwargs):
  M = []
  for key, value in kwargs.items():
    if isinstance(value, np.ndarray):
      value = value.tolist()

    for i, v in enumerate(value):
      if isinstance(v, np.ndarray):
        value[i] = value[i].tolist()

    if not isinstance(value[0], list):
      value = [[0,0], value]
    M.append([key] + value)

  ax = plt.axes()
  ax.grid(b=True, which='major')
  print(M)
  for i in range(len(M)):
    l = 0; pos = []
    for j in range(0, len(M[i][1])):
      pos.append(M[i][2][j] - M[i][1][j])
      l += (pos[j])**2
      pos[j] = pos[j] / 2 + M[i][1][j]
    l = l**0.5
    ax.text(pos[0], pos[1], f"{M[i][0]}={l:.2f}", size=14)

  x, y, u, v = zip(*[(i[1][0], i[1][1], i[2][0], i[2][1]) for i in M])
  print(x, y, u, v)
  ax.quiver(x, y, u, v, scale=1)
  ax.set_aspect('equal', 'box')

plot_vectors(a=np.array(a), b=b, d=d, e=[d,np.array(b)])

返回:

[['a', [0, 0], [2, -1]], ['b', [0, 0], [1, 2]], ['d', [0, 0], [5, 2]],
['e', [5, 2], [1, 2]]]
(0, 0, 0, 5) (0, 0, 0, 2) (2, 1, 5, 1) (-1, 2, 2, 2)

问题:

  1. 矢量e 未绘制。
  2. 如何为每个新向量分配视觉上不同的随机颜色?
  3. 矢量a 的一部分未绘制。
  4. 如何从y 轴中删除十进制值?

在@ImportanceOfBeingErnest 的大力帮助下,我终于做了我想做的事:

import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
import numpy as np

a = [2,-1]
b = [1,2]
d = [5,2]

def plot_vectors(**kwargs):
  M = []
  for key, value in kwargs.items():
    if isinstance(value, np.ndarray):
      value = value.tolist()

    for i, v in enumerate(value):
      if isinstance(v, np.ndarray):
        value[i] = value[i].tolist()

    if not isinstance(value[0], list):
      value = [[0,0], value]

    M.append([key] + value)

  plt.figure(figsize=(12,12))
  ax = plt.axes()
  ax.grid(b=True, which='major')
  ax.xaxis.set_major_locator(MaxNLocator(integer=True)); ax.yaxis.set_major_locator(MaxNLocator(integer=True))
  ax.set_aspect('equal', 'box')
  cmap = plt.get_cmap('nipy_spectral')
  lc = np.linspace(0.03, 0.99, 20)
  colors = cmap(np.insert(lc[::2], range(10), lc[::-2]))

  for i in range(len(M)):
    l = 0; pos = []

    for j in range(0, len(M[i][1])):
      pos.append(M[i][2][j] - M[i][1][j])
      l += (pos[j])**2
      pos[j] = pos[j] / 2 + M[i][1][j]

    l = l**0.5
    ax.text(pos[0], pos[1], f'{M[i][0]}={l:.2f}', size=18)

  x, y, u, v = zip(*[(i[1][0], i[1][1], i[2][0] - i[1][0], i[2][1] - i[1][1]) for i in M])
  ax.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=1., color=colors[:len(M)])
  ax.plot(np.array(x)+np.array(u), np.array(y)+np.array(v), np.array(x), np.array(y), visible=False)

plot_vectors(a=np.array(a), b=b, d=d, e=np.array([d,np.array(b)]), ab=[a,b])

【问题讨论】:

  • 如果使用 quiver,可能值得展示您遇到的问题。 (我没有看到问题,我希望它可以工作,没有设置任何限制。)
  • @ImportanceOfBeingErnest 感谢您的回答。我在帖子中添加了quiver 的问题。

标签: python matplotlib


【解决方案1】:

我认为您会通过更用力地搜索 stackoverflow 找到 2. 和 4. 的解决方案。真正的问题(1./3.)是箭头末端不参与自动缩放机制。当它们不在数据坐标中时,通常会出现这种情况,但如果它们不在数据坐标中,则可以预期它们会更改绘图的数据限制。

在任何情况下,一种解决方法是绘制一个不可见的 plot 以及带有向量起点和终点的点的箭袋:

ax.quiver(x, y, u, v, angles='xy', scale_units='xy', scale=1.)
ax.plot(np.array(x)+np.array(u), np.array(y)+np.array(v), np.array(x), np.array(y), visible=False)

【讨论】:

  • 谢谢,但画错了:矢量e 应该从[5, 2][1, 2]
  • 不,向量总是从 (x,y) 指向 (x+u, y+v),所以绘图是正确的。
  • 这就是为什么我在帖子中写道我没有找到使用ax.quiver 的方法。问题是如何在没有花哨限制的情况下绘制任何矢量。
  • 没有限制。您只需要提供正确的数据。
  • 刻度标签的格式见this。如果您只想在整数上打勾,请参阅this
猜你喜欢
  • 2012-08-29
  • 2019-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
  • 1970-01-01
  • 2021-02-02
  • 1970-01-01
相关资源
最近更新 更多