首页 > 解决方案 > Matplotlib 表格布局问题

问题描述

我正在尝试在 A4 报告中放置一张大表。pyplot.show() 呈现整个表格可见的布局。但是, pyplot.savefig() 会生成一个 pdf,其中表格被图形隐藏。(隐藏表格的 pdf 示例)我想让 pdf 显示整个表格而不是隐藏它。请参阅下面的代码以获取问题的摘要。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import TextBox


def BadTable(savefile: str):
    fig = plt.figure(constrained_layout=True, figsize=(8.27, 11.69)) #A4 size                                                                                                                                      
    fig.suptitle('Title')

    gs = GridSpec(3, 1, figure=fig)
    ax_desc = fig.add_subplot(gs[0, :])
    ax_table = fig.add_subplot(gs[1, :])
    ax_graph = fig.add_subplot(gs[2, :])

    #Description box                                                                                                                                                                                               
    TextBox(ax_desc, '', initial='Hello world')

    #Table                                                                                                                                                                                                         
    ax_table.tick_params(labelbottom=False, labelleft=False)

    nums = np.random.randint(0, 10, (30,10))
    ax_table.table(cellText=nums, colLabels=range(10), loc='center')
    ax_table.axis('off')
    ax_table.axis('tight')

    ax_graph.plot(range(20), range(20))

    if savefile is None:
        plt.show()
    elif type(savefile) is str:
        plt.savefig(savefile)
    else:
        raise Exception()

#Table fits                                                                                                                                                                                                        
BadTable(None)

#Table does not fit                                                                                                                                                                                                
BadTable('badpdf.pdf')

标签: pythonmatplotlib

解决方案


首先我想提一下,产生最佳外观结果的行为不一定是“正确的”。因此,我通常建议坚持使用@Patol 答案中的解决方案,该解决方案在理论上也给出了“正确”的行为。

关于这个问题,在 constrained_layout 和表格单元格高度优化之间存在着有趣的相互作用。

看到这一点,让我们constrained_layout关掉。(还要使绘图半透明以查看表格与绘图重叠并为其设置背景颜色以查看其范围。)

然后比较constrained_layout=True(右侧)

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import TextBox


def BadTable(savefile: str):
    fig = plt.figure(constrained_layout=False, figsize=(8.27, 11.69)) #A4 size                                                                                                                                      
    fig.suptitle('Title')

    gs = GridSpec(3, 1, figure=fig)
    ax_desc = fig.add_subplot(gs[0, :])
    ax_table = fig.add_subplot(gs[1, :])
    ax_graph = fig.add_subplot(gs[2, :])

    #Description box                                                                                                                                                                                               
    TextBox(ax_desc, '', initial='Hello world')

    #Table                                                                                                                                                                                                         
    ax_table.tick_params(labelbottom=False, labelleft=False)

    nums = np.random.randint(0, 10, (30,10))
    ax_table.table(cellText=nums, colLabels=range(10), loc='center')
    ax_table.axis('off')
    ax_graph.patch.set_alpha(0.7)

    ax_graph.plot(range(20), range(20))

    if savefile is None:
        plt.show()
    elif type(savefile) is str:
        plt.savefig(savefile)
    else:
        raise Exception()

#Table does not fit                                                                                                                                                                                                
BadTable('badpdf.png')

plt.show()

现在受约束的布局已经根据表格的原始扩展为图中的元素分配了空间。带有表格的轴已获得更多空间。但是,现在拥有更多空间的表会自行扩展,因为它认为它可以使用该空间。这导致它再次重叠。

你能做的就是重申这一点。给定额外的空间,让 constrained_layout 再次优化空间,再次绘制图形,

fig.canvas.draw()

现在,额外空间的数量将少于第一步。因此该表将不再增长,而是重新分配给它的空间。(剩下)

再次重申它,即添加第二个调用fig.canvas.draw()将最终让竞争条件收敛。(正确的)

draw()因此,一种可能的解决方案是在再次绘制之前至少调用两次以进行最终保存

fig.canvas.draw()
fig.canvas.draw()
fig.savefig(savefile)

鉴于上述情况,我们现在可以回答这个问题:为什么plt.show()显示看似正确的数字?
因为在 GUI 窗口内显示的图形大于屏幕会导致图形需要调整大小。每个调整大小步骤都需要重新绘制图形。因此,基本上您将获得至少一个额外的绘制步骤,并且我们在上面已经看到,这种额外的绘制步骤将具有调整桌子高度的效果,从而不会发生重叠。


推荐阅读