pnkraemer / tueplots

Figure sizes, font sizes, fonts, and more configurations at minimal overhead. Fix your journal papers, conference proceedings, and other scientific publications.
https://tueplots.readthedocs.io
MIT License
663 stars 25 forks source link

Tight(er) whitespace around figure when saving #101

Closed pnkraemer closed 2 years ago

pnkraemer commented 2 years ago

Resolves #100. When saving a figure via (e.g.) plt.savefig, there tends to be more whitespace around the figure than desired. This PR removes almost all whitespace. The rationale is that when embedding the figure into a paper/pdf, the paper-layout should handle the whitespace, not the figure itself.

Before: before.pdf

After: after.pdf

The padding value of 0.015 inches is a little ad-hoc (I personally found 0.01 too small and 0.02 too large, but :shrug:), and quite aggressive (removes almost all whitespace). But the value is exposed to users, and can therefore be changed easily.

daskol commented 8 months ago

I'm afraid that this issue introduced a regression: resulting media size differs from declared one.

import matplotlib as mpl
import matplotlib.pyplot as plt

def save_fig(what: str, rc: dict):
    with mpl.rc_context(rc):
        fig, ax = plt.subplots(figsize=(3.25, 2.01), layout='constrained')
        ax.plot([i ** 2 for i in range(10)], '-..', label=r'$x^2$')
        ax.legend()
        ax.set_xlabel(r'$x$')
        ax.set_ylabel(r'$f(x)$')
        fig.savefig(f'{what}.pdf')
        fig.savefig(f'{what}.png')
        fig.savefig(f'{what}.svg')

save_fig('standard', {'savefig.bbox': 'standard', 'savefig.pad_inches': 0.015})
save_fig('tight', {'savefig.bbox': 'tight', 'savefig.pad_inches': 0.015})

Then we get images with different size in pixels while DPI is the same and equals to 100.

$ file *.png
standard.png: PNG image data, 325 x 200, 8-bit/color RGBA, non-interlaced
tight.png:    PNG image data, 319 x 195, 8-bit/color RGBA, non-interlaced

Bounding boxes of generated PDFs differs too.

$ echo {standard,tight}.pdf | xargs -n1 pdfinfo | grep -i 'page size'       
Page size:       234 x 144.72 pts
Page size:       230.16 x 140.88 pts

From my perspective matplotlib documentation is a little bit vague and unclear at this point but it seems that savefig.bbox/bbox_inches tweak somehow shape of bounding box of Artist's on Figure and use it instead of bounding box of original canvas.

UPD I don't know what figsize and dpi was in your sample abut sizes of generated PDFs follow.

$ echo {before,after}.pdf | xargs -n1 pdfinfo | grep -i 'page size'
Page size:       494.4 x 158.582 pts
Page size:       482.16 x 146.342 pts
pnkraemer commented 8 months ago

I opened an issue based on your comment. Let's figure out a solution there :)