First off, a quick way to do this is jut to use axvspan
with y-coordinates greater than 1 and clip_on=False
. It draws a rectangle rather than a line, though.
As a simple example:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(10))
ax.axvspan(2, 4, 1.05, 1.1, clip_on=False)
plt.show()

For drawing lines, you just specify the transform
that you'd like to use as a kwarg to plot
(the same applies to most other plotting commands, actually).
To draw in "axes" coordinates (e.g. 0,0 is the bottom left of the axes, 1,1 is the top right), use transform=ax.transAxes
, and to draw in figure coordinates (e.g. 0,0 is the bottom left of the figure window, while 1,1 is the top right) use transform=fig.transFigure
.
As @tcaswell mentioned, annotate
makes this a bit simpler for placing text, and can be very useful for annotations, arrows, labels, etc. You could do this with annotate (by drawing a line between a point and a blank string), but if you just want to draw a line, it's simpler not to.
For what it sounds like you're wanting to do, though, you might want to do things a bit differently.
It's easy to create a transform where the x-coordinates use one transformation and the y-coordinates use a different one. This is what axhspan
and axvspan
do behind the scenes. It's very handy for something like what you want, where the y-coordinates are fixed in axes coords, and the x-coordinates reflect a particular position in data coords.
The following example illustrates the difference between just drawing in axes coordinates and using a "blended" transform instead. Try panning/zooming both subplots, and notice what happens.
import matplotlib.pyplot as plt
from matplotlib.transforms import blended_transform_factory
fig, (ax1, ax2) = plt.subplots(nrows=2)
# Plot a line starting at 30% of the width of the axes and ending at
# 70% of the width, placed 10% above the top of the axes.
ax1.plot([0.3, 0.7], [1.1, 1.1], transform=ax1.transAxes, clip_on=False)
# Now, we'll plot a line where the x-coordinates are in "data" coords and the
# y-coordinates are in "axes" coords.
# Try panning/zooming this plot and compare to what happens to the first plot.
trans = blended_transform_factory(ax2.transData, ax2.transAxes)
ax2.plot([0.3, 0.7], [1.1, 1.1], transform=trans, clip_on=False)
# Reset the limits of the second plot for easier comparison
ax2.axis([0, 1, 0, 1])
plt.show()
Before panning

After panning

Notice that with the bottom plot (which uses a "blended" transform), the line is in data coordinates and moves with the new axes extents, while the top line is in axes coordinates and stays fixed.