diff --git a/examples/text_labels_and_annotations/font_table.py b/examples/text_labels_and_annotations/font_table.py new file mode 100644 index 000000000000..2cfbd366f652 --- /dev/null +++ b/examples/text_labels_and_annotations/font_table.py @@ -0,0 +1,120 @@ +""" +========== +Font table +========== + +Matplotlib's font support is provided by the FreeType library. + +Here, we use `~.Axes.table` to draw a table that shows the glyphs by Unicode +codepoint. For brevity, the table only contains the first 256 glyphs. + +The example is a full working script. You can download it and use it to +investigate a font by running :: + + python font_table.py /path/to/font/file +""" + +import unicodedata + +import matplotlib.font_manager as fm +from matplotlib.ft2font import FT2Font +import matplotlib.pyplot as plt + + +def print_glyphs(path): + """ + Print the all glyphs in the given font file to stdout. + + Parameters + ---------- + path : str or None + The path to the font file. If None, use Matplotlib's default font. + """ + if path is None: + path = fm.findfont(fm.FontProperties()) # The default font. + + font = FT2Font(path) + + charmap = font.get_charmap() + max_indices_len = len(str(max(charmap.values()))) + + print("The font face contains the following glyphs:") + for char_code, glyph_index in charmap.items(): + char = chr(char_code) + name = unicodedata.name( + char, + f"{char_code:#x} ({font.get_glyph_name(glyph_index)})") + print(f"{glyph_index:>{max_indices_len}} {char} {name}") + + +def draw_font_table(path): + """ + Draw a font table of the first 255 chars of the given font. + + Parameters + ---------- + path : str or None + The path to the font file. If None, use Matplotlib's default font. + """ + if path is None: + path = fm.findfont(fm.FontProperties()) # The default font. + + font = FT2Font(path) + # A charmap is a mapping of "character codes" (in the sense of a character + # encoding, e.g. latin-1) to glyph indices (i.e. the internal storage table + # of the font face). + # In FreeType>=2.1, a Unicode charmap (i.e. mapping Unicode codepoints) + # is selected by default. Moreover, recent versions of FreeType will + # automatically synthesize such a charmap if the font does not include one + # (this behavior depends on the font format; for example it is present + # since FreeType 2.0 for Type 1 fonts but only since FreeType 2.8 for + # TrueType (actually, SFNT) fonts). + # The code below (specifically, the ``chr(char_code)`` call) assumes that + # we have indeed selected a Unicode charmap. + codes = font.get_charmap().items() + + labelc = ["{:X}".format(i) for i in range(16)] + labelr = ["{:02X}".format(16 * i) for i in range(16)] + chars = [["" for c in range(16)] for r in range(16)] + + for char_code, glyph_index in codes: + if char_code >= 256: + continue + row, col = divmod(char_code, 16) + chars[row][col] = chr(char_code) + + fig, ax = plt.subplots(figsize=(8, 4)) + ax.set_title(path) + ax.set_axis_off() + + table = ax.table( + cellText=chars, + rowLabels=labelr, + colLabels=labelc, + rowColours=["palegreen"] * 16, + colColours=["palegreen"] * 16, + cellColours=[[".95" for c in range(16)] for r in range(16)], + cellLoc='center', + loc='upper left', + ) + for key, cell in table.get_celld().items(): + row, col = key + if row > 0 and col > -1: # Beware of table's idiosyncratic indexing... + cell.set_text_props(fontproperties=fm.FontProperties(fname=path)) + + fig.tight_layout() + plt.show() + + +if __name__ == "__main__": + from argparse import ArgumentParser + + parser = ArgumentParser(description="Display a font table.") + parser.add_argument("path", nargs="?", help="Path to the font file.") + parser.add_argument("--print-all", action="store_true", + help="Additionally, print all chars to stdout.") + args = parser.parse_args() + + if args.print_all: + print_glyphs(args.path) + draw_font_table(args.path) diff --git a/examples/text_labels_and_annotations/font_table_ttf_sgskip.py b/examples/text_labels_and_annotations/font_table_ttf_sgskip.py deleted file mode 100644 index 6de73e68dea3..000000000000 --- a/examples/text_labels_and_annotations/font_table_ttf_sgskip.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -============== -Font Table TTF -============== - -Matplotlib has support for FreeType fonts. Here's a little example -using the 'table' command to build a font table that shows the glyphs -by character code. - -Usage python font_table_ttf.py somefile.ttf - -""" - -import sys -import os - -import matplotlib -from matplotlib.ft2font import FT2Font -from matplotlib.font_manager import FontProperties -import matplotlib.pyplot as plt - -# the font table grid - -labelc = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F'] -labelr = ['00', '10', '20', '30', '40', '50', '60', '70', '80', '90', - 'A0', 'B0', 'C0', 'D0', 'E0', 'F0'] - -if len(sys.argv) > 1: - fontname = sys.argv[1] -else: - fontname = os.path.join(matplotlib.get_data_path(), - 'fonts', 'ttf', 'DejaVuSans.ttf') - -font = FT2Font(fontname) -codes = sorted(font.get_charmap().items()) - -# a 16,16 array of character strings -chars = [['' for c in range(16)] for r in range(16)] -colors = [[(0.95, 0.95, 0.95) for c in range(16)] for r in range(16)] - -plt.figure(figsize=(8, 4), dpi=120) -for ccode, glyphind in codes: - if ccode >= 256: - continue - r, c = divmod(ccode, 16) - s = chr(ccode) - chars[r][c] = s - -lightgrn = (0.5, 0.8, 0.5) -plt.title(fontname) -tab = plt.table(cellText=chars, - rowLabels=labelr, - colLabels=labelc, - rowColours=[lightgrn] * 16, - colColours=[lightgrn] * 16, - cellColours=colors, - cellLoc='center', - loc='upper left') - -for key, cell in tab.get_celld().items(): - row, col = key - if row > 0 and col > 0: - cell.set_text_props(fontproperties=FontProperties(fname=fontname)) -plt.axis('off') -plt.show()