Joa*_*uin 7 python pdf matplotlib figure
我想使用 python 创建一个用于打印的多页 PDF 文件。我更喜欢使用可以在任何环境下正常工作的库来完成此操作,因此我尝试使用matplotlib。
\n\n我可以制作所需的A4尺寸的图形,并创建一个多页PDF文件,但图形艺术家缩小并且不占据整个页面。
\n\n我可以生成 A4 大小页面的 PDF,并在图形周围进行填充,也可以生成页面尺寸较小的 PDF 文件(页面在图形周围缩小以删除填充,而图形保持相同大小)。
\n\n有人可以帮忙吗?
\n\n(我不认为这是重复的,还有其他关于填充的问题,但与我的目标不同,而且我看不到任何对我有用的答案 - 我已经搜索了好几天了!)
\n\n到目前为止,我在一些问题/答案之后尝试过的是:
\n\nbbox_inches=\'tight\', pad_inches=0在该函数中使用pyplot.savefig(),可提供小于 A4 且无填充的 PDF 页面。(奇怪的是,这对于 EPS 格式效果很好,它可以直接打印成 A4 纸的实际尺寸,但我不知道如何用它制作多页文件。)
\n\n如果我不使用bbox_inches=\'tight\', pad_inches=0,图形大小看起来或多或少相同,但周围的填充填充了 A4 页面的空间。
使用fig.tight_layout(rect=[0,0,1,1])或fig.tight_layout(pad=0),保留填充。
此示例代码生成 EPS(A4 无填充)、PDF(A4 有填充)和 TIFF(无填充但尺寸较小,因此打印时有填充)的图形:
\n\nimport matplotlib.pyplot as plt\nfrom matplotlib import gridspec\n\ndef plot_form_page():\n    # A4 canvas\n    fig_width_cm = 21                                # A4 page\n    fig_height_cm = 29.7\n    inches_per_cm = 1 / 2.54                         # Convert cm to inches\n    fig_width = fig_width_cm * inches_per_cm         # width in inches\n    fig_height = fig_height_cm * inches_per_cm       # height in inches\n    fig_size = [fig_width, fig_height]\n\n    plt.rc(\'text\', usetex=False) # so that LaTeX is not needed when creating a PDF with PdfPages later on\n    fig = plt.figure()\n    fig.set_size_inches(fig_size)\n    fig.set_facecolor(\'#9999ff\')\n\n    gs = gridspec.GridSpec(29, 21, wspace=0.1, hspace=0.1)    \n\n    # external axis\n    ax0 = fig.add_subplot(gs[:, :])\n    # for side in ["top", "bottom", "left", "right"]:\n    #     ax0.spines[side].set_visible(False)\n\n    # header\n    ax1 = fig.add_subplot(gs[1:4, 1:4])\n    ax1.set_facecolor(\'#bbffbb\')\n\n    ax2 = fig.add_subplot(gs[1:4, 4:-6])\n    ax2.set_facecolor(\'#ffbbff\')\n\n    ax3 = fig.add_subplot(gs[1:4, -6:-1])\n    ax3.set_facecolor(\'#00bbff\')\n\n    # form\n    ax4, ax5, ax6, ax7   = [fig.add_subplot(gs[ 5+(i*6):10+(i*6), 1:10]) for i in range(4)]    \n    [ax8, ax9, ax10, ax11] = [fig.add_subplot(gs[ 5+(i*6):10+(i*6), 11:20]) for i in range(4)]\n    axes = [ax4, ax8, ax5, ax9, ax6, ax10, ax7, ax11]\n    for ax in axes:\n        ax.set_facecolor(\'#bbbbbb\')\n\n    for ax in fig.axes:\n        ax.set_xticks([])\n        ax.set_yticks([])\n\n    print(fig.properties()[\'figwidth\'], fig.properties()[\'figheight\'])\n\n    # from previous tests:\n    #fig.tight_layout(pad=0)\n\nplot_form_page()\n\nplt.savefig(\'page.tiff\',\n            dpi=300,\n            orientation=\'portrait\',\n            box_inches=\'tight\', pad_inches=0)\nplt.savefig(\'page.pdf\',\n            dpi=300,\n            orientation=\'portrait\',\n            bbox_inches=\'tight\', pad_inches=0)\nplt.savefig(\'page.eps\',\n            dpi=300,\n            orientation=\'portrait\',\n            papertype=\'a4\',\n            bbox_inches=\'tight\', pad_inches=0)\nFig.properties() 给出 A4 的正确尺寸(以英寸为单位):
\n\nfig.properties()[\'figwidth\']\nfig.properties()[\'figheight\']\n8.26771653543307 11.69291338582677
\n\n但在打印时,数字会缩小以允许填充
\n\n您可以在此处查看 PDF 文件中的效果:
\n\nhttps://www.dropbox.com/s/naqy9vj4ht6g2mv/Screenshot%202019-04-16%20at%2011.46.48.png?dl=0
\n\n使用 EPS 就不成问题了:
\n\nhttps://www.dropbox.com/s/umycd8ofwod3nk5/Screenshot%202019-04-16%20at%2012.05.52.png?dl=0
\n\n(但同样,我不知道如何创建多页 EPS)
\n\n对于 TIFF 文件,我得到相同的结果:
\n\nhttps://www.dropbox.com/s/eid1zstbm954121/Screenshot%202019-04-16%20at%2012.11.59.png?dl=0
\n\n这不一定是因为打印软件添加了填充 - 现在的数字实际上更小,因为在 300dpi 下它是 1929\xe2\x80\x8a\xc3\x97\xe2\x80\x8a2655 像素,这使得它为 6.43 \xc3 \x97 8.85 英寸 - 肯定比 A4 小。
\n\n编辑:当然,这可以通过使用“适合页面”选项进行打印来解决,但这可以适用于任何具有A4比例的图像,如果可能的话,我想控制尺寸。
\n感谢@ImportanceOfBeingErnest的评论,以及一些尝试和错误,我找到了一个解决方案,创建一个A4形状的图形,当保存为A4 PDF页面时,它占据整个页面(不是100%正确,有边际很小,但它达到了目的)。
只需要添加gs.tight_layout(fig, pad=0). 我不完全明白为什么,但我怀疑当我试图消除对象的填充figure(使用plt.savefig(..., bbox_inches='tight', pad_inches=0)或fig.tight_layout(...))时,图形可能会到达 A4 页面的边框,但不会GridSpec,所以我看到的填充是在GridSpec和 的边界之间figure,而不是在纸张的边界之间。GridSpec当和之间的填充figure设置为 0,并且figure具有 A4 尺寸时,事情似乎按我想要的方式工作。
(我仍然不明白为什么在某些情况下 PDF 文件的页面会缩小,但我将把它留在这里)。
这是执行我想要的操作的代码,如果您创建 PDF 文件,打开并检查属性,尺寸为 A4,矩形靠近边框。对于其他选项,要么是宽边距,要么是较小的页面尺寸。
import matplotlib.pyplot as plt
from matplotlib import gridspec
def plot_form_page():
    # A4 canvas
    fig_width_cm = 21                                # A4 page
    fig_height_cm = 29.7
    inches_per_cm = 1 / 2.54                         # Convert cm to inches
    fig_width = fig_width_cm * inches_per_cm         # width in inches
    fig_height = fig_height_cm * inches_per_cm       # height in inches
    fig_size = [fig_width, fig_height]
    plt.rc('text', usetex=False) # so that LaTeX is not needed when creating a PDF with PdfPages later on
    fig = plt.figure()
    fig.set_size_inches(fig_size)
    fig.set_facecolor('#9999ff')
    gs = gridspec.GridSpec(29, 21, wspace=0.1, hspace=0.1)    
    # external axis
    ax0 = fig.add_subplot(gs[:, :])
    # for side in ["top", "bottom", "left", "right"]:
    #     ax0.spines[side].set_visible(False)
    # header
    ax1 = fig.add_subplot(gs[1:4, 1:4])
    ax1.set_facecolor('#bbffbb')
    ax2 = fig.add_subplot(gs[1:4, 4:-6])
    ax2.set_facecolor('#ffbbff')
    ax3 = fig.add_subplot(gs[1:4, -6:-1])
    ax3.set_facecolor('#00bbff')
    # form
    ax4, ax5, ax6, ax7   = [fig.add_subplot(gs[ 5+(i*6):10+(i*6), 1:10]) for i in range(4)]    
    [ax8, ax9, ax10, ax11] = [fig.add_subplot(gs[ 5+(i*6):10+(i*6), 11:20]) for i in range(4)]
    axes = [ax4, ax8, ax5, ax9, ax6, ax10, ax7, ax11]
    for ax in axes:
        ax.set_facecolor('#bbbbbb')
    for ax in fig.axes:
        ax.set_xticks([])
        ax.set_yticks([])
    #print(fig.properties()['figwidth'], fig.properties()['figheight'])
    gs.tight_layout(fig, pad=0)
plot_form_page()
plt.savefig('page.pdf',
            dpi=300,
            orientation='portrait')