From 9f65fad26a6262949feb8e5cf17cf882a42d08d6 Mon Sep 17 00:00:00 2001 From: Eirik Rolland Enger Date: Wed, 8 May 2024 08:34:52 +0200 Subject: [PATCH] feat(combine): reads font from the "font.serif" matplotlib param by default (#25) * feat(combine): reads font from the "font.serif" param by default This also adjusts the `convert` command to specify the DPI, allowing for much better control of the font size. The font size is also read from the matplotlib params. * test(combine): update font for easier testing * feat(combine): read DPI from matplotlib params * fix(combine): use dpi from figure if savefig is not set * docs(combine): update default description in the `using` method * test(combine): make tests pass --- cosmoplots/concat.py | 47 +++++++++++++++++++++++++++++++++++++++----- tests/test_concat.py | 4 +++- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/cosmoplots/concat.py b/cosmoplots/concat.py index 3fac01c..09bf301 100644 --- a/cosmoplots/concat.py +++ b/cosmoplots/concat.py @@ -2,11 +2,30 @@ # `Self` was introduced in 3.11, but returning the class type works from 3.7 onwards. from __future__ import annotations -import warnings +import logging import pathlib import subprocess import tempfile +import warnings +from contextlib import contextmanager + +import matplotlib.pyplot as plt +from matplotlib.font_manager import FontProperties, findfont + + +@contextmanager +def _ignore_logging_context(): + loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict] + # turn loggers off + for logger in loggers: + logger.disabled = True + logging.root.disabled = True + yield + # turn loggers back on + for logger in loggers: + logger.disabled = False + logging.root.disabled = False class Combine: @@ -14,12 +33,19 @@ class Combine: def __init__(self) -> None: self._gravity = "northwest" - self._fontsize = 100 self._pos = (10.0, 10.0) - self._font = "Times-New-Roman" + with _ignore_logging_context(): + font = findfont(FontProperties(family=plt.rcParams["font.serif"])) + self._font = font + self._fontsize = int(plt.rcParams["font.size"]) self._color = "black" self._ft: str = ".png" self._output = pathlib.Path(f"output{self._ft}") + self._dpi = ( + plt.rcParams["savefig.dpi"] + if isinstance(plt.rcParams["savefig.dpi"], float) + else plt.rcParams["figure.dpi"] + ) self._files: list[pathlib.Path] = [] self._labels: list[str] = [] self._w: int | None = None @@ -67,7 +93,8 @@ def using( The type of font to use, default is Times New Roman. See `convert -list font` for a list of available fonts. fontsize : int, optional - The size of the font in pointsize. Default is `100`. + The size of the font in pointsize. Default is to use the "font.size" field + in the matplotlib rcParams. color : str, optional The color of the text. Default is `black`. """ @@ -132,14 +159,20 @@ def _create_labels(self) -> list[str]: count += 1 return characters - def save(self, output: pathlib.Path | str | None = None) -> None: + def save( + self, output: pathlib.Path | str | None = None, dpi: float | int | None = None + ) -> None: """Save the combined images as a png file. Parameters ---------- output : pathlib.Path | str, optional Give the name of the output file, default is `output.png`. + dpi : float | int, optional + The resolution that the input files were saved with. Default is the same as + the matplotlib savefig dpi. """ + self._dpi = dpi or self._dpi self._check_params_before_save(output) self._check_cli_available() self._run_subprocess() @@ -198,7 +231,11 @@ def _run_subprocess(self) -> None: subprocess.call( [ "convert", + "-units", + "PixelsPerInch", file, + "-density", + str(self._dpi), "-font", self._font, "-pointsize", diff --git a/tests/test_concat.py b/tests/test_concat.py index 9f401a2..0ddcd65 100644 --- a/tests/test_concat.py +++ b/tests/test_concat.py @@ -33,7 +33,9 @@ def test_convert_help() -> None: def test_help(capfd) -> None: """Test the `help` method.""" - cosmoplots.Combine().help() + # By default, the '.ttf' file is specified, but that's hard to test against. + plt.rcParams["font.size"] = 100 + cosmoplots.Combine().using(font="Times-New-Roman").help() out, err = capfd.readouterr() help = ( "To create images with labels:\n"