Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3ab6e1f

Browse filesBrowse files
authored
Merge pull request matplotlib#26479 from QuLogic/ps-papersize-figure
ps: Add option to use figure size as paper size
2 parents fb3a97a + 96b26fe commit 3ab6e1f
Copy full SHA for 3ab6e1f

File tree

Expand file treeCollapse file tree

5 files changed

+77
-30
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+77
-30
lines changed
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
PostScript paper type adds option to use figure size
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
The :rc:`ps.papertype` rcParam can now be set to ``'figure'``, which will use
5+
a paper size that corresponds exactly with the size of the figure that is being
6+
saved.

‎lib/matplotlib/backends/backend_ps.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_ps.py
+28-21Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ def _print_ps(
841841
if papertype is None:
842842
papertype = mpl.rcParams['ps.papersize']
843843
papertype = papertype.lower()
844-
_api.check_in_list(['auto', *papersize], papertype=papertype)
844+
_api.check_in_list(['figure', 'auto', *papersize], papertype=papertype)
845845

846846
orientation = _api.check_getitem(
847847
_Orientation, orientation=orientation.lower())
@@ -873,24 +873,16 @@ def _print_figure(
873873
width, height = self.figure.get_size_inches()
874874
if papertype == 'auto':
875875
_api.warn_deprecated("3.8", name="papertype='auto'",
876-
addendum="Pass an explicit paper type, or omit the "
877-
"*papertype* argument entirely.")
876+
addendum="Pass an explicit paper type, 'figure', or "
877+
"omit the *papertype* argument entirely.")
878878
papertype = _get_papertype(*orientation.swap_if_landscape((width, height)))
879879

880-
if is_eps:
880+
if is_eps or papertype == 'figure':
881881
paper_width, paper_height = width, height
882882
else:
883883
paper_width, paper_height = orientation.swap_if_landscape(
884884
papersize[papertype])
885885

886-
if mpl.rcParams['ps.usedistiller']:
887-
# distillers improperly clip eps files if pagesize is too small
888-
if width > paper_width or height > paper_height:
889-
papertype = _get_papertype(
890-
*orientation.swap_if_landscape((width, height)))
891-
paper_width, paper_height = orientation.swap_if_landscape(
892-
papersize[papertype])
893-
894886
# center the figure on the paper
895887
xo = 72 * 0.5 * (paper_width - width)
896888
yo = 72 * 0.5 * (paper_height - height)
@@ -921,10 +913,10 @@ def print_figure_impl(fh):
921913
if is_eps:
922914
print("%!PS-Adobe-3.0 EPSF-3.0", file=fh)
923915
else:
924-
print(f"%!PS-Adobe-3.0\n"
925-
f"%%DocumentPaperSizes: {papertype}\n"
926-
f"%%Pages: 1\n",
927-
end="", file=fh)
916+
print("%!PS-Adobe-3.0", file=fh)
917+
if papertype != 'figure':
918+
print(f"%%DocumentPaperSizes: {papertype}", file=fh)
919+
print("%%Pages: 1", file=fh)
928920
print(f"%%LanguageLevel: 3\n"
929921
f"{dsc_comments}\n"
930922
f"%%Orientation: {orientation.name}\n"
@@ -1061,7 +1053,7 @@ def _print_figure_tex(
10611053
# set the paper size to the figure size if is_eps. The
10621054
# resulting ps file has the given size with correct bounding
10631055
# box so that there is no need to call 'pstoeps'
1064-
if is_eps:
1056+
if is_eps or papertype == 'figure':
10651057
paper_width, paper_height = orientation.swap_if_landscape(
10661058
self.figure.get_size_inches())
10671059
else:
@@ -1160,17 +1152,22 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False):
11601152
"""
11611153

11621154
if eps:
1163-
paper_option = "-dEPSCrop"
1155+
paper_option = ["-dEPSCrop"]
1156+
elif ptype == "figure":
1157+
# The bbox will have its lower-left corner at (0, 0), so upper-right
1158+
# corner corresponds with paper size.
1159+
paper_option = [f"-dDEVICEWIDTHPOINTS={bbox[2]}",
1160+
f"-dDEVICEHEIGHTPOINTS={bbox[3]}"]
11641161
else:
1165-
paper_option = "-sPAPERSIZE=%s" % ptype
1162+
paper_option = [f"-sPAPERSIZE={ptype}"]
11661163

11671164
psfile = tmpfile + '.ps'
11681165
dpi = mpl.rcParams['ps.distiller.res']
11691166

11701167
cbook._check_and_log_subprocess(
11711168
[mpl._get_executable_info("gs").executable,
11721169
"-dBATCH", "-dNOPAUSE", "-r%d" % dpi, "-sDEVICE=ps2write",
1173-
paper_option, "-sOutputFile=%s" % psfile, tmpfile],
1170+
*paper_option, f"-sOutputFile={psfile}", tmpfile],
11741171
_log)
11751172

11761173
os.remove(tmpfile)
@@ -1196,6 +1193,16 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False):
11961193
mpl._get_executable_info("gs") # Effectively checks for ps2pdf.
11971194
mpl._get_executable_info("pdftops")
11981195

1196+
if eps:
1197+
paper_option = ["-dEPSCrop"]
1198+
elif ptype == "figure":
1199+
# The bbox will have its lower-left corner at (0, 0), so upper-right
1200+
# corner corresponds with paper size.
1201+
paper_option = [f"-dDEVICEWIDTHPOINTS#{bbox[2]}",
1202+
f"-dDEVICEHEIGHTPOINTS#{bbox[3]}"]
1203+
else:
1204+
paper_option = [f"-sPAPERSIZE#{ptype}"]
1205+
11991206
with TemporaryDirectory() as tmpdir:
12001207
tmppdf = pathlib.Path(tmpdir, "tmp.pdf")
12011208
tmpps = pathlib.Path(tmpdir, "tmp.ps")
@@ -1208,7 +1215,7 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False):
12081215
"-sAutoRotatePages#None",
12091216
"-sGrayImageFilter#FlateEncode",
12101217
"-sColorImageFilter#FlateEncode",
1211-
"-dEPSCrop" if eps else "-sPAPERSIZE#%s" % ptype,
1218+
*paper_option,
12121219
tmpfile, tmppdf], _log)
12131220
cbook._check_and_log_subprocess(
12141221
["pdftops", "-paper", "match", "-level3", tmppdf, tmpps], _log)

‎lib/matplotlib/mpl-data/matplotlibrc

Copy file name to clipboardExpand all lines: lib/matplotlib/mpl-data/matplotlibrc
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@
709709
#tk.window_focus: False # Maintain shell focus for TkAgg
710710

711711
### ps backend params
712-
#ps.papersize: letter # {letter, legal, ledger, A0-A10, B0-B10}
712+
#ps.papersize: letter # {figure, letter, legal, ledger, A0-A10, B0-B10}
713713
#ps.useafm: False # use AFM fonts, results in small files
714714
#ps.usedistiller: False # {ghostscript, xpdf, None}
715715
# Experimental: may produce smaller files.

‎lib/matplotlib/rcsetup.py

Copy file name to clipboardExpand all lines: lib/matplotlib/rcsetup.py
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,13 @@ def validate_ps_distiller(s):
441441
def _validate_papersize(s):
442442
# Re-inline this validator when the 'auto' deprecation expires.
443443
s = ValidateInStrings("ps.papersize",
444-
["auto", "letter", "legal", "ledger",
444+
["figure", "auto", "letter", "legal", "ledger",
445445
*[f"{ab}{i}" for ab in "ab" for i in range(11)]],
446446
ignorecase=True)(s)
447447
if s == "auto":
448448
_api.warn_deprecated("3.8", name="ps.papersize='auto'",
449-
addendum="Pass an explicit paper type, or omit the "
450-
"*ps.papersize* rcParam entirely.")
449+
addendum="Pass an explicit paper type, figure, or omit "
450+
"the *ps.papersize* rcParam entirely.")
451451
return s
452452

453453

‎lib/matplotlib/tests/test_backend_ps.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_backend_ps.py
+39-5Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
# This tests tends to hit a TeX cache lock on AppVeyor.
2222
@pytest.mark.flaky(reruns=3)
23+
@pytest.mark.parametrize('papersize', ['letter', 'figure'])
2324
@pytest.mark.parametrize('orientation', ['portrait', 'landscape'])
2425
@pytest.mark.parametrize('format, use_log, rcParams', [
2526
('ps', False, {}),
@@ -38,7 +39,19 @@
3839
'eps afm',
3940
'eps with usetex'
4041
])
41-
def test_savefig_to_stringio(format, use_log, rcParams, orientation):
42+
def test_savefig_to_stringio(format, use_log, rcParams, orientation, papersize):
43+
if rcParams.get("ps.usedistiller") == "ghostscript":
44+
try:
45+
mpl._get_executable_info("gs")
46+
except mpl.ExecutableNotFoundError as exc:
47+
pytest.skip(str(exc))
48+
elif rcParams.get("ps.userdistiller") == "xpdf":
49+
try:
50+
mpl._get_executable_info("gs") # Effectively checks for ps2pdf.
51+
mpl._get_executable_info("pdftops")
52+
except mpl.ExecutableNotFoundError as exc:
53+
pytest.skip(str(exc))
54+
4255
mpl.rcParams.update(rcParams)
4356

4457
fig, ax = plt.subplots()
@@ -54,15 +67,15 @@ def test_savefig_to_stringio(format, use_log, rcParams, orientation):
5467
title += " \N{MINUS SIGN}\N{EURO SIGN}"
5568
ax.set_title(title)
5669
allowable_exceptions = []
57-
if rcParams.get("ps.usedistiller"):
58-
allowable_exceptions.append(mpl.ExecutableNotFoundError)
5970
if rcParams.get("text.usetex"):
6071
allowable_exceptions.append(RuntimeError)
6172
if rcParams.get("ps.useafm"):
6273
allowable_exceptions.append(mpl.MatplotlibDeprecationWarning)
6374
try:
64-
fig.savefig(s_buf, format=format, orientation=orientation)
65-
fig.savefig(b_buf, format=format, orientation=orientation)
75+
fig.savefig(s_buf, format=format, orientation=orientation,
76+
papertype=papersize)
77+
fig.savefig(b_buf, format=format, orientation=orientation,
78+
papertype=papersize)
6679
except tuple(allowable_exceptions) as exc:
6780
pytest.skip(str(exc))
6881

@@ -71,6 +84,27 @@ def test_savefig_to_stringio(format, use_log, rcParams, orientation):
7184
s_val = s_buf.getvalue().encode('ascii')
7285
b_val = b_buf.getvalue()
7386

87+
if format == 'ps':
88+
# Default figsize = (8, 6) inches = (576, 432) points = (203.2, 152.4) mm.
89+
# Landscape orientation will swap dimensions.
90+
if rcParams.get("ps.usedistiller") == "xpdf":
91+
# Some versions specifically show letter/203x152, but not all,
92+
# so we can only use this simpler test.
93+
if papersize == 'figure':
94+
assert b'letter' not in s_val.lower()
95+
else:
96+
assert b'letter' in s_val.lower()
97+
elif rcParams.get("ps.usedistiller") or rcParams.get("text.usetex"):
98+
width = b'432.0' if orientation == 'landscape' else b'576.0'
99+
wanted = (b'-dDEVICEWIDTHPOINTS=' + width if papersize == 'figure'
100+
else b'-sPAPERSIZE')
101+
assert wanted in s_val
102+
else:
103+
if papersize == 'figure':
104+
assert b'%%DocumentPaperSizes' not in s_val
105+
else:
106+
assert b'%%DocumentPaperSizes' in s_val
107+
74108
# Strip out CreationDate: ghostscript and cairo don't obey
75109
# SOURCE_DATE_EPOCH, and that environment variable is already tested in
76110
# test_determinism.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.