【问题标题】:Plot a horizontal line using matplotlib使用 matplotlib 绘制水平线
【发布时间】:2016-01-27 17:29:25
【问题描述】:

我已经使用样条插值来平滑时间序列,并且还想在图中添加一条水平线。但似乎有一个问题超出了我的掌握。任何帮助都会非常有帮助。这是我所拥有的:

annual = np.arange(1,21,1)
l = np.array(value_list) # a list with 20 values
spl = UnivariateSpline(annual,l)
xs = np.linspace(1,21,200)
plt.plot(xs,spl(xs),'b')

plt.plot([0,len(xs)],[40,40],'r--',lw=2)
pylab.ylim([0,200])
plt.show()

问题似乎与我使用[0,len(xs)] 进行水平线绘图有关。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    使用matplotlib.pyplot.hlines:

    • 通过将list 传递给y 参数来绘制多条水平线。
    • y 可以作为单个位置传递:y=40
    • y 可以作为多个位置传递:y=[39, 40, 41]
    • 如果您要绘制带有 fig, ax = plt.subplots() 之类的图形,请将 plt.hlinesplt.axhline 分别替换为 ax.hlinesax.axhline
    • matplotlib.pyplot.axhline 只能绘制一个位置(例如y=40
    • 请参阅此answer 以获取带有.vlines 的垂直线

    plt.plot

    import numpy as np
    import matplotlib.pyplot as plt
    
    xs = np.linspace(1, 21, 200)
    
    plt.figure(figsize=(6, 3))
    plt.hlines(y=39.5, xmin=100, xmax=175, colors='aqua', linestyles='-', lw=2, label='Single Short Line')
    plt.hlines(y=[39, 40, 41], xmin=[0, 25, 50], xmax=[len(xs)], colors='purple', linestyles='--', lw=2, label='Multiple Lines')
    plt.legend(bbox_to_anchor=(1.04,0.5), loc="center left", borderaxespad=0)
    

    ax.plot

    import numpy as np
    import matplotlib.pyplot as plt
    
    xs = np.linspace(1, 21, 200)
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 6))
    
    ax1.hlines(y=40, xmin=0, xmax=len(xs), colors='r', linestyles='--', lw=2)
    ax1.set_title('One Line')
    
    ax2.hlines(y=[39, 40, 41], xmin=0, xmax=len(xs), colors='purple', linestyles='--', lw=2)
    ax2.set_title('Multiple Lines')
    
    plt.tight_layout()
    plt.show()
    

    时间序列轴

    • xminxmax 将接受像 '2020-09-10'datetime(2020, 9, 10) 这样的日期
      • 使用from datetime import datetime
      • xmin=datetime(2020, 9, 10), xmax=datetime(2020, 9, 10) + timedelta(days=3)
      • 给定date = df.index[9]xmin=date, xmax=date + pd.Timedelta(days=3),其中索引为DatetimeIndex
    • 轴上的日期列必须是datetime dtype。如果使用 pandas,则使用 pd.to_datetime。对于数组或列表,请分别参考Converting numpy array of strings to datetimeConvert datetime list into date python
    import pandas_datareader as web  # conda or pip install this; not part of pandas
    import pandas as pd
    import matplotlib.pyplot as plt
    
    # get test data; the Date index is already downloaded as datetime dtype
    df = web.DataReader('^gspc', data_source='yahoo', start='2020-09-01', end='2020-09-28').iloc[:, :2]
    
    # display(df.head(2))
                       High          Low
    Date                                
    2020-09-01  3528.030029  3494.600098
    2020-09-02  3588.110107  3535.229980
    
    # plot dataframe
    ax = df.plot(figsize=(9, 6), title='S&P 500', ylabel='Price')
    
    # add horizontal line
    ax.hlines(y=3450, xmin='2020-09-10', xmax='2020-09-17', color='purple', label='test')
    
    ax.legend()
    plt.show()
    

    • 如果web.DataReader 不起作用,则采样时间序列数据。
    data = {pd.Timestamp('2020-09-01 00:00:00'): {'High': 3528.03, 'Low': 3494.6}, pd.Timestamp('2020-09-02 00:00:00'): {'High': 3588.11, 'Low': 3535.23}, pd.Timestamp('2020-09-03 00:00:00'): {'High': 3564.85, 'Low': 3427.41}, pd.Timestamp('2020-09-04 00:00:00'): {'High': 3479.15, 'Low': 3349.63}, pd.Timestamp('2020-09-08 00:00:00'): {'High': 3379.97, 'Low': 3329.27}, pd.Timestamp('2020-09-09 00:00:00'): {'High': 3424.77, 'Low': 3366.84}, pd.Timestamp('2020-09-10 00:00:00'): {'High': 3425.55, 'Low': 3329.25}, pd.Timestamp('2020-09-11 00:00:00'): {'High': 3368.95, 'Low': 3310.47}, pd.Timestamp('2020-09-14 00:00:00'): {'High': 3402.93, 'Low': 3363.56}, pd.Timestamp('2020-09-15 00:00:00'): {'High': 3419.48, 'Low': 3389.25}, pd.Timestamp('2020-09-16 00:00:00'): {'High': 3428.92, 'Low': 3384.45}, pd.Timestamp('2020-09-17 00:00:00'): {'High': 3375.17, 'Low': 3328.82}, pd.Timestamp('2020-09-18 00:00:00'): {'High': 3362.27, 'Low': 3292.4}, pd.Timestamp('2020-09-21 00:00:00'): {'High': 3285.57, 'Low': 3229.1}, pd.Timestamp('2020-09-22 00:00:00'): {'High': 3320.31, 'Low': 3270.95}, pd.Timestamp('2020-09-23 00:00:00'): {'High': 3323.35, 'Low': 3232.57}, pd.Timestamp('2020-09-24 00:00:00'): {'High': 3278.7, 'Low': 3209.45}, pd.Timestamp('2020-09-25 00:00:00'): {'High': 3306.88, 'Low': 3228.44}, pd.Timestamp('2020-09-28 00:00:00'): {'High': 3360.74, 'Low': 3332.91}}
    
    df = pd.DataFrame.from_dict(data, 'index')
    

    条形图和直方图

    • 请注意,无论轴标签如何,条形图的索引通常为 0,因此请根据条形索引而不是刻度标签选择 xminxmax
      • ax.get_xticklabels() 将显示位置和标签。
    import pandas as pd
    import seaborn as sns  # for tips data
    
    # load data
    tips = sns.load_dataset('tips')
    
    # histogram
    ax = tips.plot(kind='hist', y='total_bill', bins=30, ec='k', title='Histogram with Horizontal Line')
    _ = ax.hlines(y=6, xmin=0, xmax=55, colors='r')
    
    # barplot 
    ax = tips.loc[5:25, ['total_bill', 'tip']].plot(kind='bar', figsize=(15, 4), title='Barplot with Vertical Lines', rot=0)
    _ = ax.hlines(y=6, xmin=3, xmax=15, colors='r')
    

    【讨论】:

      【解决方案2】:

      您正在寻找axhline(水平轴线)。例如,下面将在y = 0.5 处为您提供一条水平线:

      import matplotlib.pyplot as plt
      plt.axhline(y=0.5, color='r', linestyle='-')
      plt.show()
      

      【讨论】:

        【解决方案3】:

        如果你想在坐标轴上画一条水平线,你也可以试试ax.hlines() 方法。您需要在数据坐标中指定y 位置和xminxmax(即您在x 轴上的实际数据范围)。示例代码 sn -p 为:

        import matplotlib.pyplot as plt
        import numpy as np
        
        x = np.linspace(1, 21, 200)
        y = np.exp(-x)
        
        fig, ax = plt.subplots()
        ax.plot(x, y)
        ax.hlines(y=0.2, xmin=4, xmax=20, linewidth=2, color='r')
        
        plt.show()
        

        上面的 sn-p 将在 y=0.2 的坐标轴上绘制一条水平线。水平线从x=4 开始,到x=20 结束。生成的图像是:

        【讨论】:

          【解决方案4】:

          你可以使用plt.grid画一条水平线。

          import numpy as np
          from matplotlib import pyplot as plt
          from scipy.interpolate import UnivariateSpline
          from matplotlib.ticker import LinearLocator
          
          # your data here
          annual = np.arange(1,21,1)
          l = np.random.random(20)
          spl = UnivariateSpline(annual,l)
          xs = np.linspace(1,21,200)
          
          # plot your data
          plt.plot(xs,spl(xs),'b')
          
          # horizental line?
          ax = plt.axes()
          # three ticks:
          ax.yaxis.set_major_locator(LinearLocator(3))
          # plot grids only on y axis on major locations
          plt.grid(True, which='major', axis='y')
          
          # show
          plt.show()
          

          【讨论】:

            【解决方案5】:

            除了此处投票最多的答案外,还可以在pandasDataFrame 上调用plot 后链接axhline

            import pandas as pd
            
            (pd.DataFrame([1, 2, 3])
               .plot(kind='bar', color='orange')
               .axhline(y=1.5));
            

            【讨论】:

              【解决方案6】:

              对于那些总是忘记命令axhline 的人来说,一个简单的方法如下

              plt.plot(x, [y]*len(x))
              

              在您的情况下,xs = xy = 40。 如果 len(x) 很大,那么这将变得低效,你应该真正使用axhline

              【讨论】:

                【解决方案7】:

                你是对的,我认为[0,len(xs)] 让你失望了。您需要重用原始 x 轴变量 xs 并将其与另一个长度相同且包含您的变量的 numpy 数组绘制。

                annual = np.arange(1,21,1)
                l = np.array(value_list) # a list with 20 values
                spl = UnivariateSpline(annual,l)
                xs = np.linspace(1,21,200)
                plt.plot(xs,spl(xs),'b')
                
                #####horizontal line
                horiz_line_data = np.array([40 for i in xrange(len(xs))])
                plt.plot(xs, horiz_line_data, 'r--') 
                ###########plt.plot([0,len(xs)],[40,40],'r--',lw=2)
                pylab.ylim([0,200])
                plt.show()
                

                希望能解决问题!

                【讨论】:

                • 这行得通,但不是特别有效,尤其是当您根据数据创建一个可能非常大的数组时。如果你打算这样做,那么有两个数据点会更聪明,一个在开头,一个在结尾。尽管如此,matplotlib 已经有一个专门的水平线功能。