Module figprint
Expand source code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__all__ = ['PrintableFigure', 'custom_plt_figure', 'custom_plt_subplots', 'is_valid_figure', 'print_figure', 'print_pdf', 'print_png', 'print_svg']
"""
📁 figprint.py — Utilities for saving and displaying Matplotlib figures with printing options.
This module extends Matplotlib's `Figure` class by adding convenient methods to export
figures in PDF, PNG, and SVG formats. It also overrides `plt.figure` and `plt.subplots`
to return enhanced `PrintableFigure` objects by default.
Typical usage:
--------------
import matplotlib.pyplot as plt
from figprint import print_figure
# Automatically uses PrintableFigure
fig, ax = plt.subplots()
ax.plot([0, 1], [0, 1])
fig.print() # Saves to PNG and PDF
# Advanced control
fig.print_png("myplot", overwrite=True)
fig.print_svg("myplot", overwrite=True)
Example:
--------
# myplotmodule.py
from matplotlib import pyplot as plt
import figprint # Automatically patches pyplot
def example_plot():
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("Example Plot")
fig.print("example", overwrite=True)
Author: Generative Simulation Initiative/Olivier Vitrac, PhD
Created: 2025-05-12
"""
import os
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
_fig_metadata_atrr_ = "filename"
def is_valid_figure(fig):
"""
Check if `fig` is a valid and open Matplotlib figure.
Parameters:
fig (object): Any object to check.
Returns:
bool: True if the object is an open Matplotlib Figure.
"""
return isinstance(fig, Figure) and hasattr(fig, 'canvas') and fig.canvas is not None
def _generate_figname(fig, extension):
"""
Generate a cleaned filename using figure metadata or the current datetime.
Parameters:
fig (Figure): Matplotlib figure object.
extension (str): File extension (e.g. '.pdf').
Returns:
str: Cleaned filename with correct extension.
"""
if hasattr(fig, _fig_metadata_atrr_):
filename = getattr(fig, _fig_metadata_atrr_)
else:
filename = "fig" + datetime.now().strftime("%Y%m%d_%H%M%S")
filename = filename.strip().replace(" ", "_")
if not filename.lower().endswith(extension):
filename += extension
return filename
def _print_generic(fig, extension, filename, destinationfolder, overwrite, dpi):
"""
Generic saving logic for figure files.
Parameters:
fig (Figure): The figure to save.
extension (str): File extension (e.g. '.pdf').
filename (str): Optional filename.
destinationfolder (str): Folder path.
overwrite (bool): Overwrite existing file?
dpi (int): Resolution (ignored for SVG).
"""
if not is_valid_figure(fig):
print("no valid figure")
return
filename = filename or _generate_figname(fig, extension)
if not filename.endswith(extension):
filename += extension
filepath = os.path.join(destinationfolder, filename)
if not overwrite and os.path.exists(filepath):
print(f"File {filepath} already exists. Use overwrite=True to replace it.")
return
fig.savefig(filepath, format=extension.lstrip("."), dpi=None if extension == ".svg" else dpi, bbox_inches="tight")
print(f"Saved {extension.upper()[1:]}: {filepath}")
def print_pdf(fig, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300):
"""
Save a figure as a PDF.
Example:
--------
>>> fig, ax = plt.subplots()
>>> ax.plot([0, 1], [0, 1])
>>> print_pdf(fig, "myplot", overwrite=True)
"""
_print_generic(fig, ".pdf", filename, destinationfolder, overwrite, dpi)
def print_png(fig, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300):
"""
Save a figure as a PNG.
Example:
--------
>>> print_png(fig, "myplot", overwrite=True)
"""
_print_generic(fig, ".png", filename, destinationfolder, overwrite, dpi)
def print_svg(fig, filename="", destinationfolder=os.getcwd(), overwrite=False):
"""
Save a figure as an SVG (vector format, dpi-independent).
Example:
--------
>>> print_svg(fig, "myplot", overwrite=True)
"""
_print_generic(fig, ".svg", filename, destinationfolder, overwrite, dpi=None)
def print_figure(fig, filename="", destinationfolder=os.getcwd(), overwrite=False,
dpi={"png": 150, "pdf": 300, "svg": None}, what = ["pdf","png","svg"]):
"""
Save a figure as PDF, PNG, and SVG.
Example:
--------
>>> print_figure(fig, "full_output", overwrite=True)
Parameters:
fig (Figure): Figure to save.
filename (str): Optional base filename.
destinationfolder (str): Folder path.
overwrite (bool): Whether to overwrite existing files.
dpi (dict): Dictionary of resolution per format.
what (list): list what to print, default = ["pdf","png","svg"]
"""
if not isinstance(what,(list,tuple)):
what = [what]
if is_valid_figure(fig):
if "pdf" in what: print_pdf(fig, filename, destinationfolder, overwrite, dpi["pdf"])
if "png" in what: print_png(fig, filename, destinationfolder, overwrite, dpi["png"])
if "svg" in what: print_svg(fig, filename, destinationfolder, overwrite)
else:
print("no valid figure")
class PrintableFigure(Figure):
"""
Enhanced Matplotlib Figure with custom show and export methods.
Example:
--------
>>> fig, ax = plt.subplots()
>>> ax.plot([0, 1], [1, 0])
>>> fig.print("diag1") # Saves PDF, PNG, SVG
"""
def show(self, display_mode=None):
"""
Display figure intelligently based on context (Jupyter/script).
Parameters:
display_mode (str): 'auto' or 'classic' (default is 'auto').
"""
try:
get_ipython
if display_mode is None or display_mode == "auto":
display(self)
else:
super().show()
except NameError:
super().show()
def print(self, filename="", destinationfolder=os.getcwd(), overwrite=True,
dpi={"png": 150, "pdf": 300, "svg": None}):
"""
Save figure in PDF, PNG, and SVG formats.
Example:
--------
>>> fig.print("summary_figure")
"""
print_figure(self, filename, destinationfolder, overwrite, dpi)
def print_pdf(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300):
print_pdf(self, filename, destinationfolder, overwrite, dpi)
def print_png(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300):
print_png(self, filename, destinationfolder, overwrite, dpi)
def print_svg(self, filename="", destinationfolder=os.getcwd(), overwrite=False):
print_svg(self, filename, destinationfolder, overwrite)
# Save original constructor references
original_plt_figure = plt.figure
original_plt_subplots = plt.subplots
def custom_plt_figure(*args, **kwargs):
"""
Override `plt.figure()` to return PrintableFigure by default.
Returns:
PrintableFigure
"""
kwargs.setdefault("FigureClass", PrintableFigure)
return original_plt_figure(*args, **kwargs)
def custom_plt_subplots(*args, **kwargs):
"""
Override `plt.subplots()` to return PrintableFigure.
Returns:
(PrintableFigure, Axes)
"""
fig, ax = original_plt_subplots(*args, **kwargs)
fig.__class__ = PrintableFigure
return fig, ax
# Apply overrides globally
plt.figure = custom_plt_figure
plt.subplots = custom_plt_subplots
plt.FigureClass = PrintableFigure
plt.rcParams['figure.figsize'] = (8, 6)
Functions
def custom_plt_figure(*args, **kwargs)
-
Override
plt.figure()
to return PrintableFigure by default.Returns
PrintableFigure
Expand source code
def custom_plt_figure(*args, **kwargs): """ Override `plt.figure()` to return PrintableFigure by default. Returns: PrintableFigure """ kwargs.setdefault("FigureClass", PrintableFigure) return original_plt_figure(*args, **kwargs)
def custom_plt_subplots(*args, **kwargs)
-
Override
plt.subplots()
to return PrintableFigure.Returns
(PrintableFigure, Axes)
Expand source code
def custom_plt_subplots(*args, **kwargs): """ Override `plt.subplots()` to return PrintableFigure. Returns: (PrintableFigure, Axes) """ fig, ax = original_plt_subplots(*args, **kwargs) fig.__class__ = PrintableFigure return fig, ax
def is_valid_figure(fig)
-
Check if
fig
is a valid and open Matplotlib figure.Parameters
fig (object): Any object to check.
Returns
bool
- True if the object is an open Matplotlib Figure.
Expand source code
def is_valid_figure(fig): """ Check if `fig` is a valid and open Matplotlib figure. Parameters: fig (object): Any object to check. Returns: bool: True if the object is an open Matplotlib Figure. """ return isinstance(fig, Figure) and hasattr(fig, 'canvas') and fig.canvas is not None
def print_figure(fig, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False, dpi={'png': 150, 'pdf': 300, 'svg': None}, what=['pdf', 'png', 'svg'])
-
Save a figure as PDF, PNG, and SVG.
Example:
>>> print_figure(fig, "full_output", overwrite=True)
Parameters
fig (Figure): Figure to save. filename (str): Optional base filename. destinationfolder (str): Folder path. overwrite (bool): Whether to overwrite existing files. dpi (dict): Dictionary of resolution per format. what (list): list what to print, default = ["pdf","png","svg"]
Expand source code
def print_figure(fig, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi={"png": 150, "pdf": 300, "svg": None}, what = ["pdf","png","svg"]): """ Save a figure as PDF, PNG, and SVG. Example: -------- >>> print_figure(fig, "full_output", overwrite=True) Parameters: fig (Figure): Figure to save. filename (str): Optional base filename. destinationfolder (str): Folder path. overwrite (bool): Whether to overwrite existing files. dpi (dict): Dictionary of resolution per format. what (list): list what to print, default = ["pdf","png","svg"] """ if not isinstance(what,(list,tuple)): what = [what] if is_valid_figure(fig): if "pdf" in what: print_pdf(fig, filename, destinationfolder, overwrite, dpi["pdf"]) if "png" in what: print_png(fig, filename, destinationfolder, overwrite, dpi["png"]) if "svg" in what: print_svg(fig, filename, destinationfolder, overwrite) else: print("no valid figure")
def print_pdf(fig, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False, dpi=300)
-
Save a figure as a PDF. Example:
>>> fig, ax = plt.subplots() >>> ax.plot([0, 1], [0, 1]) >>> print_pdf(fig, "myplot", overwrite=True)
Expand source code
def print_pdf(fig, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): """ Save a figure as a PDF. Example: -------- >>> fig, ax = plt.subplots() >>> ax.plot([0, 1], [0, 1]) >>> print_pdf(fig, "myplot", overwrite=True) """ _print_generic(fig, ".pdf", filename, destinationfolder, overwrite, dpi)
def print_png(fig, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False, dpi=300)
-
Save a figure as a PNG.
Example:
>>> print_png(fig, "myplot", overwrite=True)
Expand source code
def print_png(fig, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): """ Save a figure as a PNG. Example: -------- >>> print_png(fig, "myplot", overwrite=True) """ _print_generic(fig, ".png", filename, destinationfolder, overwrite, dpi)
def print_svg(fig, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False)
-
Save a figure as an SVG (vector format, dpi-independent).
Example:
>>> print_svg(fig, "myplot", overwrite=True)
Expand source code
def print_svg(fig, filename="", destinationfolder=os.getcwd(), overwrite=False): """ Save a figure as an SVG (vector format, dpi-independent). Example: -------- >>> print_svg(fig, "myplot", overwrite=True) """ _print_generic(fig, ".svg", filename, destinationfolder, overwrite, dpi=None)
Classes
class PrintableFigure (figsize=None, dpi=None, *, facecolor=None, edgecolor=None, linewidth=0.0, frameon=None, subplotpars=None, tight_layout=None, constrained_layout=None, layout=None, **kwargs)
-
Enhanced Matplotlib Figure with custom show and export methods.
Example:
>>> fig, ax = plt.subplots() >>> ax.plot([0, 1], [1, 0]) >>> fig.print("diag1") # Saves PDF, PNG, SVG
Parameters
figsize
:2-tuple
offloats
, default: :rc:
figure.figsize``- Figure dimension
(width, height)
in inches. dpi
:float
, default: :rc:
figure.dpi``- Dots per inch.
facecolor
:default: :rc:
figure.facecolor``- The figure patch facecolor.
edgecolor
:default: :rc:
figure.edgecolor``- The figure patch edge color.
linewidth
:float
- The linewidth of the frame (i.e. the edge linewidth of the figure patch).
frameon
:bool
, default: :rc:
figure.frameon``- If
False
, suppress drawing the figure background patch. subplotpars
:~matplotlib.gridspec.SubplotParams
- Subplot parameters. If not given, the default subplot
parameters :rc:
figure.subplot.*
are used. tight_layout
:bool
ordict
, default: :rc:
figure.autolayout``-
Whether to use the tight layout mechanism. See
.set_tight_layout
.Discouraged
The use of this parameter is discouraged. Please use
layout='tight'
instead for the common case oftight_layout=True
and use.set_tight_layout
otherwise. constrained_layout
:bool
, default: :rc:
figure.constrained_layout.use``-
This is equal to
layout='constrained'
.Discouraged
The use of this parameter is discouraged. Please use
layout='constrained'
instead. layout
:{'constrained', 'compressed', 'tight', 'none',
.LayoutEngine, None}
, default: None
-
The layout mechanism for positioning of plot elements to avoid overlapping Axes decorations (labels, ticks, etc). Note that layout managers can have significant performance penalties.
- 'constrained': The constrained layout solver adjusts Axes sizes to avoid overlapping Axes decorations. Can handle complex plot layouts and colorbars, and is thus recommended.
See :ref:
constrainedlayout_guide
for examples.-
'compressed': uses the same algorithm as 'constrained', but removes extra space between fixed-aspect-ratio Axes. Best for simple grids of Axes.
-
'tight': Use the tight layout mechanism. This is a relatively simple algorithm that adjusts the subplot parameters so that decorations do not overlap.
See :ref:
tight_layout_guide
for examples.-
'none': Do not use a layout engine.
-
A
.LayoutEngine
instance. Builtin layout classes are.ConstrainedLayoutEngine
and.TightLayoutEngine
, more easily accessible by 'constrained' and 'tight'. Passing an instance allows third parties to provide their own layout engine.
If not given, fall back to using the parameters tight_layout and constrained_layout, including their config defaults :rc:
figure.autolayout
and :rc:figure.constrained_layout.use
.
Other Parameters
**kwargs
:.Figure</code> properties
, optional- Properties:
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image
alpha: scalar or None
animated: bool
canvas: FigureCanvas
clip_box:
~matplotlib.transforms.BboxBase
or None clip_on: bool clip_path: Patch or (Path, Transform) or None constrained_layout: unknown constrained_layout_pads: unknown dpi: float edgecolor: :mpltype:color
facecolor: :mpltype:color
figheight: float figure: unknown figwidth: float frameon: bool gid: str in_layout: bool label: object layout_engine: {'constrained', 'compressed', 'tight', 'none',.LayoutEngine
, None} linewidth: number mouseover: bool path_effects: list of.AbstractPathEffect
picker: None or bool or float or callable rasterized: bool size_inches: (float, float) or float sketch_params: (scale: float, length: float, randomness: float) snap: bool or None tight_layout: unknown transform:~matplotlib.transforms.Transform
url: str visible: bool zorder: float
Expand source code
class PrintableFigure(Figure): """ Enhanced Matplotlib Figure with custom show and export methods. Example: -------- >>> fig, ax = plt.subplots() >>> ax.plot([0, 1], [1, 0]) >>> fig.print("diag1") # Saves PDF, PNG, SVG """ def show(self, display_mode=None): """ Display figure intelligently based on context (Jupyter/script). Parameters: display_mode (str): 'auto' or 'classic' (default is 'auto'). """ try: get_ipython if display_mode is None or display_mode == "auto": display(self) else: super().show() except NameError: super().show() def print(self, filename="", destinationfolder=os.getcwd(), overwrite=True, dpi={"png": 150, "pdf": 300, "svg": None}): """ Save figure in PDF, PNG, and SVG formats. Example: -------- >>> fig.print("summary_figure") """ print_figure(self, filename, destinationfolder, overwrite, dpi) def print_pdf(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): print_pdf(self, filename, destinationfolder, overwrite, dpi) def print_png(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): print_png(self, filename, destinationfolder, overwrite, dpi) def print_svg(self, filename="", destinationfolder=os.getcwd(), overwrite=False): print_svg(self, filename, destinationfolder, overwrite)
Ancestors
- matplotlib.figure.Figure
- matplotlib.figure.FigureBase
- matplotlib.artist.Artist
Methods
def print(self, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=True, dpi={'png': 150, 'pdf': 300, 'svg': None})
-
Save figure in PDF, PNG, and SVG formats.
Example:
>>> fig.print("summary_figure")
Expand source code
def print(self, filename="", destinationfolder=os.getcwd(), overwrite=True, dpi={"png": 150, "pdf": 300, "svg": None}): """ Save figure in PDF, PNG, and SVG formats. Example: -------- >>> fig.print("summary_figure") """ print_figure(self, filename, destinationfolder, overwrite, dpi)
def print_pdf(self, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False, dpi=300)
-
Expand source code
def print_pdf(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): print_pdf(self, filename, destinationfolder, overwrite, dpi)
def print_png(self, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False, dpi=300)
-
Expand source code
def print_png(self, filename="", destinationfolder=os.getcwd(), overwrite=False, dpi=300): print_png(self, filename, destinationfolder, overwrite, dpi)
def print_svg(self, filename='', destinationfolder='/home/olivi/natacha/python/utils', overwrite=False)
-
Expand source code
def print_svg(self, filename="", destinationfolder=os.getcwd(), overwrite=False): print_svg(self, filename, destinationfolder, overwrite)
def set(self, *, agg_filter=<UNSET>, alpha=<UNSET>, animated=<UNSET>, canvas=<UNSET>, clip_box=<UNSET>, clip_on=<UNSET>, clip_path=<UNSET>, constrained_layout=<UNSET>, constrained_layout_pads=<UNSET>, dpi=<UNSET>, edgecolor=<UNSET>, facecolor=<UNSET>, figheight=<UNSET>, figwidth=<UNSET>, frameon=<UNSET>, gid=<UNSET>, in_layout=<UNSET>, label=<UNSET>, layout_engine=<UNSET>, linewidth=<UNSET>, mouseover=<UNSET>, path_effects=<UNSET>, picker=<UNSET>, rasterized=<UNSET>, size_inches=<UNSET>, sketch_params=<UNSET>, snap=<UNSET>, tight_layout=<UNSET>, transform=<UNSET>, url=<UNSET>, visible=<UNSET>, zorder=<UNSET>)
-
Set multiple properties at once.
Supported properties are
Properties
agg_filter: a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image alpha: scalar or None animated: bool canvas: FigureCanvas clip_box:
~matplotlib.transforms.BboxBase
or None clip_on: bool clip_path: Patch or (Path, Transform) or None constrained_layout: unknown constrained_layout_pads: unknown dpi: float edgecolor: :mpltype:color
facecolor: :mpltype:color
figheight: float figure: unknown figwidth: float frameon: bool gid: str in_layout: bool label: object layout_engine: {'constrained', 'compressed', 'tight', 'none',.LayoutEngine
, None} linewidth: number mouseover: bool path_effects: list of.AbstractPathEffect
picker: None or bool or float or callable rasterized: bool size_inches: (float, float) or float sketch_params: (scale: float, length: float, randomness: float) snap: bool or None tight_layout: unknown transform:~matplotlib.transforms.Transform
url: str visible: bool zorder: floatExpand source code
cls.set = lambda self, **kwargs: Artist.set(self, **kwargs)
def show(self, display_mode=None)
-
Display figure intelligently based on context (Jupyter/script).
Parameters
display_mode (str): 'auto' or 'classic' (default is 'auto').
Expand source code
def show(self, display_mode=None): """ Display figure intelligently based on context (Jupyter/script). Parameters: display_mode (str): 'auto' or 'classic' (default is 'auto'). """ try: get_ipython if display_mode is None or display_mode == "auto": display(self) else: super().show() except NameError: super().show()