4

I have created a plot in Python with Pyplot that have multiple subplots.

I would like to draw a line which is not on any of the plots. I know how to draw a line which is part of a plot, but I don't know how to do it on the white space between the plots.

Thank you.


Thank you for the link but I don't want vertical lines between the plots. It is in fact a horizontal line above one of the plots to denote a certain range. Is there not a way to draw an arbitrary line on top of a figure?

user1551817
  • 6,693
  • 22
  • 72
  • 109
  • 2
    Is [this](http://stackoverflow.com/questions/6146290/plotting-a-line-over-several-graphs/6147154#6147154) the kind of thing you're thinking of? If so, then `clip_on=False` may help. – DSM Aug 12 '13 at 17:08
  • 2
    You can use "manual coordinates", respective to the whole plot, to add shapes to the figure. That would be coordinates from 0 and 1 relative to figure height and width. I've seen that already (but don't remember how, will take a look). – heltonbiker Aug 12 '13 at 17:28
  • 1
    `annotate` is also very useful for this purpose – tacaswell Aug 12 '13 at 18:08

1 Answers1

3

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

enter image description here

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

enter image description here

After panning

enter image description here

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.

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • 2
    It's also possible to use `ax.hlines(1.1, 0.3, 0.7, clip_on=False, transform=ax.transAxes)` although this is essentially what you are doing with the `plot` method. At least I think it is more intuitive to use this method rather than `plot` when intentionally drawing horizontal lines. – sodd Aug 12 '13 at 20:20