Skip to content

Commit 6dcd951

Browse files
authored
Merge branch 'matplotlib:master' into patch-2
2 parents a86d26c + b932575 commit 6dcd951

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+21507
-200
lines changed

.circleci/config.yml

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -119,51 +119,6 @@ commands:
119119
#
120120

121121
jobs:
122-
docs-python37:
123-
docker:
124-
- image: circleci/python:3.7
125-
steps:
126-
- checkout
127-
128-
- apt-install
129-
- fonts-install
130-
- pip-install
131-
132-
- deps-install
133-
- mpl-install
134-
135-
- doc-build
136-
137-
- doc-bundle
138-
139-
- store_artifacts:
140-
path: doc/build/html
141-
- store_test_results:
142-
path: doc/build/test-results
143-
144-
docs-python38-min:
145-
docker:
146-
- image: circleci/python:3.8
147-
steps:
148-
- checkout
149-
150-
- apt-install
151-
- fonts-install
152-
- pip-install
153-
154-
- deps-install:
155-
numpy_version: "==1.17.3"
156-
- mpl-install
157-
158-
- doc-build
159-
160-
- doc-bundle
161-
162-
- store_artifacts:
163-
path: doc/build/html
164-
- store_test_results:
165-
path: doc/build/test-results
166-
167122
docs-python38:
168123
docker:
169124
- image: circleci/python:3.8
@@ -201,6 +156,4 @@ workflows:
201156
version: 2
202157
build:
203158
jobs:
204-
- docs-python37
205159
- docs-python38
206-
- docs-python38-min

.github/workflows/circleci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ jobs:
99
with:
1010
repo-token: ${{ secrets.GITHUB_TOKEN }}
1111
artifact-path: 0/doc/build/html/index.html
12-
circleci-jobs: docs-python37,docs-python38,docs-python38-min
12+
circleci-jobs: docs-python38

doc/conf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
import sphinx
2121

2222
from datetime import datetime
23+
import time
24+
25+
# Parse year using SOURCE_DATE_EPOCH, falling back to current time.
26+
# https://reproducible-builds.org/specs/source-date-epoch/
27+
sourceyear = datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))).year
2328

2429
# If your extensions are in another directory, add it here. If the directory
2530
# is relative to the documentation root, use os.path.abspath to make it
@@ -212,7 +217,7 @@ def _check_dependencies():
212217
project = 'Matplotlib'
213218
copyright = ('2002 - 2012 John Hunter, Darren Dale, Eric Firing, '
214219
'Michael Droettboom and the Matplotlib development '
215-
f'team; 2012 - {datetime.now().year} The Matplotlib development team')
220+
f'team; 2012 - {sourceyear} The Matplotlib development team')
216221

217222

218223
# The default replacements for |version| and |release|, also used in various

