Download lib/python3.12/site-packages/matplotlib/tests/test_backend_pgf.py from parallel-reasoner/env-full: direct link, hf CLI and curl.
- Browser
- Download file 13 kB
-
https://huggingface.co/parallel-reasoner/env-full/resolve/a2585bd5ca1cf640fa361bd20177ded829caaa8d/lib/python3.12/site-packages/matplotlib/tests/test_backend_pgf.py
- Command line
-
hf download hf://parallel-reasoner/env-full@a2585bd5ca1cf640fa361bd20177ded829caaa8d/lib/python3.12/site-packages/matplotlib/tests/test_backend_pgf.py
-
curl -L -o test_backend_pgf.py https://huggingface.co/parallel-reasoner/env-full/resolve/a2585bd5ca1cf640fa361bd20177ded829caaa8d/lib/python3.12/site-packages/matplotlib/tests/test_backend_pgf.py
13 kB
| import datetime | |
| from io import BytesIO | |
| import os | |
| import shutil | |
| import numpy as np | |
| from packaging.version import parse as parse_version | |
| import pytest | |
| import matplotlib as mpl | |
| import matplotlib.pyplot as plt | |
| from matplotlib.testing import _has_tex_package, _check_for_pgf | |
| from matplotlib.testing.exceptions import ImageComparisonFailure | |
| from matplotlib.testing.compare import compare_images | |
| from matplotlib.backends.backend_pgf import PdfPages | |
| from matplotlib.testing.decorators import ( | |
| _image_directories, check_figures_equal, image_comparison) | |
| from matplotlib.testing._markers import ( | |
| needs_ghostscript, needs_pgf_lualatex, needs_pgf_pdflatex, | |
| needs_pgf_xelatex) | |
| baseline_dir, result_dir = _image_directories(lambda: 'dummy func') | |
| def compare_figure(fname, savefig_kwargs={}, tol=0): | |
| actual = os.path.join(result_dir, fname) | |
| plt.savefig(actual, **savefig_kwargs) | |
| expected = os.path.join(result_dir, "expected_%s" % fname) | |
| shutil.copyfile(os.path.join(baseline_dir, fname), expected) | |
| err = compare_images(expected, actual, tol=tol) | |
| if err: | |
| raise ImageComparisonFailure(err) | |
| def test_tex_special_chars(tmp_path): | |
| fig = plt.figure() | |
| fig.text(.5, .5, "%_^ $a_b^c$") | |
| buf = BytesIO() | |
| fig.savefig(buf, format="png", backend="pgf") | |
| buf.seek(0) | |
| t = plt.imread(buf) | |
| assert not (t == 1).all() # The leading "%" didn't eat up everything. | |
| def create_figure(): | |
| plt.figure() | |
| x = np.linspace(0, 1, 15) | |
| # line plot | |
| plt.plot(x, x ** 2, "b-") | |
| # marker | |
| plt.plot(x, 1 - x**2, "g>") | |
| # filled paths and patterns | |
| plt.fill_between([0., .4], [.4, 0.], hatch='//', facecolor="lightgray", | |
| edgecolor="red") | |
| plt.fill([3, 3, .8, .8, 3], [2, -2, -2, 0, 2], "b") | |
| # text and typesetting | |
| plt.plot([0.9], [0.5], "ro", markersize=3) | |
| plt.text(0.9, 0.5, 'unicode (ü, °, \N{Section Sign}) and math ($\\mu_i = x_i^2$)', | |
| ha='right', fontsize=20) | |
| plt.ylabel('sans-serif, blue, $\\frac{\\sqrt{x}}{y^2}$..', | |
| family='sans-serif', color='blue') | |
| plt.text(1, 1, 'should be clipped as default clip_box is Axes bbox', | |
| fontsize=20, clip_on=True) | |
| plt.xlim(0, 1) | |
| plt.ylim(0, 1) | |
| # test compiling a figure to pdf with xelatex | |
| def test_xelatex(): | |
| rc_xelatex = {'font.family': 'serif', | |
| 'pgf.rcfonts': False} | |
| mpl.rcParams.update(rc_xelatex) | |
| create_figure() | |
| try: | |
| _old_gs_version = \ | |
| mpl._get_executable_info('gs').version < parse_version('9.50') | |
| except mpl.ExecutableNotFoundError: | |
| _old_gs_version = True | |
| # test compiling a figure to pdf with pdflatex | |
| def test_pdflatex(): | |
| rc_pdflatex = {'font.family': 'serif', | |
| 'pgf.rcfonts': False, | |
| 'pgf.texsystem': 'pdflatex', | |
| 'pgf.preamble': ('\\usepackage[utf8x]{inputenc}' | |
| '\\usepackage[T1]{fontenc}')} | |
| mpl.rcParams.update(rc_pdflatex) | |
| create_figure() | |
| # test updating the rc parameters for each figure | |
| def test_rcupdate(): | |
| rc_sets = [{'font.family': 'sans-serif', | |
| 'font.size': 30, | |
| 'figure.subplot.left': .2, | |
| 'lines.markersize': 10, | |
| 'pgf.rcfonts': False, | |
| 'pgf.texsystem': 'xelatex'}, | |
| {'font.family': 'monospace', | |
| 'font.size': 10, | |
| 'figure.subplot.left': .1, | |
| 'lines.markersize': 20, | |
| 'pgf.rcfonts': False, | |
| 'pgf.texsystem': 'pdflatex', | |
| 'pgf.preamble': ('\\usepackage[utf8x]{inputenc}' | |
| '\\usepackage[T1]{fontenc}' | |
| '\\usepackage{sfmath}')}] | |
| tol = [0, 13.2] if _old_gs_version else [0, 0] | |
| for i, rc_set in enumerate(rc_sets): | |
| with mpl.rc_context(rc_set): | |
| for substring, pkg in [('sfmath', 'sfmath'), ('utf8x', 'ucs')]: | |
| if (substring in mpl.rcParams['pgf.preamble'] | |
| and not _has_tex_package(pkg)): | |
| pytest.skip(f'needs {pkg}.sty') | |
| create_figure() | |
| compare_figure(f'pgf_rcupdate{i + 1}.pdf', tol=tol[i]) | |
| # test backend-side clipping, since large numbers are not supported by TeX | |
| def test_pathclip(): | |
| np.random.seed(19680801) | |
| mpl.rcParams.update({'font.family': 'serif', 'pgf.rcfonts': False}) | |
| fig, axs = plt.subplots(1, 2) | |
| axs[0].plot([0., 1e100], [0., 1e100]) | |
| axs[0].set_xlim(0, 1) | |
| axs[0].set_ylim(0, 1) | |
| axs[1].scatter([0, 1], [1, 1]) | |
| axs[1].hist(np.random.normal(size=1000), bins=20, range=[-10, 10]) | |
| axs[1].set_xscale('log') | |
| fig.savefig(BytesIO(), format="pdf") # No image comparison. | |
| # test mixed mode rendering | |
| def test_mixedmode(): | |
| mpl.rcParams.update({'font.family': 'serif', 'pgf.rcfonts': False}) | |
| Y, X = np.ogrid[-1:1:40j, -1:1:40j] | |
| plt.pcolor(X**2 + Y**2).set_rasterized(True) | |
| # test bbox_inches clipping | |
| def test_bbox_inches(): | |
| mpl.rcParams.update({'font.family': 'serif', 'pgf.rcfonts': False}) | |
| fig, (ax1, ax2) = plt.subplots(1, 2) | |
| ax1.plot(range(5)) | |
| ax2.plot(range(5)) | |
| plt.tight_layout() | |
| bbox = ax1.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) | |
| compare_figure('pgf_bbox_inches.pdf', savefig_kwargs={'bbox_inches': bbox}, | |
| tol=0) | |
| def test_pdf_pages(system): | |
| rc_pdflatex = { | |
| 'font.family': 'serif', | |
| 'pgf.rcfonts': False, | |
| 'pgf.texsystem': system, | |
| } | |
| mpl.rcParams.update(rc_pdflatex) | |
| fig1, ax1 = plt.subplots() | |
| ax1.plot(range(5)) | |
| fig1.tight_layout() | |
| fig2, ax2 = plt.subplots(figsize=(3, 2)) | |
| ax2.plot(range(5)) | |
| fig2.tight_layout() | |
| path = os.path.join(result_dir, f'pdfpages_{system}.pdf') | |
| md = { | |
| 'Author': 'me', | |
| 'Title': 'Multipage PDF with pgf', | |
| 'Subject': 'Test page', | |
| 'Keywords': 'test,pdf,multipage', | |
| 'ModDate': datetime.datetime( | |
| 1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))), | |
| 'Trapped': 'Unknown' | |
| } | |
| with PdfPages(path, metadata=md) as pdf: | |
| pdf.savefig(fig1) | |
| pdf.savefig(fig2) | |
| pdf.savefig(fig1) | |
| assert pdf.get_pagecount() == 3 | |
| def test_pdf_pages_metadata_check(monkeypatch, system): | |
| # Basically the same as test_pdf_pages, but we keep it separate to leave | |
| # pikepdf as an optional dependency. | |
| pikepdf = pytest.importorskip('pikepdf') | |
| monkeypatch.setenv('SOURCE_DATE_EPOCH', '0') | |
| mpl.rcParams.update({'pgf.texsystem': system}) | |
| fig, ax = plt.subplots() | |
| ax.plot(range(5)) | |
| md = { | |
| 'Author': 'me', | |
| 'Title': 'Multipage PDF with pgf', | |
| 'Subject': 'Test page', | |
| 'Keywords': 'test,pdf,multipage', | |
| 'ModDate': datetime.datetime( | |
| 1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))), | |
| 'Trapped': 'True' | |
| } | |
| path = os.path.join(result_dir, f'pdfpages_meta_check_{system}.pdf') | |
| with PdfPages(path, metadata=md) as pdf: | |
| pdf.savefig(fig) | |
| with pikepdf.Pdf.open(path) as pdf: | |
| info = {k: str(v) for k, v in pdf.docinfo.items()} | |
| # Not set by us, so don't bother checking. | |
| if '/PTEX.FullBanner' in info: | |
| del info['/PTEX.FullBanner'] | |
| if '/PTEX.Fullbanner' in info: | |
| del info['/PTEX.Fullbanner'] | |
| # Some LaTeX engines ignore this setting, and state themselves as producer. | |
| producer = info.pop('/Producer') | |
| assert producer == f'Matplotlib pgf backend v{mpl.__version__}' or ( | |
| system == 'lualatex' and 'LuaTeX' in producer) | |
| assert info == { | |
| '/Author': 'me', | |
| '/CreationDate': 'D:19700101000000Z', | |
| '/Creator': f'Matplotlib v{mpl.__version__}, https://matplotlib.org', | |
| '/Keywords': 'test,pdf,multipage', | |
| '/ModDate': 'D:19680801000000Z', | |
| '/Subject': 'Test page', | |
| '/Title': 'Multipage PDF with pgf', | |
| '/Trapped': '/True', | |
| } | |
| def test_multipage_keep_empty(tmp_path): | |
| # An empty pdf deletes itself afterwards. | |
| fn = tmp_path / "a.pdf" | |
| with PdfPages(fn) as pdf: | |
| pass | |
| assert not fn.exists() | |
| # Test pdf files with content, they should never be deleted. | |
| fn = tmp_path / "b.pdf" | |
| with PdfPages(fn) as pdf: | |
| pdf.savefig(plt.figure()) | |
| assert fn.exists() | |
| def test_tex_restart_after_error(): | |
| fig = plt.figure() | |
| fig.suptitle(r"\oops") | |
| with pytest.raises(ValueError): | |
| fig.savefig(BytesIO(), format="pgf") | |
| fig = plt.figure() # start from scratch | |
| fig.suptitle(r"this is ok") | |
| fig.savefig(BytesIO(), format="pgf") | |
| def test_bbox_inches_tight(): | |
| fig, ax = plt.subplots() | |
| ax.imshow([[0, 1], [2, 3]]) | |
| fig.savefig(BytesIO(), format="pdf", backend="pgf", bbox_inches="tight") | |
| def test_png_transparency(): # Actually, also just testing that png works. | |
| buf = BytesIO() | |
| plt.figure().savefig(buf, format="png", backend="pgf", transparent=True) | |
| buf.seek(0) | |
| t = plt.imread(buf) | |
| assert (t[..., 3] == 0).all() # fully transparent. | |
| def test_unknown_font(caplog): | |
| with caplog.at_level("WARNING"): | |
| mpl.rcParams["font.family"] = "this-font-does-not-exist" | |
| plt.figtext(.5, .5, "hello, world") | |
| plt.savefig(BytesIO(), format="pgf") | |
| assert "Ignoring unknown font: this-font-does-not-exist" in [ | |
| r.getMessage() for r in caplog.records] | |
| def test_minus_signs_with_tex(fig_test, fig_ref, texsystem): | |
| if not _check_for_pgf(texsystem): | |
| pytest.skip(texsystem + ' + pgf is required') | |
| mpl.rcParams["pgf.texsystem"] = texsystem | |
| fig_test.text(.5, .5, "$-1$") | |
| fig_ref.text(.5, .5, "$\N{MINUS SIGN}1$") | |
| def test_sketch_params(): | |
| fig, ax = plt.subplots(figsize=(3, 3)) | |
| ax.set_xticks([]) | |
| ax.set_yticks([]) | |
| ax.set_frame_on(False) | |
| handle, = ax.plot([0, 1]) | |
| handle.set_sketch_params(scale=5, length=30, randomness=42) | |
| with BytesIO() as fd: | |
| fig.savefig(fd, format='pgf') | |
| buf = fd.getvalue().decode() | |
| baseline = r"""\pgfpathmoveto{\pgfqpoint{0.375000in}{0.300000in}}% | |
| \pgfpathlineto{\pgfqpoint{2.700000in}{2.700000in}}% | |
| \usepgfmodule{decorations}% | |
| \usepgflibrary{decorations.pathmorphing}% | |
| \pgfkeys{/pgf/decoration/.cd, """ \ | |
| r"""segment length = 0.150000in, amplitude = 0.100000in}% | |
| \pgfmathsetseed{42}% | |
| \pgfdecoratecurrentpath{random steps}% | |
| \pgfusepath{stroke}%""" | |
| # \pgfdecoratecurrentpath must be after the path definition and before the | |
| # path is used (\pgfusepath) | |
| assert baseline in buf | |
| # test to make sure that the document font size is set consistently (see #26892) | |
| def test_document_font_size(): | |
| mpl.rcParams.update({ | |
| 'pgf.texsystem': 'xelatex', | |
| 'pgf.rcfonts': False, | |
| 'pgf.preamble': r'\usepackage{unicode-math}', | |
| }) | |
| plt.figure() | |
| plt.plot([], | |
| label=r'$this is a very very very long math label a \times b + 10^{-3}$ ' | |
| r'and some text' | |
| ) | |
| plt.plot([], | |
| label=r'\normalsize the document font size is \the\fontdimen6\font' | |
| ) | |
| plt.legend() | |