It appears that matplotlib does not offer such a feature out-of-the-box. In addition, there is no "backend-agnostic" way to control the figure geometry, as discussed here.
I therefore wrote tile_figures()
to implement this mini-feature extending Anwarvic's suggestion by some tiling logic and a simple backend abstraction. It currently supports only Qt- or Tk-backends, but it certainly can be extended to other backends as well.
Happy tiling!
Usage
tile_figures(cols=3, rows=2, screen_rect=None, tile_offsets=None)
# You may have to adjust the available screen area and a tile offset
# for nice results. This works well for my MacOS.
tile_figure(screen_rect=(0,22,1440,740), tile_offsets=(0,22))
# Run a test with 10 figures. Note that you cannot switch the backend dynamically.
# It's best to set mpl.use(<backend>) at the very beginning of your script.
# https://matplotlib.org/faq/usage_faq.html#what-is-a-backend
test(n_figs=10, backend="Qt5Agg", screen_rect=(0,22,1440,750), tile_offsets=(0,22))
Result

Implementation
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def screen_geometry(monitor=0):
try:
from screeninfo import get_monitors
sizes = [(s.x, s.y, s.width, s.height) for s in get_monitors()]
return sizes[monitor]
except ModuleNotFoundError:
default = (0, 0, 900, 600)
print("screen_geometry: module screeninfo is no available.")
print("Returning default: %s" % (default,))
return default
def set_figure_geometry(fig, backend, x, y, w, h):
if backend in ("Qt5Agg", "Qt4Agg"):
fig.canvas.manager.window.setGeometry(x, y, w, h)
#fig.canvas.manager.window.statusBar().setVisible(False)
#fig.canvas.toolbar.setVisible(True)
elif backend in ("TkAgg",):
fig.canvas.manager.window.wm_geometry("%dx%d+%d+%d" % (w,h,x,y))
else:
print("This backend is not supported yet.")
print("Set the backend with matplotlib.use(<name>).")
return
def tile_figures(cols=3, rows=2, screen_rect=None, tile_offsets=None):
"""
Tile figures. If more than cols*rows figures are present, cols and
rows are adjusted. For now, a Qt- or Tk-backend is required.
import matplotlib
matplotlib.use('Qt5Agg')
matplotlib.use('TkAgg')
Arguments:
cols, rows: Number of cols, rows shown. Will be adjusted if the
number of figures is larger than cols*rows.
screen_rect: A 4-tuple specifying the geometry (x,y,w,h) of the
screen area used for tiling (in pixels). If None, the
system's screen is queried using the screeninfo module.
tile_offsets: A 2-tuple specifying the offsets in x- and y- direction.
Can be used to compensate the title bar height.
"""
assert(isinstance(cols, int) and cols>0)
assert(isinstance(rows, int) and rows>0)
assert(screen_rect is None or len(screen_rect)==4)
backend = mpl.get_backend()
if screen_rect is None:
screen_rect = screen_geometry()
if tile_offsets is None:
tile_offsets = (0,0)
sx, sy, sw, sh = screen_rect
sx += tile_offsets[0]
sy += tile_offsets[1]
fig_ids = plt.get_fignums()
# Adjust tiles if necessary.
tile_aspect = cols/rows
while len(fig_ids) > cols*rows:
cols += 1
rows = max(np.round(cols/tile_aspect), rows)
# Apply geometry per figure.
w = int(sw/cols)
h = int(sh/rows)
for i, num in enumerate(fig_ids):
fig = plt.figure(num)
x = (i%cols) *(w+tile_offsets[0])+sx
y = (i//cols)*(h+tile_offsets[1])+sy
set_figure_geometry(fig, backend, x, y, w, h)
def test(n_figs=10, backend="Qt5Agg", **kwargs):
mpl.use(backend)
plt.close("all")
for i in range(n_figs):
plt.figure()
tile_figures(**kwargs)
plt.show()
The tile-offset in y-direction is best chosen as the height of the title bar. On my MacOS it is 22. This value can be queried programmatically using for example Qt.
from PyQt5 import QtWidgets as qtw
enum = qtw.QStyle.PM_TitleBarHeight
style = qtw.QApplication.style()
tile_offset_y = style.pixelMetric(enum)