【问题标题】:Show direction arrows in a scatterplot在散点图中显示方向箭头
【发布时间】:2019-10-11 13:34:27
【问题描述】:

我在散点图中绘制数据,我想查看滞后的方向。有谁知道如何在每条线上实现指向下一点方向的箭头?

或者,标记可以替换为指向下一个点的方向的箭头。

我在寻找什么:

获取绘图的代码(无箭头):

df = pd.DataFrame.from_dict({'x' : [0,3,8,7,5,3,2,1],
                             'y' : [0,1,3,5,9,8,7,5]})
x = df['x']
y = df['y']
fig, ax = plt.subplots()
ax.scatter(x,y)
ax.plot(x,y)

【问题讨论】:

  • 如果你有两个点(x0,y0)(x1,y1),那么它们之间的中间是((x0+y0)/2, (y0+y1)/2)。这将是箭头的位置。角度是 arctan(x1-x0, y1-y0)`(为此使用 numpy.arctan2)。箭头可以用plt.quiver绘制。
  • 还有这个:stackoverflow.com/questions/34017866/… 虽然所有这些解决方案都将箭头放在顶点而不是线的中间。

标签: python matplotlib scatter-plot


【解决方案1】:

正如评论的那样,可以使用plt.quiver 沿一条线生成箭头,例如喜欢

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame.from_dict({'x' : [0,3,8,7,5,3,2,1],
                             'y' : [0,1,3,5,9,8,7,5]})
x = df['x'].values
y = df['y'].values

u = np.diff(x)
v = np.diff(y)
pos_x = x[:-1] + u/2
pos_y = y[:-1] + v/2
norm = np.sqrt(u**2+v**2) 

fig, ax = plt.subplots()
ax.plot(x,y, marker="o")
ax.quiver(pos_x, pos_y, u/norm, v/norm, angles="xy", zorder=5, pivot="mid")
plt.show()

【讨论】:

    【解决方案2】:

    感谢有用的提示!这是我的解决方案:

    df = pd.DataFrame.from_dict({'x' : [0,3,8,7,5,3,2,1],
                                 'y' : [0,1,3,5,9,8,7,5]})
    x = df['x']
    y = df['y']
    # calculate position and direction vectors:
    x0 = x.iloc[range(len(x)-1)].values
    x1 = x.iloc[range(1,len(x))].values
    y0 = y.iloc[range(len(y)-1)].values
    y1 = y.iloc[range(1,len(y))].values
    xpos = (x0+x1)/2
    ypos = (y0+y1)/2
    xdir = x1-x0
    ydir = y1-y0
    fig, ax = plt.subplots()
    ax.scatter(x,y)
    ax.plot(x,y)
    # plot arrow on each line:
    for X,Y,dX,dY in zip(xpos, ypos, xdir, ydir):
        ax.annotate("", xytext=(X,Y),xy=(X+0.001*dX,Y+0.001*dY), 
        arrowprops=dict(arrowstyle="->", color='k'), size = 20)
    

    这给出了这个:

    plt.quiver 在这种情况下没有帮助,因为它会创建一个箭头字段。 plt.arrow 随轴缩放,如果 x 和 y 单位不是同一个数量级,那么看起来很奇怪的箭头。因此,ax.annotate 是我的选择。论据xytext &xy分别表示箭头的开始和结束。

    【讨论】:

      【解决方案3】:

      感谢@NicoH。这段代码很棒。我用它来绘制一个 TSP 求解器。

      nyc_map_zoom = plt.imread('https://aiblog.nl/download/nyc_-74.3_-73.7_40.5_40.9.png')
      
      def plot_on_map(df, BB, nyc_map, s=40, alpha=0.2):
          x = df['Longitude']
          y = df['Latitude']
          # calculate position and direction vectors:
          x0 = x.iloc[range(len(x)-1)].values
          x1 = x.iloc[range(1,len(x))].values
          y0 = y.iloc[range(len(y)-1)].values
          y1 = y.iloc[range(1,len(y))].values
          xpos = (x0+x1)/2
          ypos = (y0+y1)/2
          xdir = x1-x0
          ydir = y1-y0
          # plot map
          fig, ax = plt.subplots(figsize=(20,20))
          ax.scatter(x,y, marker='H',c='fuchsia',s=80,label=df["Name"])
          ax.set_xlim((BB[0], BB[1]))
          ax.set_ylim((BB[2], BB[3]))
          ax.set_title('Pizza Locations and Route Directions', fontsize=15)
          ax.imshow(nyc_map, zorder=0, extent=BB)
          ax.plot(x,y,linewidth=3)
          plt.legend(title='Pizza Joints', facecolor='white', framealpha=1,fontsize=15,title_fontsize=18, fancybox=True,edgecolor = 'k')
          # plot arrow on each line:
          for X,Y,dX,dY in zip(xpos, ypos, xdir, ydir):
              ax.annotate("", xytext=(X,Y),xy=(X+0.001*dX,Y+0.001*dY), 
              arrowprops=dict(arrowstyle="->", linewidth=3,color='k'), size = 40)
          plt.savefig('Pizza_Route.png',bbox_inches='tight');
      
      
      
      BB_zoom = (-74.3, -73.7, 40.5, 40.9)
      plot_on_map(TSP, BB_zoom, nyc_map_loc, s=20, alpha=0.3)
      

      【讨论】:

        【解决方案4】:

        您可以像这样使用箭头注释来表示实际的线段:

        df = pd.DataFrame.from_dict({'x' : [0,3,8,7,5,3,2,1],
                                     'y' : [0,1,3,5,9,8,7,5]})
        
        for i,row in df.iterrows():
            if i==0:
                pass
            else:
                plt.annotate('',xy=(row['x'],row['y']),xytext=(df.iloc[i-1]['x'],df.iloc[i-1]['y']),
                arrowprops=dict(facecolor='black',width=1,headwidth=5))
        
        plt.xlim(0 ,10)
        plt.ylim(0,10)
        

        可以使用颜色/宽度使其更漂亮

        【讨论】:

          猜你喜欢
          • 2013-01-17
          • 2016-10-09
          • 2017-07-26
          • 1970-01-01
          • 2011-04-30
          • 1970-01-01
          • 1970-01-01
          • 2018-03-03
          • 1970-01-01
          相关资源
          最近更新 更多