doc/users/fonts.rst

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
Fonts in Matplotlib Text Engine
2+
===============================
3+
4+
Matplotlib needs fonts to work with its text engine, some of which are shipped
5+
alongside the installation. However, users can configure the default fonts, or
6+
even provide their own custom fonts! For more details, see :doc:`Customizing
7+
text properties </tutorials/text/text_props>`.
8+
9+
However, Matplotlib also provides an option to offload text rendering to a TeX
10+
engine (``usetex=True``),
11+
see :doc:`Text rendering with LaTeX </tutorials/text/usetex>`.
12+
13+
Font Specifications
14+
-------------------
15+
Fonts have a long and sometimes incompatible history in computing, leading to
16+
different platforms supporting different types of fonts. In practice, there are
17+
3 types of font specifications Matplotlib supports (in addition to 'core
18+
fonts', more about which is explained later in the guide):
19+
20+
.. list-table:: Type of Fonts
21+
:header-rows: 1
22+
23+
* - Type 1 (PDF)
24+
- Type 3 (PDF/PS)
25+
- TrueType (PDF)
26+
* - One of the oldest types, introduced by Adobe
27+
- Similar to Type 1 in terms of introduction
28+
- Newer than previous types, used commonly today, introduced by Apple
29+
* - Restricted subset of PostScript, charstrings are in bytecode
30+
- Full PostScript language, allows embedding arbitrary code
31+
(in theory, even render fractals when rasterizing!)
32+
- Include a virtual machine that can execute code!
33+
* - These fonts support font hinting
34+
- Do not support font hinting
35+
- Hinting supported (virtual machine processes the "hints")
36+
* - Non-subsetted through Matplotlib
37+
- Subsetted via external module `ttconv <https://github.com/sandflow/ttconv>`_
38+
- Subsetted via external module `fonttools <https://github.com/fonttools/fonttools>`_
39+
40+
NOTE: Adobe will disable support for authoring with Type 1 fonts in
41+
January 2023. `Read more here. <https://helpx.adobe.com/fonts/kb/postscript-type-1-fonts-end-of-support.html>`_
42+
43+
Special Mentions
44+
^^^^^^^^^^^^^^^^
45+
Other font specifications which Matplotlib supports:
46+
47+
- Type 42 fonts (PS):
48+
49+
- PostScript wrapper around TrueType fonts
50+
- 42 is the `Answer to Life, the Universe, and Everything! <https://en.wikipedia.org/wiki/Answer_to_Life,_the_Universe,_and_Everything>`_
51+
- Matplotlib uses an external library called `fonttools <https://github.com/fonttools/fonttools>`_
52+
to subset these types of fonts
53+
54+
- OpenType fonts:
55+
56+
- OpenType is a new standard for digital type fonts, developed jointly by
57+
Adobe and Microsoft
58+
- Generally contain a much larger character set!
59+
- Limited Support with Matplotlib
60+
61+
Subsetting
62+
----------
63+
Matplotlib is able to generate documents in multiple different formats. Some of
64+
those formats (for example, PDF, PS/EPS, SVG) allow embedding font data in such
65+
a way that when these documents are visually scaled, the text does not appear
66+
pixelated.
67+
68+
This can be achieved by embedding the *whole* font file within the
69+
output document. However, this can lead to very large documents, as some
70+
fonts (for instance, CJK - Chinese/Japanese/Korean fonts) can contain a large
71+
number of glyphs, and thus their embedded size can be quite huge.
72+
73+
Font Subsetting can be used before generating documents, to embed only the
74+
*required* glyphs within the documents. Fonts can be considered as a collection
75+
of glyphs, so ultimately the goal is to find out *which* glyphs are required
76+
for a certain array of characters, and embed only those within the output.
77+
78+
.. note::
79+
The role of subsetter really shines when we encounter characters like **ä**
80+
(composed by calling subprograms for **a** and **¨**); since the subsetter
81+
has to find out *all* such subprograms being called by every glyph included
82+
in the subset, this is a generally difficult problem!
83+
84+
Luckily, Matplotlib uses a fork of an external dependency called
85+
`ttconv <https://github.com/sandflow/ttconv>`_, which helps in embedding and
86+
subsetting font data. (however, recent versions have moved away from ttconv to
87+
pure Python for certain types: for more details visit
88+
`these <https://github.com/matplotlib/matplotlib/pull/18370>`_, `links <https://github.com/matplotlib/matplotlib/pull/18181>`_)
89+
90+
| *Type 1 fonts are still non-subsetted* through Matplotlib. (though one will encounter these mostly via *usetex*/*dviread* in PDF backend)
91+
| **Type 3 and Type 42 fonts are subsetted**, with a fair amount of exceptions and bugs for the latter.
92+
93+
What to use?
94+
------------
95+
Practically, most fonts that are readily available on most operating systems or
96+
are readily available on the internet to download include *TrueType fonts* and
97+
its "extensions" such as MacOS-resource fork fonts and the newer OpenType
98+
fonts.
99+
100+
PS and PDF backends provide support for yet another type of fonts, which remove
101+
the need of subsetting altogether! These are called **Core Fonts**, and
102+
Matplotlib calls them via the keyword **AFM**; all that is supplied from
103+
Matplotlib to such documents are font metrics (specified in AFM format), and it
104+
is the job of the viewer applications to supply the glyph definitions.
105+
106+
This is especially helpful to generate *really lightweight* documents.::
107+
108+
# trigger core fonts for PDF backend
109+
plt.rcParams["pdf.use14corefonts"] = True
110+
# trigger core fonts for PS backend
111+
plt.rcParams["ps.useafm"] = True
112+
113+
chars = "AFM ftw!"
114+
fig, ax = plt.subplots()
115+
ax.text(0.5, 0.5, chars)
116+
117+
fig.savefig("AFM_PDF.pdf", format="pdf")
118+
fig.savefig("AFM_PS.ps", format="ps)
119+
120+
.. note::
121+
These core fonts are limited to PDF and PS backends only; they can not be
122+
rendered in other backends.
123+
124+
Another downside to this is that while the font metric are standardized,
125+
different PDF viewer applications will have different fonts to render these
126+
metrics. In other words, the **output might look different on different
127+
viewers**, as well as (let's say) Windows and Linux, if Linux tools included
128+
free versions of the proprietary fonts.
129+
130+
This also violates the *what-you-see-is-what-you-get* feature of Matplotlib.

doc/users/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ User's guide
1313
:maxdepth: 2
1414

1515
interactive.rst
16+
fonts.rst
1617
release_notes.rst
1718
license.rst
1819
../citing.rst

examples/axes_grid1/make_room_for_ylabel_using_axesgrid.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
plt.figure()
1515
ax = plt.axes([0, 0, 1, 1])
1616

17-
ax.set_yticks([0.5])
18-
ax.set_yticklabels(["very long label"])
17+
ax.set_yticks([0.5], labels=["very long label"])
1918

2019
make_axes_area_auto_adjustable(ax)
2120

@@ -26,8 +25,7 @@
2625
ax1 = plt.axes([0, 0, 1, 0.5])
2726
ax2 = plt.axes([0, 0.5, 1, 0.5])
2827

29-
ax1.set_yticks([0.5])
30-
ax1.set_yticklabels(["very long label"])
28+
ax1.set_yticks([0.5], labels=["very long label"])
3129
ax1.set_ylabel("Y label")
3230

3331
ax2.set_title("Title")
@@ -53,8 +51,7 @@
5351
divider.add_auto_adjustable_area(use_axes=[ax1, ax2], pad=0.1,
5452
adjust_dirs=["top", "bottom"])
5553

56-
ax1.set_yticks([0.5])
57-
ax1.set_yticklabels(["very long label"])
54+
ax1.set_yticks([0.5], labels=["very long label"])
5855

5956
ax2.set_title("Title")
6057
ax2.set_xlabel("X - Label")

examples/axes_grid1/simple_axisline4.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
ax.plot(xx, np.sin(xx))
1414

1515
ax2 = ax.twin() # ax2 is responsible for "top" axis and "right" axis
16-
ax2.set_xticks([0., .5*np.pi, np.pi, 1.5*np.pi, 2*np.pi])
17-
ax2.set_xticklabels(["$0$", r"$\frac{1}{2}\pi$",
18-
r"$\pi$", r"$\frac{3}{2}\pi$", r"$2\pi$"])
16+
ax2.set_xticks([0., .5*np.pi, np.pi, 1.5*np.pi, 2*np.pi],
17+
labels=["$0$", r"$\frac{1}{2}\pi$",
18+
r"$\pi$", r"$\frac{3}{2}\pi$", r"$2\pi$"])
1919

2020
ax2.axis["right"].major_ticklabels.set_visible(False)
2121
ax2.axis["top"].major_ticklabels.set_visible(True)

examples/axisartist/demo_ticklabel_alignment.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212

1313
def setup_axes(fig, pos):
1414
ax = fig.add_subplot(pos, axes_class=axisartist.Axes)
15-
ax.set_yticks([0.2, 0.8])
16-
ax.set_yticklabels(["short", "loooong"])
17-
ax.set_xticks([0.2, 0.8])
18-
ax.set_xticklabels([r"$\frac{1}{2}\pi$", r"$\pi$"])
15+
ax.set_yticks([0.2, 0.8], labels=["short", "loooong"])
16+
ax.set_xticks([0.2, 0.8], labels=[r"$\frac{1}{2}\pi$", r"$\pi$"])
1917
return ax
2018

2119

examples/images_contours_and_fields/image_annotated_heatmap.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,9 @@
5959
fig, ax = plt.subplots()
6060
im = ax.imshow(harvest)
6161

62-
# We want to show all ticks...
63-
ax.set_xticks(np.arange(len(farmers)))
64-
ax.set_yticks(np.arange(len(vegetables)))
65-
# ... and label them with the respective list entries
66-
ax.set_xticklabels(farmers)
67-
ax.set_yticklabels(vegetables)
62+
# Show all ticks and label them with the respective list entries
63+
ax.set_xticks(np.arange(len(farmers)), labels=farmers)
64+
ax.set_yticks(np.arange(len(vegetables)), labels=vegetables)
6865

6966
# Rotate the tick labels and set their alignment.
7067
plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
@@ -133,12 +130,9 @@ def heatmap(data, row_labels, col_labels, ax=None,
133130
cbar = ax.figure.colorbar(im, ax=ax, **cbar_kw)
134131
cbar.ax.set_ylabel(cbarlabel, rotation=-90, va="bottom")
135132

136-
# We want to show all ticks...
137-
ax.set_xticks(np.arange(data.shape[1]))
138-
ax.set_yticks(np.arange(data.shape[0]))
139-
# ... and label them with the respective list entries.
140-
ax.set_xticklabels(col_labels)
141-
ax.set_yticklabels(row_labels)
133+
# Show all ticks and label them with the respective list entries.
134+
ax.set_xticks(np.arange(data.shape[1]), labels=col_labels)
135+
ax.set_yticks(np.arange(data.shape[0]), labels=row_labels)
142136

143137
# Let the horizontal axes labeling appear on top.
144138
ax.tick_params(top=True, bottom=False,

examples/lines_bars_and_markers/bar_label_demo.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@
4040
ax.axhline(0, color='grey', linewidth=0.8)
4141
ax.set_ylabel('Scores')
4242
ax.set_title('Scores by group and gender')
43-
ax.set_xticks(ind)
44-
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))
43+
ax.set_xticks(ind, labels=['G1', 'G2', 'G3', 'G4', 'G5'])
4544
ax.legend()
4645

4746
# Label with label_type 'center' instead of the default 'edge'
@@ -66,8 +65,7 @@
6665
fig, ax = plt.subplots()
6766

6867
hbars = ax.barh(y_pos, performance, xerr=error, align='center')
69-
ax.set_yticks(y_pos)
70-
ax.set_yticklabels(people)
68+
ax.set_yticks(y_pos, labels=people)
7169
ax.invert_yaxis() # labels read top-to-bottom
7270
ax.set_xlabel('Performance')
7371
ax.set_title('How fast do you want to go today?')
@@ -84,8 +82,7 @@
8482
fig, ax = plt.subplots()
8583

8684
hbars = ax.barh(y_pos, performance, xerr=error, align='center')
87-
ax.set_yticks(y_pos)
88-
ax.set_yticklabels(people)
85+
ax.set_yticks(y_pos, labels=people)
8986
ax.invert_yaxis() # labels read top-to-bottom
9087
ax.set_xlabel('Performance')
9188
ax.set_title('How fast do you want to go today?')

0 commit comments

Comments
 (0)