Plot a horizontal line using matplotlib

April 06, 2022, at 7:40 PM

I have used spline interpolation to smooth a time series and would also like to add a horizontal line to the plot. But there seems to be an issue that is out of my grips. Any assistance would be really helpful. Here is what I have:

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)

problem seems to be with my use of [0,len(xs)] for horizontal line plotting.

Answer 1

You're looking for axhline (a horizontal axis line). For example, the following will give you a horizontal line at y = 0.5:

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

Answer 2

If you want to draw a horizontal line in the axes, you might also try ax.hlines() method. You need to specify y position and xmin and xmax in the data coordinate (i.e, your actual data range in the x-axis). A sample code snippet is:

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')

The snippet above will plot a horizontal line in the axes at y=0.2. The horizontal line starts at x=4 and ends at x=20. The generated image is:

Answer 3

Use matplotlib.pyplot.hlines:

  • Plot multiple horizontal lines by passing a list to the y parameter.
  • y can be passed as a single location: y=40
  • y can be passed as multiple locations: y=[39, 40, 41]
  • If you're a plotting a figure with something like fig, ax = plt.subplots(), then replace plt.hlines or plt.axhline with ax.hlines or ax.axhline, respectively.
  • matplotlib.pyplot.axhline can only plot a single location (e.g. y=40)
  • See this answer for vertical lines with .vlines


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)


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')

Time Series Axis

  • xmin and xmax will accept a date like '2020-09-10' or datetime(2020, 9, 10)
    • Using from datetime import datetime
    • xmin=datetime(2020, 9, 10), xmax=datetime(2020, 9, 10) + timedelta(days=3)
    • Given date = df.index[9], xmin=date, xmax=date + pd.Timedelta(days=3), where the index is a DatetimeIndex.
  • The date column on the axis must be a datetime dtype. If using pandas, then use pd.to_datetime. For an array or list, refer to Converting numpy array of strings to datetime or Convert datetime list into date python, respectively.
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
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')

  • Sample time series data if web.DataReader doesn't work.
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')

Barplot and Histograms

  • Note that barplots are usually 0 indexed, regardless of the axis labels, so select xmin and xmax based on the bar index, not the tick label.
    • ax.get_xticklabels() will show the locations and labels.
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')

Answer 4

In addition to the most upvoted answer here, one can also chain axhline after calling plot on a pandas's DataFrame.

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

Answer 5

You are correct, I think the [0,len(xs)] is throwing you off. You'll want to reuse the original x-axis variable xs and plot that with another numpy array of the same length that has your variable in it.

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)
#####horizontal line
horiz_line_data = np.array([40 for i in xrange(len(xs))])
plt.plot(xs, horiz_line_data, 'r--') 

Hopefully that fixes the problem!

Answer 6

A nice and easy way for those people who always forget the command axhline is the following

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

In your case xs = x and y = 40. If len(x) is large, then this becomes inefficient and you should really use axhline.

Answer 7

You can use plt.grid to draw a horizontal line.

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
# horizental line?
ax = plt.axes()
# three ticks:
# plot grids only on y axis on major locations
plt.grid(True, which='major', axis='y')
# show

Finding best representative point in a group of latitudes and longitudes

Finding best representative point in a group of latitudes and longitudes

I have a cluster of 10 Latitudes and LongitudesI want to find the optimal location to do set up a lemonade stand

Changing python list size during iteration. Is it okay?

Changing python list size during iteration. Is it okay?

Above is simple code changes list size during iterating itself

Average using loops

Average using loops

Anyone know how to rearrange this code so that when the values that are inputted are 3 4 8 4 , the average is 475