如何在屏幕上均匀地平铺 matplotlib 图形?
How to tile matplotlib figures evenly on screen?
matplotlib 是否提供在屏幕上均匀分布多个图形的功能?或者有人知道能够实现这一目标的工具箱吗?我已经厌倦了手动执行此操作。
import matplotlib.pyplot as plt
for i in range(5):
plt.figure()
plt.show()
这将创建五个相互重叠的图形。要检查图 1 上的内容,我必须将其他 4 个数字移到一边。
在 MacOS 上,我可以使用 Ctrl+↓ 快捷键来浏览所有数字。或者,我可以将绘图写入文件并检查图库中的图像。但我想知道是否有一个自定义的 window matplotlib 管理器可以提供更多的灵活性。
在Matlab中,我习惯了spreadfigure or autoArrangeFigures等工具。
您可以像这样使用图形管理器控制绘图的位置 window:
import matplotlib.pyplot as plt
start_x, start_y, dx, dy = (0, 0, 640, 550)
for i in range(5):
if i%3 == 0:
x = start_x
y = start_y + (dy * (i//3) )
plt.figure()
mngr = plt.get_current_fig_manager()
mngr.window.setGeometry(x, y, dx, dy)
x += dx
plt.show()
这将导致五个图表并排显示,如下所示:
希望这就是您要找的!
matplotlib 似乎没有提供这样的功能out-of-the-box。此外,没有“backend-agnostic”控制图形几何的方法,如讨论here。
因此,我写了 tile_figures()
来实现这个 mini-feature 通过一些平铺逻辑和简单的后端抽象来扩展 Anwarvic 的建议。它目前仅支持 Qt- 或 Tk-backends,但它当然也可以扩展到其他后端。
快乐平铺!
用法
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))
结果
实施
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()
标题栏的高度最好选择y-direction中的tile-offset。在我的 MacOS 上它是 22。可以使用例如 Qt 以编程方式查询此值。
from PyQt5 import QtWidgets as qtw
enum = qtw.QStyle.PM_TitleBarHeight
style = qtw.QApplication.style()
tile_offset_y = style.pixelMetric(enum)
matplotlib 是否提供在屏幕上均匀分布多个图形的功能?或者有人知道能够实现这一目标的工具箱吗?我已经厌倦了手动执行此操作。
import matplotlib.pyplot as plt
for i in range(5):
plt.figure()
plt.show()
这将创建五个相互重叠的图形。要检查图 1 上的内容,我必须将其他 4 个数字移到一边。
在 MacOS 上,我可以使用 Ctrl+↓ 快捷键来浏览所有数字。或者,我可以将绘图写入文件并检查图库中的图像。但我想知道是否有一个自定义的 window matplotlib 管理器可以提供更多的灵活性。
在Matlab中,我习惯了spreadfigure or autoArrangeFigures等工具。
您可以像这样使用图形管理器控制绘图的位置 window:
import matplotlib.pyplot as plt
start_x, start_y, dx, dy = (0, 0, 640, 550)
for i in range(5):
if i%3 == 0:
x = start_x
y = start_y + (dy * (i//3) )
plt.figure()
mngr = plt.get_current_fig_manager()
mngr.window.setGeometry(x, y, dx, dy)
x += dx
plt.show()
这将导致五个图表并排显示,如下所示:
希望这就是您要找的!
matplotlib 似乎没有提供这样的功能out-of-the-box。此外,没有“backend-agnostic”控制图形几何的方法,如讨论here。
因此,我写了 tile_figures()
来实现这个 mini-feature 通过一些平铺逻辑和简单的后端抽象来扩展 Anwarvic 的建议。它目前仅支持 Qt- 或 Tk-backends,但它当然也可以扩展到其他后端。
快乐平铺!
用法
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))
结果
实施
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()
标题栏的高度最好选择y-direction中的tile-offset。在我的 MacOS 上它是 22。可以使用例如 Qt 以编程方式查询此值。
from PyQt5 import QtWidgets as qtw
enum = qtw.QStyle.PM_TitleBarHeight
style = qtw.QApplication.style()
tile_offset_y = style.pixelMetric(enum)