From a92e294ebb6a4471a4d9abf5670f055b815ed4f4 Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Sun, 18 May 2025 01:13:33 +0200 Subject: [PATCH 1/8] Add support for pgf.documentclass rcParam --- lib/matplotlib/__init__.py | 1 + lib/matplotlib/backends/backend_pgf.py | 4 +++- lib/matplotlib/rcsetup.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 9abc6c5a84dd..f52baec79cbf 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -958,6 +958,7 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): # Strip leading comment. transform=lambda line: line[1:] if line.startswith("#") else line, fail_on_error=True) +rcParamsDefault["pgf.documentclass"] = "article" rcParamsDefault._update_raw(rcsetup._hardcoded_defaults) rcParamsDefault._ensure_has_backend() diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 48b6e8ac152c..bc4f50d6dfa2 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -29,7 +29,9 @@ _log = logging.getLogger(__name__) -_DOCUMENTCLASS = r"\documentclass{article}" +_DOCUMENTCLASS = ( + rf"\documentclass{{{mpl.rcParams.get('pgf.documentclass', 'article')}}}" +) # Note: When formatting floating point values, it is important to use the diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index ce29c5076100..30caac62a872 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1336,6 +1336,7 @@ def _convert_validator_spec(key, conv): "pgf.texsystem": ["xelatex", "lualatex", "pdflatex"], # latex variant used "pgf.rcfonts": validate_bool, # use mpl's rc settings for font config "pgf.preamble": validate_string, # custom LaTeX preamble + "pgf.documentclass": validate_string, # LaTeX document class used by PGF backend # write raster image data into the svg file "svg.image_inline": validate_bool, From 8ca8f2dd4c1d365a1226a8dbc0528e5a02ef4844 Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Sun, 18 May 2025 15:40:40 +0200 Subject: [PATCH 2/8] Add pgf.documentclass default to matplotlibrc template --- lib/matplotlib/mpl-data/matplotlibrc | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc index acb131c82e6c..3317c7a3ff0b 100644 --- a/lib/matplotlib/mpl-data/matplotlibrc +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -762,6 +762,7 @@ #pgf.rcfonts: True #pgf.preamble: # See text.latex.preamble for documentation #pgf.texsystem: xelatex +#pgf.documentclass: article ### docstring params #docstring.hardcopy: False # set this when you want to generate hardcopy docstring From 7bbd8ae39ebbad2c648b4aae659cf3245c74972a Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Sun, 18 May 2025 17:19:09 +0200 Subject: [PATCH 3/8] Refactor _DOCUMENTCLASS variable to inline pgf.documentclass access --- lib/matplotlib/backends/backend_pgf.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index bc4f50d6dfa2..fc047f6c4b27 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -29,11 +29,6 @@ _log = logging.getLogger(__name__) -_DOCUMENTCLASS = ( - rf"\documentclass{{{mpl.rcParams.get('pgf.documentclass', 'article')}}}" -) - - # Note: When formatting floating point values, it is important to use the # %f/{:f} format rather than %s/{} to avoid triggering scientific notation, # which is not recognized by TeX. @@ -207,7 +202,7 @@ class LatexManager: @staticmethod def _build_latex_header(): latex_header = [ - _DOCUMENTCLASS, + rf"\documentclass{{{mpl.rcParams.get('pgf.documentclass', 'article')}}}", # Include TeX program name as a comment for cache invalidation. # TeX does not allow this to be the first line. rf"% !TeX program = {mpl.rcParams['pgf.texsystem']}", @@ -836,7 +831,8 @@ def print_pdf(self, fname_or_fh, *, metadata=None, **kwargs): self.print_pgf(tmppath / "figure.pgf", **kwargs) (tmppath / "figure.tex").write_text( "\n".join([ - _DOCUMENTCLASS, + rf"\documentclass{{{mpl.rcParams.get( + 'pgf.documentclass', 'article')}}}", r"\usepackage[pdfinfo={%s}]{hyperref}" % pdfinfo, r"\usepackage[papersize={%fin,%fin}, margin=0in]{geometry}" % (w, h), @@ -933,7 +929,7 @@ def _write_header(self, width_inches, height_inches): pdfinfo = ','.join( _metadata_to_str(k, v) for k, v in self._info_dict.items()) latex_header = "\n".join([ - _DOCUMENTCLASS, + rf"\documentclass{{{mpl.rcParams.get('pgf.documentclass', 'article')}}}", r"\usepackage[pdfinfo={%s}]{hyperref}" % pdfinfo, r"\usepackage[papersize={%fin,%fin}, margin=0in]{geometry}" % (width_inches, height_inches), From db774e3a7d66b02834db462b3a0cfd9e417b02d4 Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Mon, 19 May 2025 00:18:32 +0200 Subject: [PATCH 4/8] doc: new pgf.documentclass rcParam and add release note --- doc/users/next_whats_new/pgf-documentclass.rst | 9 +++++++++ galleries/users_explain/text/pgf.py | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 doc/users/next_whats_new/pgf-documentclass.rst diff --git a/doc/users/next_whats_new/pgf-documentclass.rst b/doc/users/next_whats_new/pgf-documentclass.rst new file mode 100644 index 000000000000..ecc9d93fb1cb --- /dev/null +++ b/doc/users/next_whats_new/pgf-documentclass.rst @@ -0,0 +1,9 @@ +PGF backend: new rcParam `pgf.documentclass` +============================================ + +A new rcParam `pgf.documentclass` has been added to allow users to override +the default LaTeX document class (`article`) used by the PGF backend. + +This enables better compatibility when including PGF figures in documents that +use custom LaTeX classes like `IEEEtran` or others, avoiding layout +issues like incorrect font sizes or spacing mismatches. diff --git a/galleries/users_explain/text/pgf.py b/galleries/users_explain/text/pgf.py index c5fa16f35ce7..6b5b0eacb63a 100644 --- a/galleries/users_explain/text/pgf.py +++ b/galleries/users_explain/text/pgf.py @@ -48,6 +48,7 @@ pgf.preamble Lines to be included in the LaTeX preamble pgf.rcfonts Setup fonts from rc params using the fontspec package pgf.texsystem Either "xelatex" (default), "lualatex" or "pdflatex" +pgf.documentclass The LaTeX document class to use (e.g., "article", "IEEEtran") ================= ===================================================== .. note:: @@ -144,6 +145,7 @@ if you want to do the font configuration yourself instead of using the fonts specified in the rc parameters, make sure to disable :rc:`pgf.rcfonts`. + .. code-block:: python import matplotlib as mpl @@ -170,6 +172,17 @@ ax.set_ylabel(r"\url{https://matplotlib.org}") ax.legend(["unicode math: $λ=∑_i^∞ μ_i^2$"]) +You can also change the LaTeX document class used when generating PGF figures. +By default, Matplotlib uses ``article``, but you can override this using +the ``pgf.documentclass`` rcParam:: + + import matplotlib.pyplot as plt + plt.rcParams["pgf.documentclass"] = "IEEEtran" + +This is useful when including PGF figures into LaTeX documents using +custom classes such as ``IEEEtran``, to avoid layout +mismatches in font size or spacing. + .. redirect-from:: /gallery/userdemo/pgf_texsystem .. _pgf-texsystem: From 852824b199166555910d2e5e436e103b57b03e09 Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Mon, 19 May 2025 00:50:30 +0200 Subject: [PATCH 5/8] Add test for pgf.documentclass rcParam in PGF backend --- lib/matplotlib/tests/test_backend_pgf.py | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/matplotlib/tests/test_backend_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index e218a81cdceb..5fa9d4d36732 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -400,3 +400,37 @@ def test_document_font_size(): label=r'\normalsize the document font size is \the\fontdimen6\font' ) plt.legend() + + +@needs_pgf_pdflatex +@pytest.mark.backend("pgf") +def test_pgf_documentclass_written(): + import pathlib + from tempfile import TemporaryDirectory + # Set custom documentclass + mpl.rcParams["pgf.texsystem"] = "pdflatex" + mpl.rcParams["pgf.documentclass"] = "IEEEtran" + + with TemporaryDirectory() as tmpdir: + tmpdir = pathlib.Path(tmpdir) + texfile = tmpdir / "figure.tex" + pgffile = tmpdir / "figure.pgf" + + # Generate PGF figure + fig, ax = plt.subplots() + ax.plot([1, 2, 3], [4, 5, 6]) + fig.savefig(pgffile, format="pgf") + + # Manually generate .tex using PGF backend logic + texfile.write_text( + "\n".join([ + r"\documentclass{IEEEtran}", + r"\usepackage{pgf}", + r"\begin{document}", + r"\input{figure.pgf}", + r"\end{document}" + ]) + ) + + content = texfile.read_text() + assert r"\documentclass{IEEEtran}" in content From c4b684c2d16ad780a757d92ea2a0a6378a1fa723 Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Thu, 22 May 2025 00:24:49 +0200 Subject: [PATCH 6/8] test: replaced test with a more representative test case --- lib/matplotlib/tests/test_backend_pgf.py | 33 +++--------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/lib/matplotlib/tests/test_backend_pgf.py b/lib/matplotlib/tests/test_backend_pgf.py index 5fa9d4d36732..661ae2d3a59e 100644 --- a/lib/matplotlib/tests/test_backend_pgf.py +++ b/lib/matplotlib/tests/test_backend_pgf.py @@ -402,35 +402,10 @@ def test_document_font_size(): plt.legend() -@needs_pgf_pdflatex @pytest.mark.backend("pgf") def test_pgf_documentclass_written(): - import pathlib - from tempfile import TemporaryDirectory - # Set custom documentclass - mpl.rcParams["pgf.texsystem"] = "pdflatex" - mpl.rcParams["pgf.documentclass"] = "IEEEtran" + from matplotlib.backends.backend_pgf import LatexManager - with TemporaryDirectory() as tmpdir: - tmpdir = pathlib.Path(tmpdir) - texfile = tmpdir / "figure.tex" - pgffile = tmpdir / "figure.pgf" - - # Generate PGF figure - fig, ax = plt.subplots() - ax.plot([1, 2, 3], [4, 5, 6]) - fig.savefig(pgffile, format="pgf") - - # Manually generate .tex using PGF backend logic - texfile.write_text( - "\n".join([ - r"\documentclass{IEEEtran}", - r"\usepackage{pgf}", - r"\begin{document}", - r"\input{figure.pgf}", - r"\end{document}" - ]) - ) - - content = texfile.read_text() - assert r"\documentclass{IEEEtran}" in content + mpl.rcParams["pgf.documentclass"] = "IEEEtran" + header = LatexManager._build_latex_header() + assert r"\documentclass{IEEEtran}" in header From 20a73f04b86892d6653345cdb5ea94b0e9fa27aa Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Thu, 22 May 2025 11:33:40 +0200 Subject: [PATCH 7/8] doc: fix :rc: role usage in release note --- doc/users/next_whats_new/pgf-documentclass.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/users/next_whats_new/pgf-documentclass.rst b/doc/users/next_whats_new/pgf-documentclass.rst index ecc9d93fb1cb..0d4c80d7561d 100644 --- a/doc/users/next_whats_new/pgf-documentclass.rst +++ b/doc/users/next_whats_new/pgf-documentclass.rst @@ -1,9 +1,8 @@ -PGF backend: new rcParam `pgf.documentclass` -============================================ - -A new rcParam `pgf.documentclass` has been added to allow users to override -the default LaTeX document class (`article`) used by the PGF backend. +PGF backend: new rcParam :rc:`pgf.documentclass` +------------------------------------------------ +A new rcParam :rc:`pgf.documentclass` has been added to allow users to override +the default LaTeX document class (``article``) used by the PGF backend. This enables better compatibility when including PGF figures in documents that -use custom LaTeX classes like `IEEEtran` or others, avoiding layout +use custom LaTeX classes like ``IEEEtran`` or others, avoiding layout issues like incorrect font sizes or spacing mismatches. From e670dd0ff8f5d87ee245afd37bfacfa59e4711ae Mon Sep 17 00:00:00 2001 From: MiniX16 Date: Thu, 22 May 2025 12:22:46 +0200 Subject: [PATCH 8/8] Avoiding to use rf and multiline --- lib/matplotlib/backends/backend_pgf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index fc047f6c4b27..7cbf8300fd66 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -828,11 +828,11 @@ def print_pdf(self, fname_or_fh, *, metadata=None, **kwargs): # print figure to pgf and compile it with latex with TemporaryDirectory() as tmpdir: tmppath = pathlib.Path(tmpdir) + docclass = mpl.rcParams.get("pgf.documentclass", "article") self.print_pgf(tmppath / "figure.pgf", **kwargs) (tmppath / "figure.tex").write_text( "\n".join([ - rf"\documentclass{{{mpl.rcParams.get( - 'pgf.documentclass', 'article')}}}", + r"\\documentclass{{{docclass}}}" r"\usepackage[pdfinfo={%s}]{hyperref}" % pdfinfo, r"\usepackage[papersize={%fin,%fin}, margin=0in]{geometry}" % (w, h),