24

I have tried the following:

d = [1,2,3,4,5,6,7,8,9]
f = [0,1,0,0,1,0,1,1,0]
fig = plt.figure()
fig.set_size_inches(30,10)
ax1 = fig.add_subplot(211)
line1 = ax1.plot(d,marker='.',color='b',label="1 row")
ax2 = fig.add_subplot(212)
line1 = ax2.plot(f,marker='.',color='b',label="1 row")
ax1.grid()
ax2.grid()
plt.show()

I got the following output :

output

But I was expecting the following output:
expected output

How I can get the grids across the two plots?

James Z
  • 12,209
  • 10
  • 24
  • 44
Jaffer Wilson
  • 7,029
  • 10
  • 62
  • 139
  • Possible duplicate of [Draw line between two subplots](https://stackoverflow.com/questions/3635411/draw-line-between-two-subplots) – SpghttCd Aug 30 '18 at 11:07
  • @SpghttCd That is for matlab. This question asks for Python – DavidG Aug 30 '18 at 11:09
  • Sorry, I know there was this question for matplotlib in the last few months, so I was too fast on choosing. – SpghttCd Aug 30 '18 at 11:12
  • Possible duplicate of [Plotting a line over several graphs](https://stackoverflow.com/questions/6146290/plotting-a-line-over-several-graphs) – DavidG Aug 30 '18 at 11:12
  • This link [here](https://stackoverflow.com/questions/6146290/plotting-a-line-over-several-graphs) might help. Although it is not gridlines exactly but you can turn them black and thin to make them look like one – Sheldore Aug 30 '18 at 11:13
  • @DavidG: I wouldn't call it duplicate but similar. – Sheldore Aug 30 '18 at 11:14
  • I get this behavior without wanting it in 2.1.1... – Radio Controlled Oct 02 '19 at 07:32

4 Answers4

30

There is no built-in option to create inter-subplot grids. In this case I'd say an easy option is to create a third axes in the background with the same grid in x direction, such that the gridline can be seen in between the two subplots.

import matplotlib.pyplot as plt

d = [1,2,3,4,5,6,7,8,9]
f = [0,1,0,0,1,0,1,1,0]

fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True)
ax3 = fig.add_subplot(111, zorder=-1)
for _, spine in ax3.spines.items():
    spine.set_visible(False)
ax3.tick_params(labelleft=False, labelbottom=False, left=False, right=False )
ax3.get_shared_x_axes().join(ax3,ax1)
ax3.grid(axis="x")


line1 = ax1.plot(d, marker='.', color='b', label="1 row")
line1 = ax2.plot(f, marker='.', color='b', label="1 row")
ax1.grid()
ax2.grid()
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
3

Here is my solution:

import matplotlib.pyplot as plt

x1 = [1,2,3,4,5,6,7,8,9]
x2= [0,1,0,0,1,0,1,1,0]
x3= range(-10,0)
# frameon=False removes frames
# fig, (ax1,ax2, ax3) = plt.subplots(nrows=3, sharex=True, subplot_kw=dict(frameon=False))
fig, (ax1,ax2, ax3) = plt.subplots(nrows=3, sharex=True)
# remove vertical gap between subplots
plt.subplots_adjust(hspace=.0)

ax1.grid()
ax2.grid()
ax3.grid()

ax1.plot(x1)
ax2.plot(x2)
ax3.plot(x3)

enter image description here

Without frames subplot_kw=dict(frameon=False):

enter image description here

Aray Karjauv
  • 2,679
  • 2
  • 26
  • 44
2

An option is to create a single plot then just offset the data. So one set plots above the other.

fuyi
  • 2,573
  • 4
  • 23
  • 46
cbradford
  • 21
  • 1
  • 1
    Thank you for your reply. Please can you give an example as you see I have given the data that I am trying to plot. Your answer looks like comment but since you have less score so you are unable to comment. If you give an example then it will be more helpful to everybody. – Jaffer Wilson Aug 11 '21 at 08:43
1

Solution

You can extend the grid lines by passing the appropriate coordinates through to Line2D with ax1.grid(ydata=[-space_between_axes, 1], clip_on=False).

import matplotlib.pyplot as plt

d = [1,2,3,4,5,6,7,8,9]
f = [0,1,0,0,1,0,1,1,0]
fig = plt.figure()
fig.set_size_inches(30,10)
ax1 = fig.add_subplot(211)
line1 = ax1.plot(d,marker='.',color='b',label="1 row")
ax2 = fig.add_subplot(212)
line1 = ax2.plot(f,marker='.',color='b',label="1 row")
plt.setp(ax1.get_xticklabels(), backgroundcolor="white")  # Eliminate strike-through.
space_between_plots = plt.rcParams["figure.subplot.hspace"]  # <==========
ax1.xaxis.grid(ydata=[-space_between_plots, 1], clip_on=False)  # <==========
ax1.yaxis.grid()
ax2.grid()
plt.show()

enter image description here

How does this work?

  • Per the docs of the matplotlib.axis.Axis.grid == ax1.xaxis.grid method, keyword arguments can be passed on to Line2D.
  • Line2D takes the x- and y-coordinates (xdata and ydata) as arguments.
  • But what coordinate system is used? You can check this with ax1.get_xgridlines()[-1].get_xydata(). The output is array([[9., 0.], [9., 1.]]). Apparently the x-values are in Data coordinates and the y-values are in Axes coordinates.
  • Next question: How far down do you need to extend? In this particular case you can just take the number -1 because the overlap with the same lines further down is invisible. The proper way however is to get the actual distance, in this case with space_between_plots = plt.rcParams["figure.subplot.hspace"]. That's 0.2 which means one fifth of the height of one plot.
  • The top stays the same at 1.
  • clip_on=True is needed because Matplotlib doesn't draw anything outside the plotting area by default.

Note

It looks like Matplotlib has a bug that makes this solution unworkable in some circumstances. E.g. if I leave out plt.setp(...), Maptlotlib complains that it receives the ydata argument multiple times and raises a TypeError.

Joooeey
  • 3,394
  • 1
  • 35
  • 49