1

What's Python's equivalent to R's layout() function which can create a plotting grid of any shape?

Consider the following 3 figures made by layout():

set.seed(123)
layout(t(matrix(c(
  1, 1, 2, 2, 3, 3,
  4, 5, 5, 6, 6, 7
), ncol = 2)), widths = rep(1, 6), heights = rep(1, 2))
par(mar = c(4, 5, 1, 1), family = "serif")
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 1
plot(x = runif(30), y = runif(30), cex.axis = 1.5, 
     bty = "L", xlab = "", ylab = "", las = 1) # 2
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 3
plot.new() # 4
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 5
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 6

enter image description here

set.seed(123)
layout(t(matrix(c(
  1, 1, 2, 2, 3, 3,
  4, 4, 4, 5, 5, 5
), ncol = 2)), widths = rep(1, 6), heights = rep(1, 2))
par(mar = c(4, 5, 1, 1), family = "serif")
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 1
plot(x = runif(30), y = runif(30), cex.axis = 1.5, 
     bty = "L", xlab = "", ylab = "", las = 1) # 2
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 3
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 4
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 5

enter image description here

set.seed(123)
layout(t(matrix(c(
  1, 1, 2, 2, 3, 3,
  4, 4, 4, 4, 5, 5
), ncol = 2)), widths = rep(1, 6), heights = rep(1, 2))
par(mar = c(4, 5, 1, 1), family = "serif")
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 1
plot(x = runif(30), y = runif(30), cex.axis = 1.5, 
     bty = "L", xlab = "", ylab = "", las = 1) # 2
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 3
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 4
plot(x = runif(30), y = runif(30), cex.axis = 1.5,
     bty = "L", xlab = "", ylab = "", las = 1) # 5

enter image description here

In Python, how to make figures of constituent plots with exactly the same layout as the above?

tdy
  • 36,675
  • 19
  • 86
  • 83
user2961927
  • 1,290
  • 1
  • 14
  • 22

1 Answers1

4

The simplest counterpart is plt.subplot_mosaic, which is a convenience wrapper for making custom gridspecs:

  • Each character is a column, and each line is a row
  • Each unique letter gets grouped into one subplot
  • Each dot . represents empty space

So your 3 examples correspond to these 3 mosaics:

fig, axs = plt.subplot_mosaic('''
    aabbcc
    .ddee.
''')

fig, axs = plt.subplot_mosaic('''
    aabbcc
    dddeee
''')

fig, axs = plt.subplot_mosaic('''
    abc
    dde
''')


Full example

Note that plt.subplot_mosaic returns a dictionary of axes (not an array like plt.subplots):

import matplotlib.pyplot as plt
import numpy as np

mosaic = '''
    aabbcc
    .ddee.
'''

fig, axs = plt.subplot_mosaic(mosaic, figsize=(7, 4))
print(axs)
# {'a': <Axes: label='a'>,
#  'b': <Axes: label='b'>,
#  'c': <Axes: label='c'>,
#  'd': <Axes: label='d'>,
#  'e': <Axes: label='e'>}

for label, ax in axs.items():
    ax.scatter(np.random.random(30), np.random.random(30), s=10)
    ax.set_title(label)

plt.tight_layout()
plt.show()

full example

tdy
  • 36,675
  • 19
  • 86
  • 83