DOC: Add thumbnail for ftface_props gallery example#31321
DOC: Add thumbnail for ftface_props gallery example#31321AMAN194701 wants to merge 4 commits intomatplotlib:mainfrom
Conversation
Slightly concerned about this from a licensing point of view. @QuLogic does this seem generic enough? I think the image is descriptive. ETA: Also thanks the disclosure - it'd be a lot more of a problem if we didn't know AI was used and there was a licensing problem (I don't think that's the case here, but the knowledge helps a lot in the discussion.) |
|
Thumbnail is rendering correctly in the CI-built gallery: |
|
I'd also add this (or an even more detailed pic) to the example - I really like the markup of attributes, it explains what they are really well. |
|
It would be even nicer if it agreed with the font displayed. I doubt there are too many fonts where the ascender is so much taller than the height. |
2f8d1e8 to
3255921
Compare
|
Thanks for the feedback @jklymak and @story645! |
|
Baseline and cap height aren't listed in the font properties - can the labels match the listed properties? And also can you add a box? (I wonder if this might be easier to make in Matplotlib using the font in the example and the coordinate system in font properties) |
|
Thank you @story645 for the feedback ! |
|
Maybe it would make sense to change this example to generate that figure as well... But some care might have to be taken to handle fonts that don't have whatever sample characters we end up using. The image doesn't quite make sense though as I doubt the cap height is going to be the same as the x height, and it certainly isn't for the default DejaVu Sans. |
|
Thanks ! @QuLogic I ran the example locally and I can see what you mean — |
|
Yes, that's what I suggest. |
f9343ba to
b734475
Compare
|
Thanks @story645 and @QuLogic for the feedback! I have Updated the example to actually generate a matplotlib figure using font.bbox, font.ascender, font.descender, font.underline_position and font.underline_thickness , all normalised to units_per_EM. The thumbnail is now auto-generated by Sphinx Gallery from the figure itself, no static image needed anymore. |
story645
left a comment
There was a problem hiding this comment.
Also I was thinking plot bbox as a box around the image.
| print(f"{name:17}", flag in font.face_flags) | ||
|
|
||
| # ── Visualise font metrics ────────────────────────────────────────────────── | ||
| if font.scalable: |
There was a problem hiding this comment.
There's no reason for this if statement in an example b/c it should be known. This can be added to the image as a property if you want to use it.
|
Thanks @scottshambaugh and @story645 for the feedback ! |
|
Hi @story645 — I just want to confirm the direction before implementing. Is this roughly correct ? I'll use the actual font metrics with the real values from DejaVu Sans Oblique. |
|
Yeah + a box representing the bbox |
|
Sure, I'll add a box representing the bbox and update it shortly ! |
d840d72 to
47c30d4
Compare
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 matplotlib#17479
47c30d4 to
e6add6a
Compare
|
Hi @story645 — updated the figure with all the requested changes. Here's how it looks now: https://output.circle-artifacts.com/output/job/408bd2aa-35cd-4b4c-b0d6-098821c76163/artifacts/0/doc/build/html/gallery/misc/index.html |
|
|
||
| # ── Visualise font metrics ──────────────────────────────────────────────────── | ||
| # Normalise all metrics to units_per_EM so values are in the range [-1, 1]. | ||
| # This figure is used by Sphinx Gallery to auto-generate the gallery thumbnail. |
There was a problem hiding this comment.
This comment is unnecessary; all examples go in the gallery.
| ] | ||
|
|
||
| # Lines span from left edge to 72% of axes width — crossing through the glyph. | ||
| # Labels sit at 75%, clearly to the right of the lines. |
There was a problem hiding this comment.
Not really an important word here.
| # Labels sit at 75%, clearly to the right of the lines. | |
| # Labels sit at 75%, to the right of the lines. |
| ax.set_ylim(bbox_ymin - 0.10, bbox_ymax + 0.15) | ||
| ax.set_title( | ||
| f"Font metrics — {font.family_name} {font.style_name}\n" | ||
| f"(values normalised to units_per_EM = {font.units_per_EM})", |
There was a problem hiding this comment.
The only value shown is the underline thickness, and that one isn't normalized. I don't think this second line in the title is useful.
| va='baseline', ha='center', color='black', zorder=10) | ||
|
|
||
| ax.set_xlim(0, 1.35) | ||
| ax.set_ylim(bbox_ymin - 0.10, bbox_ymax + 0.15) |
There was a problem hiding this comment.
This is a clever way to get the lines on the plot without having to adjust the units much, but unfortunately, it's not clever enough.
The Ag text is positioned in data units, but its size is in points and thus unrelated to the Axes in any way. You can see this immediately by resizing the figure larger vertically; the text stays the same but the ascender and bbox are farther and farther away.
You need to rescale things so that they are in the same coordinate space:
- Either grab the vector outline of the text and place it in the
Axesas some kind of path, after scaling it so that it's the same units as the metrics (i.e., it should end up in data space just like your metrics), - Or, rescale the metrics as something physical, like points or pixels, and then plot them with the text; you would probably have to switch everything to be an artist manually placed on the Figure instead of the Axes.
|
Thank you so much @QuLogic for detail feedback ! |
|
Is there a character that would be near the ascender to show what ascender means? Like how g is showing the descender? |
|
Hiii.. @story645 I investigated why the ascender line isn't being touched by any glyph in the current example, and I want to share my findings along with a proposed fix. Root Cause: The font's ascender metric (
This ~0.17 EM gap exists in every font by design — So no matter which plain ASCII letter is used, none will ever physically reach the ascender line. This is why Proposed Fix: Replace the current TextPath string with # font.ascender is the font-wide maximum height (includes accented glyphs
# like Ĥ, Â). Plain letters like b, h, l sit ~0.17 EM below it.
# Ĥ reaches ~0.926 EM ≈ ascender, just as g crosses the descender line.
# Before (current in PR)
tp = TextPath((0, 0), "Ag", size=1, prop=fp)
# After
tp = TextPath((0, 0), "Ĥg", size=1, prop=fp)Why this works:
I've tested this locally and attached the output below. Alternative options if you prefer a different character:
Happy to go ahead with Thanks |







Problem :
The ftface_props example does not generate a gallery thumbnail as it produces no visual output.
Cause :
The example only prints font properties to stdout and does not call plt.savefig() or plt.show(), so Sphinx Gallery cannot auto-generate a thumbnail.
Fix :
Added a custom SVG thumbnail using sphinx_gallery_thumbnail_path. The thumbnail illustrates key font metrics (ascender, cap height, baseline, descender) using the letters "Ag" with annotated reference lines.
Closes #17479
AI Disclosure
I used AI assistance to help generate and iterate on the SVG thumbnail design.