How to plot a horizontal line in Python
Learn how to plot a horizontal line in Python using different methods. Discover tips, real-world applications, and how to debug common errors.

Horizontal lines are a key element in Python data visualization. They help highlight thresholds or specific values. Matplotlib's axhline() function makes this process simple and efficient.
In this article, you'll explore several techniques to plot these lines. You'll also find practical tips, real-world applications, and debugging advice to help you master this skill.
Basic horizontal line with matplotlib
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4))
plt.axhline(y=0.5, color='r', linestyle='-')
plt.grid(True)
plt.show()--OUTPUT--[A plot with a red horizontal line at y=0.5 with a grid background]
The core of this plot is the plt.axhline() function, which draws a line across the entire chart width. The y=0.5 argument sets its vertical position precisely at the 0.5 mark on the y-axis. You're not limited to the default look, either.
Customization is straightforward. Here, color='r' makes the line red, and linestyle='-' ensures it's a solid line. Combining these parameters is how you add clear visual guides, such as performance targets or statistical averages, directly onto your plots.
Basic line plotting techniques
Beyond drawing a single, full-width line, you can also use axhline to plot partial segments, further customize styles, and create multiple lines at once.
Using axhline for partial lines
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4))
ax.axhline(y=0.5, xmin=0.25, xmax=0.75, color='b')
plt.show()--OUTPUT--[A plot with a blue horizontal line at y=0.5 spanning from 25% to 75% of the x-axis]
You're not limited to lines that cross the entire chart. To draw a partial line, you can use the xmin and xmax parameters within axhline(). These arguments specify the line's start and end points as a proportion of the x-axis, ranging from 0.0 (left edge) to 1.0 (right edge).
- In this example,
xmin=0.25begins the line 25% of the way across the axis. xmax=0.75stops the line at the 75% mark.
This approach is ideal for highlighting a specific data range without extending the line across the whole plot.
Customizing line styles and colors
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4))
plt.axhline(y=0.5, color='g', linestyle='--', linewidth=2)
plt.axhline(y=0.7, color='r', linestyle=':', linewidth=3)
plt.show()--OUTPUT--[A plot with two horizontal lines: a green dashed line at y=0.5 and a red dotted line at y=0.7]
You can fine-tune your lines beyond just color. The axhline() function offers several styling options to differentiate data thresholds.
linestyle: Sets the line pattern. Use'--'for a dashed line or':'for a dotted one.linewidth: Controls the line's thickness. A larger value, likelinewidth=3, creates a heavier line.
By combining these, you can layer multiple, distinct horizontal lines onto a single plot to compare different values, as shown in the example.
Creating multiple evenly spaced lines
import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(8, 4))
y_values = np.linspace(0, 1, 5)
for y in y_values:
plt.axhline(y=y, color='purple', alpha=0.3)
plt.show()--OUTPUT--[A plot with 5 evenly spaced light purple horizontal lines from y=0 to y=1]
You can efficiently create multiple lines by pairing NumPy with a simple for loop. This approach is perfect for adding a grid-like structure or showing multiple thresholds at once.
- First,
np.linspace(0, 1, 5)generates an array of five evenly spaced numbers from 0 to 1. - The loop then calls
plt.axhline()for each number, drawing a distinct line at each position.
Notice the alpha=0.3 argument. It controls the line's transparency, making the plot cleaner when you have many lines or overlapping data points.
Advanced horizontal line techniques
Now that you've mastered the basics, you can elevate your plots with annotations, shaded regions using axhspan, and lines that dynamically respond to your data.
Adding annotations to horizontal lines
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4))
ax.axhline(y=0.5, color='r')
ax.annotate('Threshold', xy=(0.5, 0.5), xytext=(0.7, 0.6),
arrowprops=dict(facecolor='black', shrink=0.05))
plt.show()--OUTPUT--[A plot with a red horizontal line at y=0.5 with an annotation "Threshold" and an arrow pointing to it]
A line on its own can be ambiguous, so adding context is key. The ax.annotate() function lets you place explanatory text directly onto your plot, making it instantly understandable.
- The first argument,
'Threshold', is the text label. xydefines the coordinate the arrow points to—right on the line.xytextsets where the text itself appears.arrowpropscustomizes the arrow connecting the label to the data point.
This simple addition turns a plain line into a meaningful threshold.
Using axhspan for horizontal bands
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4))
ax.axhspan(0.25, 0.75, alpha=0.2, color='green')
ax.set_ylim(0, 1)
plt.show()--OUTPUT--[A plot with a light green horizontal band spanning from y=0.25 to y=0.75]
When a single line isn't enough, you can highlight an entire range using axhspan(). This function draws a horizontal band, which is perfect for showing acceptable ranges or confidence intervals.
- The first two arguments,
0.25and0.75in this example, define the band's bottom and top edges on the y-axis. - You can also style the band with familiar parameters like
colorand adjust its transparency usingalpha.
Dynamic horizontal lines based on data
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y)
plt.axhline(y=y.mean(), color='r', linestyle='--', label=f'Mean: {y.mean():.2f}')
plt.legend()
plt.show()--OUTPUT--[A plot showing a sine wave with a red dashed horizontal line representing the mean value of the data]
You can make your horizontal lines respond directly to your data. Instead of a fixed value, you can calculate a position on the fly. This example plots a line at the average value of the sine wave data.
- The key is passing a calculated value, like
y.mean(), to theyparameter ofaxhline(). - The label is also dynamic, using an
f-stringto automatically include the calculated mean in the legend.
This approach ensures your visual references always reflect the underlying dataset, updating automatically if the data changes.
Move faster with Replit
Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.
For the line plotting techniques from this article, Replit Agent can turn them into production tools:
- Build a stock monitoring tool that uses
axhline()to plot custom price alerts. - Create a quality control dashboard that uses
axhspan()to visualize acceptable tolerance ranges. - Deploy an analytics app that dynamically plots the
mean()of a dataset as a horizontal line.
Bring your own data visualization ideas to life. Describe your application, and Replit Agent will build it, from the initial code to final deployment.
Common errors and challenges
Even with a simple function like axhline, you might run into a few common roadblocks, but they're usually straightforward to fix.
Fixing issues with axhline outside plot boundaries
Sometimes your horizontal line doesn't appear at all. This often happens when the line's y-position is outside the plot's visible range. Matplotlib automatically sets the y-axis limits based on your data, so if your data ranges from 10 to 20, an axhline at y=5 won't be visible.
To fix this, you need to manually set the y-axis limits. Use the set_ylim() function on your axes object to expand the range and ensure your line is included in the view.
Resolving axhline visibility problems with zorder
Another common issue is an axhline getting hidden behind other plot elements, like bars in a bar chart. This is a layering problem. Matplotlib draws elements in a certain order, and your line might be drawn before the data that covers it up.
The solution is to use the zorder parameter, which controls the stacking order of plot elements. Think of it as assigning layers—a higher zorder value brings an element to the front. By giving your axhline a higher zorder than the other data points, you ensure it's always visible on top.
Correctly applying axhline in multiple subplots
When working with a figure that contains multiple subplots, it's easy to draw a line on the wrong one. This typically occurs if you use plt.axhline(), which targets whichever subplot is currently "active." This can lead to unpredictable results.
For precise control, you should always call the method directly on the specific axes object you want to modify. For instance, if you have two subplots, ax1 and ax2, use ax1.axhline() to draw a line only on the first plot. This object-oriented approach avoids ambiguity and ensures your lines appear exactly where you intend.
Fixing issues with axhline outside plot boundaries
A common frustration is when your axhline doesn't appear on the plot. This usually happens because its y value is outside the visible y-axis range, which Matplotlib sets automatically based on your data. The code below demonstrates this exact problem.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y)
plt.axhline(y=1.5, color='r', linestyle='--', label='Target')
plt.legend()
plt.show()
The np.sin(x) data has a maximum value of 1, so Matplotlib's automatic axis scaling doesn't include the line at y=1.5. The line is drawn but isn't visible. The corrected code below shows the solution.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.plot(x, y)
plt.axhline(y=1.5, color='r', linestyle='--', label='Target')
plt.ylim(-1.5, 2) # Explicitly set y-axis limits to include the line
plt.legend()
plt.show()
The fix is to manually expand the y-axis using plt.ylim(). By setting the limits to (-1.5, 2), you ensure the plot’s visible area is large enough to include the line at y=1.5. This issue often arises when your horizontal line represents a target or threshold that falls outside your dataset's natural range. Explicitly setting the limits overrides Matplotlib's automatic scaling, guaranteeing your line appears exactly where you intended.
Resolving axhline visibility problems with zorder
Your axhline can easily get hidden behind other plot elements, especially when you use functions like fill_between. This is a layering issue. Matplotlib renders elements in a default order, which can obscure your line. The following code demonstrates this exact problem.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.fill_between(x, y, alpha=0.5)
plt.axhline(y=0, color='r', linestyle='-')
plt.show()
The code calls plt.fill_between() before plt.axhline(), which draws the shaded region over the line and hides it from view. The corrected code below shows how to bring the line to the front.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(8, 4))
plt.fill_between(x, y, alpha=0.5)
plt.axhline(y=0, color='r', linestyle='-', zorder=3)
plt.show()
The fix is to add the zorder parameter to your axhline() call. This parameter controls the stacking order of plot elements. By setting zorder=3, you're telling Matplotlib to draw the line on a higher layer, ensuring it appears on top of the shaded area created by fill_between(). This is a common solution when lines get hidden behind bar charts, heatmaps, or other filled plot elements.
Correctly applying axhline in multiple subplots
When you're working with multiple subplots, using the general plt.axhline() function can be tricky. It draws a line only on the subplot Matplotlib considers "active"—often the last one created. This can lead to lines appearing in the wrong place.
The code below demonstrates this common pitfall. Notice how the horizontal line only appears on the bottom subplot, even though you might have intended it for both or just the top one.
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
ax1.plot([1, 2, 3, 4], [1, 4, 2, 3])
ax2.plot([1, 2, 3, 4], [4, 3, 2, 1])
plt.axhline(y=2.5, color='r', linestyle='--')
plt.show()
Because plt.axhline() is state-based, it draws only on the last active subplot—ax2 in this instance. This leaves ax1 without a line. The corrected code below shows how to target each subplot directly for precise control.
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
ax1.plot([1, 2, 3, 4], [1, 4, 2, 3])
ax2.plot([1, 2, 3, 4], [4, 3, 2, 1])
ax1.axhline(y=2.5, color='r', linestyle='--')
plt.show()
The fix is to call axhline() on the specific axes object you want to modify. Instead of the general plt.axhline(), the corrected code uses ax1.axhline() to draw the line exclusively on the top subplot, ax1. This object-oriented approach gives you precise control. It's best to always use this method when your figure has multiple subplots to ensure your lines appear exactly where you intend them, avoiding any ambiguity.
Real-world applications
Now that you can troubleshoot plotting errors, you can use axhline and axhspan for practical financial and performance analysis.
Visualizing investment thresholds with axhline
You can use axhline to clearly mark important investment thresholds, like a target selling price, directly on a stock chart.
import matplotlib.pyplot as plt
stock_prices = [100, 102, 104, 103, 105, 107, 108]
plt.plot(stock_prices)
plt.axhline(y=105, color='r', linestyle='--', label='Sell Target')
plt.legend()
plt.show()
This code visualizes a data series and overlays a reference line. First, plt.plot() draws a line chart from the stock_prices list. Next, plt.axhline() adds a horizontal line at the y=105 position.
- The line is styled to be red and dashed with the
colorandlinestylearguments. - The
label='Sell Target'gives the line a name, whichplt.legend()then displays on the plot.
This combination lets you add clear, labeled reference points to any data visualization.
Monitoring system performance with axhspan zones
You can use axhspan to create colored zones that represent different system performance levels, such as normal, warning, and critical.
import matplotlib.pyplot as plt
cpu_usage = [30, 45, 70, 82, 65, 55, 40]
plt.plot(cpu_usage, 'o-', label='CPU Usage %')
plt.axhspan(80, 100, alpha=0.2, color='red', label='Critical')
plt.axhspan(60, 80, alpha=0.2, color='yellow', label='Warning')
plt.axhspan(0, 60, alpha=0.2, color='green', label='Normal')
plt.legend()
plt.show()
This code visualizes CPU usage data against performance thresholds. The plt.plot() function draws the cpu_usage data as a line with markers. The key is using plt.axhspan() to create three distinct, colored zones that represent different performance levels.
- Each
axhspan()call defines a horizontal band using a y-axis range, such as 80 to 100 for the "Critical" zone. - The
colorandalphaparameters style each band, withalpha=0.2adding transparency so the data line remains visible. - Finally,
plt.legend()gathers thelabelfrom each plot element to create a helpful key.
Get started with Replit
Turn what you've learned into a real tool. Tell Replit Agent: “Build a dashboard that plots sensor data and shows safe ranges” or “Create a tool to visualize my spending against a budget line.”
Replit Agent writes the code, tests for errors, and deploys your application from a single prompt. Start building with Replit.
Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.



