From d0124a9f07d1f200efe5592afaedfa6bb8ea7dad Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Tue, 7 Apr 2026 17:39:55 +0100 Subject: [PATCH 1/2] perf: defer scipy imports to reduce import time Move scipy imports from module level to local function scope in convolver, delaunay interpolator, mask utilities, cholesky, and fnnls modules. This avoids loading scipy during `import autoarray`, cutting ~0.3s from the import floor in smoke tests. Co-Authored-By: Claude Opus 4.6 (1M context) --- autoarray/inversion/inversion/inversion_util.py | 3 ++- autoarray/inversion/mesh/interpolator/delaunay.py | 6 ++++-- autoarray/mask/mask_2d_util.py | 4 ++-- autoarray/operators/convolver.py | 3 ++- autoarray/util/cholesky_funcs.py | 5 ++++- autoarray/util/fnnls.py | 4 +++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/autoarray/inversion/inversion/inversion_util.py b/autoarray/inversion/inversion/inversion_util.py index 7c552c23..40045ed9 100644 --- a/autoarray/inversion/inversion/inversion_util.py +++ b/autoarray/inversion/inversion/inversion_util.py @@ -5,7 +5,6 @@ from autoarray.settings import Settings from autoarray import exc -from autoarray.util.fnnls import fnnls_cholesky def curvature_matrix_diag_via_psf_weighted_noise_from( @@ -281,6 +280,8 @@ def reconstruction_positive_only_from( try: + from autoarray.util.fnnls import fnnls_cholesky + return fnnls_cholesky( curvature_reg_matrix, (data_vector).T, diff --git a/autoarray/inversion/mesh/interpolator/delaunay.py b/autoarray/inversion/mesh/interpolator/delaunay.py index 5d241037..ea491a2b 100644 --- a/autoarray/inversion/mesh/interpolator/delaunay.py +++ b/autoarray/inversion/mesh/interpolator/delaunay.py @@ -1,6 +1,4 @@ import numpy as np -import scipy.spatial -from scipy.spatial import cKDTree, Delaunay, Voronoi from autoconf import cached_property @@ -12,6 +10,7 @@ def scipy_delaunay(points_np, query_points_np, areas_factor): """Compute Delaunay simplices (simplices_padded) and Voronoi areas in one call.""" + from scipy.spatial import Delaunay max_simplices = 2 * points_np.shape[0] @@ -182,6 +181,8 @@ def pix_indexes_for_sub_slim_index_delaunay_from( # Case 2: Outside → KDTree NN # --------------------------- if outside_mask.any(): + from scipy.spatial import cKDTree + tree = cKDTree(delaunay_points) _, idx = tree.query(data_grid[outside_mask], k=1) out[outside_mask, 0] = idx.astype(np.int32) @@ -202,6 +203,7 @@ def scipy_delaunay_matern(points_np, query_points_np): typically of shape (Q, 3), where each row gives the indices of the Delaunay mesh vertices ("pixels") associated with that query point. """ + from scipy.spatial import Delaunay max_simplices = 2 * points_np.shape[0] diff --git a/autoarray/mask/mask_2d_util.py b/autoarray/mask/mask_2d_util.py index e5d1ccc1..c13b97b1 100644 --- a/autoarray/mask/mask_2d_util.py +++ b/autoarray/mask/mask_2d_util.py @@ -1,6 +1,5 @@ import numpy as np import warnings -from scipy.ndimage import binary_dilation from typing import Tuple from autoarray import exc @@ -465,7 +464,6 @@ def min_false_distance_to_edge(mask: np.ndarray) -> Tuple[int, int]: from typing import Tuple import numpy as np -from scipy.ndimage import binary_dilation def required_shape_for_kernel( @@ -608,6 +606,8 @@ def blurring_mask_2d_from( ) # Pixels within kernel footprint of any unmasked pixel + from scipy.ndimage import binary_dilation + near_unmasked_padded = binary_dilation(unmasked_padded, structure=structure) near_unmasked = near_unmasked_padded[ pad_y : pad_y + mask_2d.shape[0], diff --git a/autoarray/operators/convolver.py b/autoarray/operators/convolver.py index 2a48b57a..b7705760 100644 --- a/autoarray/operators/convolver.py +++ b/autoarray/operators/convolver.py @@ -7,7 +7,6 @@ import numpy as np from pathlib import Path -import scipy from typing import Optional, Tuple, Union import warnings @@ -116,6 +115,8 @@ class determines how masked real-space data are embedded into a padded array, full_shape = tuple( s1 + s2 - 1 for s1, s2 in zip(mask_shape, self.kernel.shape_native) ) + import scipy.fft + fft_shape = tuple(scipy.fft.next_fast_len(s, real=True) for s in full_shape) self.fft_shape = fft_shape diff --git a/autoarray/util/cholesky_funcs.py b/autoarray/util/cholesky_funcs.py index bd211eeb..71323782 100644 --- a/autoarray/util/cholesky_funcs.py +++ b/autoarray/util/cholesky_funcs.py @@ -1,5 +1,4 @@ import numpy as np -from scipy import linalg import math import time from autoarray import numba_util @@ -46,6 +45,8 @@ def _cholupdate(U, x): def cholinsert(U, index, x): + from scipy import linalg + S = np.insert(np.insert(U, index, 0, axis=0), index, 0, axis=1) S[:index, index] = S12 = linalg.solve_triangular( @@ -70,6 +71,8 @@ def cholinsertlast(U, x): As in current Cholesky scheme implemented in fnnls, we only use this kind of insertion, so I separate it out from the `cholinsert`. """ + from scipy import linalg + index = U.shape[0] S = np.insert(np.insert(U, index, 0, axis=0), index, 0, axis=1) diff --git a/autoarray/util/fnnls.py b/autoarray/util/fnnls.py index 3f49c1f2..5e95d9b7 100644 --- a/autoarray/util/fnnls.py +++ b/autoarray/util/fnnls.py @@ -1,5 +1,4 @@ import numpy as np -from scipy import linalg as slg from autoarray.util.cholesky_funcs import cholinsertlast, choldeleteindexes @@ -27,6 +26,7 @@ def fnnls_cholesky( """ Similar to fnnls, but use solving the lstsq problem by updating Cholesky factorisation. """ + from scipy import linalg as slg lstsq = lambda A, x: slg.solve( A, @@ -147,6 +147,8 @@ def fix_constraint_cholesky(ZTx, s_chol, d, P, P_inorder, U, tolerance): # solve the lstsq problem by cho_solve if len(P_inorder): + from scipy import linalg as slg + # there could be a case where P_inorder is empty. s_chol[P_inorder] = slg.cho_solve((U, False), ZTx[P_inorder]) From a31da2b8f0cb8e3edf8b7ee69f554485a5f1540a Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Tue, 7 Apr 2026 18:32:42 +0100 Subject: [PATCH 2/2] perf: defer matplotlib.pyplot via wrapper functions in plot/utils Replace all module-level `import matplotlib.pyplot as plt` across plot files with `subplots()` and `get_cmap()` wrappers from plot/utils that import matplotlib lazily on first call. This prevents matplotlib from loading during `import autoarray`, deferring ~0.3s of import cost to first plot use. Co-Authored-By: Claude Opus 4.6 (1M context) --- autoarray/dataset/plot/imaging_plots.py | 7 ++-- .../dataset/plot/interferometer_plots.py | 7 ++-- autoarray/fit/plot/fit_imaging_plots.py | 5 +-- .../fit/plot/fit_interferometer_plots.py | 7 ++-- autoarray/inversion/plot/inversion_plots.py | 7 ++-- autoarray/inversion/plot/mapper_plots.py | 5 +-- autoarray/plot/array.py | 10 ++--- autoarray/plot/grid.py | 9 +++-- autoarray/plot/inversion.py | 7 ++-- autoarray/plot/utils.py | 38 +++++++++++++++---- autoarray/plot/yx.py | 7 ++-- 11 files changed, 63 insertions(+), 46 deletions(-) diff --git a/autoarray/dataset/plot/imaging_plots.py b/autoarray/dataset/plot/imaging_plots.py index 095c9704..53f6499c 100644 --- a/autoarray/dataset/plot/imaging_plots.py +++ b/autoarray/dataset/plot/imaging_plots.py @@ -1,8 +1,7 @@ from typing import Optional -import matplotlib.pyplot as plt -from autoarray.plot.utils import subplot_save, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, subplot_save, conf_subplot_figsize, tight_layout def subplot_imaging_dataset( @@ -51,7 +50,7 @@ def subplot_imaging_dataset( from autoarray.plot.array import plot_array - fig, axes = plt.subplots(3, 3, figsize=conf_subplot_figsize(3, 3)) + fig, axes = subplots(3, 3, figsize=conf_subplot_figsize(3, 3)) axes = axes.flatten() plot_array( @@ -172,7 +171,7 @@ def subplot_imaging_dataset_list( from autoarray.plot.array import plot_array n = len(dataset_list) - fig, axes = plt.subplots(n, 3, figsize=conf_subplot_figsize(n, 3)) + fig, axes = subplots(n, 3, figsize=conf_subplot_figsize(n, 3)) if n == 1: axes = [axes] for i, dataset in enumerate(dataset_list): diff --git a/autoarray/dataset/plot/interferometer_plots.py b/autoarray/dataset/plot/interferometer_plots.py index 87c751cd..359d55b1 100644 --- a/autoarray/dataset/plot/interferometer_plots.py +++ b/autoarray/dataset/plot/interferometer_plots.py @@ -1,12 +1,11 @@ import numpy as np from typing import Optional -import matplotlib.pyplot as plt from autoarray.plot.array import plot_array from autoarray.plot.grid import plot_grid from autoarray.plot.yx import plot_yx -from autoarray.plot.utils import subplot_save, hide_unused_axes, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, subplot_save, hide_unused_axes, conf_subplot_figsize, tight_layout from autoarray.structures.grids.irregular_2d import Grid2DIrregular @@ -39,7 +38,7 @@ def subplot_interferometer_dataset( use_log10 Apply log10 normalisation to image panels. """ - fig, axes = plt.subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) + fig, axes = subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) axes = axes.flatten() plot_grid(dataset.data.in_grid, ax=axes[0], title="Visibilities", xlabel="", ylabel="") @@ -117,7 +116,7 @@ def subplot_interferometer_dirty_images( use_log10 Apply log10 normalisation. """ - fig, axes = plt.subplots(1, 3, figsize=conf_subplot_figsize(1, 3)) + fig, axes = subplots(1, 3, figsize=conf_subplot_figsize(1, 3)) plot_array( dataset.dirty_image, diff --git a/autoarray/fit/plot/fit_imaging_plots.py b/autoarray/fit/plot/fit_imaging_plots.py index 298d6ccd..ae474e69 100644 --- a/autoarray/fit/plot/fit_imaging_plots.py +++ b/autoarray/fit/plot/fit_imaging_plots.py @@ -1,9 +1,8 @@ from typing import Optional -import matplotlib.pyplot as plt from autoarray.plot.array import plot_array -from autoarray.plot.utils import subplot_save, symmetric_vmin_vmax, hide_unused_axes, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, subplot_save, symmetric_vmin_vmax, hide_unused_axes, conf_subplot_figsize, tight_layout def subplot_fit_imaging( @@ -43,7 +42,7 @@ def subplot_fit_imaging( grid, positions, lines Optional overlays forwarded to every panel. """ - fig, axes = plt.subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) + fig, axes = subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) axes = axes.flatten() plot_array( diff --git a/autoarray/fit/plot/fit_interferometer_plots.py b/autoarray/fit/plot/fit_interferometer_plots.py index 15f29fe0..2cc805b9 100644 --- a/autoarray/fit/plot/fit_interferometer_plots.py +++ b/autoarray/fit/plot/fit_interferometer_plots.py @@ -1,11 +1,10 @@ import numpy as np from typing import Optional -import matplotlib.pyplot as plt from autoarray.plot.array import plot_array from autoarray.plot.yx import plot_yx -from autoarray.plot.utils import subplot_save, symmetric_vmin_vmax, hide_unused_axes, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, subplot_save, symmetric_vmin_vmax, hide_unused_axes, conf_subplot_figsize, tight_layout def subplot_fit_interferometer( @@ -40,7 +39,7 @@ def subplot_fit_interferometer( Not used here (UV-plane residuals are scatter plots); kept for API consistency. """ - fig, axes = plt.subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) + fig, axes = subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) axes = axes.flatten() uv = fit.dataset.uv_distances / 10**3.0 @@ -135,7 +134,7 @@ def subplot_fit_interferometer_dirty_images( residuals_symmetric_cmap Centre residual colour scale symmetrically around zero. """ - fig, axes = plt.subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) + fig, axes = subplots(2, 3, figsize=conf_subplot_figsize(2, 3)) axes = axes.flatten() plot_array( diff --git a/autoarray/inversion/plot/inversion_plots.py b/autoarray/inversion/plot/inversion_plots.py index e6e55ac5..0187caa4 100644 --- a/autoarray/inversion/plot/inversion_plots.py +++ b/autoarray/inversion/plot/inversion_plots.py @@ -4,12 +4,11 @@ from pathlib import Path from typing import Optional, Union -import matplotlib.pyplot as plt from autoconf import conf from autoarray.inversion.mappers.abstract import Mapper from autoarray.plot.array import plot_array -from autoarray.plot.utils import numpy_grid, numpy_lines, numpy_positions, subplot_save, hide_unused_axes, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, numpy_grid, numpy_lines, numpy_positions, subplot_save, hide_unused_axes, conf_subplot_figsize, tight_layout from autoarray.inversion.plot.mapper_plots import plot_mapper from autoarray.structures.arrays.uniform_2d import Array2D @@ -53,7 +52,7 @@ def subplot_of_mapper( """ mapper = inversion.cls_list_from(cls=Mapper)[mapper_index] - fig, axes = plt.subplots(3, 4, figsize=conf_subplot_figsize(3, 4)) + fig, axes = subplots(3, 4, figsize=conf_subplot_figsize(3, 4)) axes = axes.flatten() # panel 0: data subtracted @@ -279,7 +278,7 @@ def subplot_mappings( ) mapper.slim_indexes_for_pix_indexes(pix_indexes=pix_indexes) - fig, axes = plt.subplots(2, 2, figsize=conf_subplot_figsize(2, 2)) + fig, axes = subplots(2, 2, figsize=conf_subplot_figsize(2, 2)) axes = axes.flatten() # panel 0: data subtracted diff --git a/autoarray/inversion/plot/mapper_plots.py b/autoarray/inversion/plot/mapper_plots.py index 088d10c5..6e3d9e6b 100644 --- a/autoarray/inversion/plot/mapper_plots.py +++ b/autoarray/inversion/plot/mapper_plots.py @@ -1,11 +1,10 @@ import logging from typing import Optional -import matplotlib.pyplot as plt from autoarray.plot.array import plot_array from autoarray.plot.inversion import plot_inversion_reconstruction -from autoarray.plot.utils import numpy_grid, numpy_lines, subplot_save, conf_subplot_figsize, tight_layout +from autoarray.plot.utils import subplots, numpy_grid, numpy_lines, subplot_save, conf_subplot_figsize, tight_layout logger = logging.getLogger(__name__) @@ -114,7 +113,7 @@ def subplot_image_and_mapper( lines Lines to overlay on both panels. """ - fig, axes = plt.subplots(1, 2, figsize=conf_subplot_figsize(1, 2)) + fig, axes = subplots(1, 2, figsize=conf_subplot_figsize(1, 2)) plot_array( image, diff --git a/autoarray/plot/array.py b/autoarray/plot/array.py index 39c0e779..618c74eb 100644 --- a/autoarray/plot/array.py +++ b/autoarray/plot/array.py @@ -5,11 +5,9 @@ import os from typing import List, Optional, Tuple -import matplotlib.pyplot as plt import numpy as np -from matplotlib.colors import LogNorm, Normalize - from autoarray.plot.utils import ( + subplots, apply_extent, apply_labels, conf_figsize, @@ -29,7 +27,7 @@ def plot_array( array, - ax: Optional[plt.Axes] = None, + ax=None, # --- spatial metadata ------------------------------------------------------- extent: Optional[Tuple[float, float, float, float]] = None, # --- overlays --------------------------------------------------------------- @@ -158,7 +156,7 @@ def plot_array( owns_figure = ax is None if owns_figure: figsize = figsize or conf_figsize("figures") - fig, ax = plt.subplots(1, 1, figsize=figsize) + fig, ax = subplots(1, 1, figsize=figsize) else: fig = ax.get_figure() @@ -181,8 +179,10 @@ def plot_array( vmax_log = np.nanmax(clipped) if not np.isfinite(vmax_log) or vmax_log <= vmin_log: vmax_log = vmin_log * 10.0 + from matplotlib.colors import LogNorm norm = LogNorm(vmin=vmin_log, vmax=vmax_log) elif vmin is not None or vmax is not None: + from matplotlib.colors import Normalize norm = Normalize(vmin=vmin, vmax=vmax) else: norm = None diff --git a/autoarray/plot/grid.py b/autoarray/plot/grid.py index 01230344..6a109f61 100644 --- a/autoarray/plot/grid.py +++ b/autoarray/plot/grid.py @@ -6,10 +6,11 @@ from typing import Iterable, List, Optional, Tuple -import matplotlib.pyplot as plt import numpy as np from autoarray.plot.utils import ( + subplots, + get_cmap, apply_extent, apply_labels, conf_figsize, @@ -20,7 +21,7 @@ def plot_grid( grid, - ax: Optional[plt.Axes] = None, + ax=None, # --- errors ----------------------------------------------------------------- y_errors: Optional[np.ndarray] = None, x_errors: Optional[np.ndarray] = None, @@ -108,13 +109,13 @@ def plot_grid( owns_figure = ax is None if owns_figure: figsize = figsize or conf_figsize("figures") - fig, ax = plt.subplots(1, 1, figsize=figsize) + fig, ax = subplots(1, 1, figsize=figsize) else: fig = ax.get_figure() # --- scatter / errorbar ---------------------------------------------------- if color_array is not None: - cmap = plt.get_cmap(colormap) + cmap = get_cmap(colormap) colors = cmap((color_array - color_array.min()) / (np.ptp(color_array) or 1)) if y_errors is None and x_errors is None: diff --git a/autoarray/plot/inversion.py b/autoarray/plot/inversion.py index fa58b7a6..cd85dcec 100644 --- a/autoarray/plot/inversion.py +++ b/autoarray/plot/inversion.py @@ -6,17 +6,16 @@ from typing import List, Optional, Tuple -import matplotlib.pyplot as plt import numpy as np from matplotlib.colors import LogNorm, Normalize -from autoarray.plot.utils import apply_extent, apply_labels, conf_figsize, save_figure, _conf_imshow_origin +from autoarray.plot.utils import subplots, apply_extent, apply_labels, conf_figsize, save_figure, _conf_imshow_origin def plot_inversion_reconstruction( pixel_values: np.ndarray, mapper, - ax: Optional[plt.Axes] = None, + ax=None, # --- cosmetics -------------------------------------------------------------- title: str = "Reconstruction", xlabel: str = 'x (")', @@ -84,7 +83,7 @@ def plot_inversion_reconstruction( owns_figure = ax is None if owns_figure: figsize = figsize or conf_figsize("figures") - fig, ax = plt.subplots(1, 1, figsize=figsize) + fig, ax = subplots(1, 1, figsize=figsize) else: fig = ax.get_figure() diff --git a/autoarray/plot/utils.py b/autoarray/plot/utils.py index 8dcebc4b..232f493b 100644 --- a/autoarray/plot/utils.py +++ b/autoarray/plot/utils.py @@ -6,7 +6,6 @@ import os from typing import List, Optional, Tuple -import matplotlib.pyplot as plt import numpy as np logger = logging.getLogger(__name__) @@ -15,6 +14,20 @@ _FAST_PLOTS = os.environ.get("PYAUTO_FAST_PLOTS") == "1" +def subplots(*args, **kwargs): + """Lazy wrapper around ``plt.subplots`` that defers the matplotlib import.""" + import matplotlib.pyplot as plt + + return plt.subplots(*args, **kwargs) + + +def get_cmap(name): + """Lazy wrapper around ``plt.get_cmap`` that defers the matplotlib import.""" + import matplotlib.pyplot as plt + + return plt.get_cmap(name) + + def tight_layout(): """Call ``plt.tight_layout()`` unless fast-plot mode is active. @@ -24,6 +37,9 @@ def tight_layout(): """ if _FAST_PLOTS: return + + import matplotlib.pyplot as plt + plt.tight_layout() @@ -281,6 +297,8 @@ def set_with_color_values(ax, cmap, color_values, norm=None): def _output_mode_save(fig, filename): + import matplotlib.pyplot as plt + """If ``PYAUTOARRAY_OUTPUT_MODE=1``, save *fig* to a numbered file in ``./output_mode//`` and return ``True``. Otherwise return ``False`` so the caller can proceed with normal saving. @@ -335,6 +353,8 @@ def subplot_save(fig, output_path, output_filename, output_format=None): File format string, e.g. ``"png"`` or ``"pdf"``. ``"show"`` displays the figure interactively. ``None`` reads from config. """ + import matplotlib.pyplot as plt + if output_format is None: output_format = _conf_output_format() @@ -441,7 +461,7 @@ def conf_subplot_figsize(rows: int, cols: int) -> Tuple[int, int]: def apply_labels( - ax: plt.Axes, + ax, title: str = "", xlabel: str = "", ylabel: str = "", @@ -474,7 +494,7 @@ def apply_labels( def save_figure( - fig: plt.Figure, + fig, path: str, filename: str, format: str = None, @@ -505,6 +525,8 @@ def save_figure( dpi Resolution in dots per inch. """ + import matplotlib.pyplot as plt + if format is None: format = _conf_output_format() @@ -543,7 +565,7 @@ def save_figure( plt.close(fig) -def plot_visibilities_1d(vis, ax: plt.Axes, title: str = "") -> None: +def plot_visibilities_1d(vis, ax, title: str = "") -> None: """Plot the real and imaginary components of a visibilities array as 1D line plots. Draws two overlapping lines — one for the real part and one for the @@ -664,7 +686,7 @@ def _colorbar_tick_labels(tick_values: List[float], cb_unit: Optional[str] = Non def _apply_colorbar( mappable, - ax: plt.Axes, + ax, cb_unit: Optional[str] = None, is_subplot: bool = False, ) -> None: @@ -679,6 +701,8 @@ def _apply_colorbar( When ``True`` uses ``labelsize_subplot`` from config (default 16) instead of the single-figure ``labelsize`` (default 16). """ + import matplotlib.pyplot as plt + tick_values = _colorbar_tick_values(getattr(mappable, "norm", None)) cb = plt.colorbar( @@ -706,7 +730,7 @@ def _apply_colorbar( def _apply_contours( - ax: plt.Axes, + ax, array: np.ndarray, extent, use_log10: bool = False, @@ -879,7 +903,7 @@ def _arcsec_labels(ticks) -> List[str]: def apply_extent( - ax: plt.Axes, + ax, extent: Tuple[float, float, float, float], ) -> None: """ diff --git a/autoarray/plot/yx.py b/autoarray/plot/yx.py index e80f5476..cb397dae 100644 --- a/autoarray/plot/yx.py +++ b/autoarray/plot/yx.py @@ -6,16 +6,15 @@ from typing import List, Optional, Tuple -import matplotlib.pyplot as plt import numpy as np -from autoarray.plot.utils import apply_labels, conf_figsize, save_figure +from autoarray.plot.utils import subplots, apply_labels, conf_figsize, save_figure def plot_yx( y, x=None, - ax: Optional[plt.Axes] = None, + ax=None, # --- errors / extras -------------------------------------------------------- y_errors: Optional[np.ndarray] = None, x_errors: Optional[np.ndarray] = None, @@ -91,7 +90,7 @@ def plot_yx( owns_figure = ax is None if owns_figure: figsize = figsize or conf_figsize("figures") - fig, ax = plt.subplots(1, 1, figsize=figsize) + fig, ax = subplots(1, 1, figsize=figsize) else: fig = ax.get_figure()