How to "zoom out" a plot in matplotlib, keeping all the size ratios the same, but reducing the size in inches?

Question:

I’m using matplotlib for plots, and one problem I’m having is that the standard plot sizes appear to have ridiculously huge sizes (in inches). The default dpi value for MPL seems to be set at 100dpi, but plots get produced at sizes of several like 6+ inches. The problem is that if I save this as a pdf, the immediate size is much too large to put on a scientific paper (I’d rather have it be “column-sized” which would be like an inch or two of width).

However, if you directly specify the figsize like

fig, ax = plt.subplots(figsize=[2.,3.])

the font sizes and marker sizes stay the same size in inches, leading to relatively huge figure items and ugly graphics. What I would prefer is the same ratios that come up by default, but reduced to a different inch size.

There’s two ways around this that I know of. Either save the figure in the standard size (which is coming out to about 8 by 6 inches or something), and then scale it when inserting it into LaTeX. Or manually go through all the figure elements, and change the font sizes, marker sizes, and figure sizes to make it perfect.

In some cases you can’t do the former, and the latter is extremely tedious. I’d have to figure out for each figure element what the proper size is to keep it the same ratio as in the default.

So if there another quick option for changing figure size while also scaling everything from what it would be by default?

Asked By: Marses

||

Answers:

You might want to ask the journal if using width=columnwidth, e.g.,

includegraphics[width=columnwidth]{example-image}

is acceptable. Although this is a rescaling, it adapts to the current column
width so this might be sufficiently journal-friendly.

And if not, perhaps ask them (or other authors who have published in that
journal) for a sample of the LaTeX a typical paper uses to include a graphic, or
advice on how graphics are to be generated.

It might also be the case that the journal simply doesn’t want raster images to be
scaled up since that can make images look blurry. Scaling down may not be a
problem for raster images, and scaling non-raster images might not be a problem at all.


If all else fails, you could use LaTeX itself to rescale the pdf generated by
matplotlib. Below, the make_plot function (taken from the matplotlib example
gallery
) generates
/tmp/tex_demo.pdf. The rescale_pdf function rescales tex_demo.pdf and
writes the result to /tmp/tex_demo-scaled.pdf. The rescale_pdf function
calls pdflatex via the subprocess module.

Adjust the paperheight and paperwidth parameters in the LaTeX template

paperheight=2.25in, 
paperwidth=3in, 

to control the size of the rescaled pdf figure.


import subprocess
import os
import textwrap
import numpy as np
import matplotlib.pyplot as plt

def make_plot(filename):
    """https://matplotlib.org/users/usetex.html"""
    # Example data
    t = np.arange(0.0, 1.0 + 0.01, 0.01)
    s = np.cos(4 * np.pi * t) + 2

    # fig, ax = plt.subplots(figsize=(2, 3))

    plt.rc('text', usetex=True)
    plt.rc('font', family='serif')
    fig, ax = plt.subplots()
    ax.plot(t, s)

    ax.set_xlabel(r'textbf{time} (s)')
    ax.set_ylabel(r'textit{voltage} (mV)',fontsize=16)
    ax.set_title(r"TeX is Number "
              r"$displaystylesum_{n=1}^inftyfrac{-e^{ipi}}{2^n}$!",
              fontsize=16, color='gray')
    # Make room for the ridiculously large title.
    plt.subplots_adjust(top=0.8)

    plt.savefig(filename)

def rescale_pdf(filename):
    stub, ext = os.path.splitext(filename)
    print('begin rescale')
    template = textwrap.dedent(r'''
        documentclass{article}

        %% https://tex.stackexchange.com/a/46178/3919
        usepackage[
                paperheight=2.25in, 
                paperwidth=3in, 
                bindingoffset=0in, 
                left=0in,
                right=0in,
                top=0in,
                bottom=0in, 
                footskip=0in]{geometry}
        usepackage{graphicx}

        begin{document}
        pagenumbering{gobble}
        begin{figure}
        %% https://tex.stackexchange.com/questions/63221/how-to-deal-with-pdf-figures
        includegraphics[width=linewidth]{%s}
        end{figure}

        end{document}''' % (stub,))

    tex_filename = 'result.tex'
    with open(tex_filename, 'w') as f:
        f.write(template)

    proc = subprocess.Popen(['pdflatex', '-interaction', 'batchmode', tex_filename])
    output, err = proc.communicate()

filename = '/tmp/tex_demo.pdf'
dirname = os.path.dirname(filename)
if dirname: 
    os.chdir(dirname)
make_plot(filename)
rescale_pdf(filename)
Answered By: unutbu

Usually, it would be enough to set a different font-size for the complete script.

import matplotlib.pyplot as plt
plt.rcParams["font.size"] =7

Complete example:

import matplotlib.pyplot as plt
plt.rcParams["font.size"] =7


fig, ax = plt.subplots(figsize=[2.,3.], dpi=100)
ax.plot([2,4,1], label="label")
ax.set_xlabel("xlabel")
ax.set_title("title")
ax.text( 0.5,1.4,"text",)
ax.legend()

plt.tight_layout()
plt.savefig("figure.pdf", dpi="figure")
plt.savefig("figure.png", dpi="figure")
plt.show()

enter image description here
enter image description here

You can also fix the size of the plot as a whole by adding

plt.figure(figsize=(7, 5))

before you add any data to the plot. This line of code will create a new figure with the specific size you give it.

Answered By: Rey Abolofia