【发布时间】:2019-08-15 00:27:45
【问题描述】:
我正在开发一个 python 模块,该模块创建一个带有on_resize 侦听器的 matplotlib 图。侦听器将下轴的高度强制为特定数量的像素(而不是相对于图形大小进行缩放)。有用。但是,如果(在 matplotlib 交互模式下)在创建绘图后用户调用 fig.subplots_adjust() 它会弄乱子图的大小。这是该模块功能的一个彻底简化的版本:
import matplotlib.pyplot as plt
plt.ion()
def make_plot():
fig = plt.figure()
gs = plt.GridSpec(10, 1, figure=fig)
ax_upper = fig.add_subplot(gs[:-1])
ax_lower = fig.add_subplot(gs[-1])
ax_upper.plot([0, 1])
ax_lower.plot([0, 1])
fig.canvas.mpl_connect('resize_event', on_resize)
return fig
def on_resize(event):
fig = event.canvas.figure
# get the current position
ax_lower_pos = list(fig.axes[1].get_position().bounds) # L,B,W,H
# compute desired height in figure-relative coords
desired_height_px = 40
xform = fig.transFigure.inverted()
desired_height_rel = xform.transform([0, desired_height_px])[1]
# set the new height
ax_lower_pos[-1] = desired_height_rel
fig.axes[1].set_position(ax_lower_pos)
# adjust ax_upper accordingly
ax_lower_top = fig.axes[1].get_position().extents[-1] # L,B,R,T
ax_upper_pos = list(fig.axes[0].get_position().bounds) # L,B,W,H
# new bottom
new_upper_bottom = ax_lower_top + desired_height_rel
ax_upper_pos[1] = new_upper_bottom
# new height
ax_upper_top = fig.axes[0].get_position().extents[-1] # L,B,R,T
new_upper_height = ax_upper_top - new_upper_bottom
ax_upper_pos[-1] = new_upper_height
# set the new position
fig.axes[0].set_position(ax_upper_pos)
fig.canvas.draw()
这是用户调用fig = make_plot()时的输出:
现在如果用户调用fig.subplots_adjust,底部轴被挤压,底部和顶部轴之间的空间被挤压得更大(on_resize 监听器将它们都设置为 40px):
fig.subplots_adjust(top=0.7)
此时,抓住窗口的一角并拖动一点点就足以触发on_resize 侦听器并恢复我想要的(底部轴的固定像素高度和轴之间的空间),同时保持新的-原封不动地添加宽上边距:
如何在不手动触发调整大小事件的情况下获得该结果?据我所知,subplots_adjust 不会触发任何我可以监听的事件。
我认为问题在于ax.update_params() 使用从底层subplotspec 获取的figbox 更新轴位置(据我所知,在初始之后不会更新)人物创作?)。 (注意:update_params 是从 subplots_adjust 内部调用的,参见 here)。
【问题讨论】:
-
@ImportanceOfBeingErnest 调用
set_position的回调是python模块的一部分。subplots_adjust以后可能会或可能不会被用户调用(为标题腾出空间,或以其他方式自定义默认图形布局以用于出版物或演示文稿)。作为模块的贡献者,我可以更改回调的工作方式,但我无法控制用户,所以如果可能的话,我希望subplots_adjust(大多数用户都知道)按他们的预期工作。 -
不,
plt.show发生在模块中,在用户开始与绘图交互之前。 -
@ImportanceOfBeingErnest 我已经编辑了问题和示例代码,希望能让您更容易重现。
标签: matplotlib events subplot