Figure Size#

Let’s explore how to use the FigureScale class to create precisely sized figures. We first need to import the packages:

import matplotlib.pyplot as plt
import figure_scale as fs
import math  # this is used to get demonstration data

FigureScale Object#

The FigureScale class is the core component of the library. It allows you to define figure dimensions in different ways:

  1. Width and Height: Specify both dimensions explicitly

  2. Width and Aspect Ratio: Specify width and let height be calculated from aspect ratio

  3. Height and Aspect Ratio: Specify height and let width be calculated from aspect ratio

All dimensions can be specified in various units. Let’s explore each approach:

size_a = fs.FigureScale(units="mm", width=100, height=100)
size_b = fs.FigureScale(units="mm", width=100, aspect=1.0)
size_c = fs.FigureScale(units="mm", height=100, aspect=1.0)

Providing all width, height, and aspect arguments will raise an ValueError, the same will happen if any of them is small than or equal to zero.

The available units are:

unit_mapping = fs.UnitConversionMapping()
", ".join(unit_mapping.keys())
'in, ft, yd, m, cm, mm, pt'

Check Unit Conversion for examples on how to add user provided units if needed.

FigureScale is set as a frozen dataclass to ensure constancy and immutability after its creation. The replace method allows you to create a new instance with modified attributes, whenever convenient:

size_a.replace(width=200)
FigureScale(units='mm', width=200, height=100, aspect=None)
size_a.replace(units="cm")
FigureScale(units='cm', width=10.0, height=10.0, aspect=None)

Notice arguments not provided to replace will be copied from the original instance. Remember just two out of width, height, and aspect can be provided at a time, so disable one of them by setting it to None if you need to set the third one:

size_a.replace(height=None, aspect=2.0)
FigureScale(units='mm', width=100, height=None, aspect=2.0)

Using FigureScale with Matplotlib#

Now let’s explore the different ways to use FigureScale with matplotlib figures. Under the hood, FigureScale implements the Sequence interface allowing it to be used as a tuple-like object for the figure.figsize parameter in matplotlib. The values on such sequence are always in inches, as expected by matplotlib.

First, let’s create a figure size and some demo data to demonstrate the different ways to apply figure scaling:

demo_figure_size = fs.FigureScale(units="mm", width=100, height=100)
x = [i * math.pi / 180 for i in range(0, 360, 10)]
y = [math.sin(i) for i in x]

Set as Default#

You can set the figure scale as the default size for all figures by modifying matplotlib’s rcParams:

plt.rcParams["figure.figsize"] = demo_figure_size

or just by using the set_as_default method:

demo_figure_size.set_as_default()

Any new figure created after this will use the specified size by default:

plt.plot(x, y);
../_images/c32165275d5f284d0bbd3ad1f39f5ac93dd8b7f646d160d8d8e9db1da64eee52.png

Set per Figure#

You can pass the FigureScale object directly to matplotlib functions that accept a figsize parameter:

fig, ax = plt.subplots(figsize=demo_figure_size)
ax.plot(x, y);
../_images/c32165275d5f284d0bbd3ad1f39f5ac93dd8b7f646d160d8d8e9db1da64eee52.png

Change it Locally#

You can use the FigureScale object as a callable to create a context manager that temporarily sets the figure size for the duration of the with block:

with demo_figure_size():
    plt.plot(x, y)
../_images/c32165275d5f284d0bbd3ad1f39f5ac93dd8b7f646d160d8d8e9db1da64eee52.png

As a syntax sugar, you can pass extra keyword arguments that are forwarded to matplotlib.pyplot.rc_context, for instance:

with demo_figure_size(**{"axes.grid": True}):
    plt.plot(x, y)
../_images/47adebe17b250f1c7e070a7e371dabb281bd71f54b691a190aa24dbfded5da61.png

In a similar fashion, you can call the FigureScale object and use it as a decorator to apply the figure size to a function:

@demo_figure_size()
def plot_demo_figure():
    plt.plot(x, y)


plot_demo_figure()
../_images/c32165275d5f284d0bbd3ad1f39f5ac93dd8b7f646d160d8d8e9db1da64eee52.png

Extra keyword arguments are also forwarded to matplotlib.pyplot.rc_context, for instance:

@demo_figure_size(**{"axes.grid": True})
def plot_demo_figure():
    plt.plot(x, y)


plot_demo_figure()
../_images/47adebe17b250f1c7e070a7e371dabb281bd71f54b691a190aa24dbfded5da61.png