Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b734475

Browse files
committed
DOC: Make ftface_props example generate a font metrics figure
The example only printed to stdout with no visual output, so Sphinx Gallery could not auto-generate a thumbnail. Added a matplotlib figure that visualises the font metrics (ascender, descender, bbox, underline position/thickness) normalised to units_per_EM using the same font loaded in the example. Closes #17479
1 parent 315010b commit b734475

1 file changed

Lines changed: 54 additions & 17 deletions

File tree

galleries/examples/misc/ftface_props.py

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import os
1212

13+
import matplotlib.pyplot as plt
14+
1315
import matplotlib
1416
import matplotlib.ft2font as ft
1517

@@ -18,33 +20,23 @@
1820
os.path.join(matplotlib.get_data_path(),
1921
'fonts/ttf/DejaVuSans-Oblique.ttf'))
2022

21-
print('Num instances: ', font.num_named_instances) # number of named instances in file
22-
print('Num faces: ', font.num_faces) # number of faces in file
23-
print('Num glyphs: ', font.num_glyphs) # number of glyphs in the face
24-
print('Family name: ', font.family_name) # face family name
25-
print('Style name: ', font.style_name) # face style name
26-
print('PS name: ', font.postscript_name) # the postscript name
27-
print('Num fixed: ', font.num_fixed_sizes) # number of embedded bitmaps
23+
print('Num instances: ', font.num_named_instances)
24+
print('Num faces: ', font.num_faces)
25+
print('Num glyphs: ', font.num_glyphs)
26+
print('Family name: ', font.family_name)
27+
print('Style name: ', font.style_name)
28+
print('PS name: ', font.postscript_name)
29+
print('Num fixed: ', font.num_fixed_sizes)
2830

29-
# the following are only available if face.scalable
3031
if font.scalable:
31-
# the face global bounding box (xmin, ymin, xmax, ymax)
3232
print('Bbox: ', font.bbox)
33-
# number of font units covered by the EM
3433
print('EM: ', font.units_per_EM)
35-
# the ascender in 26.6 units
3634
print('Ascender: ', font.ascender)
37-
# the descender in 26.6 units
3835
print('Descender: ', font.descender)
39-
# the height in 26.6 units
4036
print('Height: ', font.height)
41-
# maximum horizontal cursor advance
4237
print('Max adv width: ', font.max_advance_width)
43-
# same for vertical layout
4438
print('Max adv height: ', font.max_advance_height)
45-
# vertical position of the underline bar
4639
print('Underline pos: ', font.underline_position)
47-
# vertical thickness of the underline
4840
print('Underline thickness:', font.underline_thickness)
4941

5042
for flag in ft.StyleFlags:
@@ -54,3 +46,48 @@
5446
for flag in ft.FaceFlags:
5547
name = flag.name.replace('_', ' ').title() + ':'
5648
print(f"{name:17}", flag in font.face_flags)
49+
50+
# ── Visualise font metrics ──────────────────────────────────────────────────
51+
if font.scalable:
52+
u = font.units_per_EM # normalise every value: divide by EM = 1.0
53+
54+
ascender = font.ascender / u
55+
descender = font.descender / u
56+
bbox_ymax = font.bbox[3] / u
57+
bbox_ymin = font.bbox[1] / u
58+
ul_pos = font.underline_position / u
59+
ul_thick = font.underline_thickness / u
60+
61+
fig, ax = plt.subplots(figsize=(5, 4))
62+
63+
ax.text(0.15, 0, "Ag", fontsize=74, va='baseline',
64+
fontfamily='DejaVu Sans', color='black', zorder=3)
65+
66+
metrics = [
67+
("ascender", ascender, "tab:blue"),
68+
("baseline (y=0)", 0, "black"),
69+
("descender", descender, "tab:red"),
70+
("bbox top (ymax)", bbox_ymax, "tab:green"),
71+
("bbox bottom (ymin)", bbox_ymin, "tab:purple"),
72+
("underline_position", ul_pos, "tab:orange"),
73+
]
74+
75+
for label, y, color in metrics:
76+
ax.axhline(y, color=color, linewidth=1, linestyle='--', alpha=0.8)
77+
ax.text(0.82, y, label, color=color, va='center',
78+
fontsize=7.5, clip_on=True)
79+
80+
ax.axhspan(ul_pos - ul_thick, ul_pos,
81+
color='tab:orange', alpha=0.25,
82+
label=f'underline_thickness = {font.underline_thickness}')
83+
84+
ax.set_xlim(0, 1.55)
85+
ax.set_ylim(bbox_ymin - 0.05, bbox_ymax + 0.05)
86+
ax.set_title(
87+
f"Font metrics — {font.family_name} {font.style_name}\n"
88+
f"(values normalised to units_per_EM = {font.units_per_EM})"
89+
)
90+
ax.legend(fontsize=7, loc='lower right')
91+
ax.axis('off')
92+
plt.tight_layout()
93+
plt.show()

0 commit comments

Comments
 (0)