From b715ddb39340129a5684d1a53b44d5804c0a800e Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:10:34 +0530 Subject: [PATCH 01/15] Allow font manager to parse all families --- lib/matplotlib/font_manager.py | 65 +++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 9d45575eb13d..fd9b4c139a2e 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -23,6 +23,7 @@ # - setWeights function needs improvement # - 'light' is an invalid weight value, remove it. +from collections import OrderedDict import dataclasses from functools import lru_cache import json @@ -1019,6 +1020,19 @@ def json_load(filename): return json.load(fh, object_hook=_json_decode) +class FontsPath: + """Class to hold the result of findfont""" + def __init__(self, file_paths): + self._filepaths = None + self.set_filepaths(file_paths) + + def set_filepaths(self, file_paths): + self._filepaths = file_paths + + def get_filepaths(self): + return self._filepaths + + def _normalize_font_family(family): if isinstance(family, str): family = [family] @@ -1304,16 +1318,39 @@ def findfont(self, prop, fontext='ttf', directory=None, rc_params = tuple(tuple(rcParams[key]) for key in [ "font.serif", "font.sans-serif", "font.cursive", "font.fantasy", "font.monospace"]) - return self._findfont_cached( - prop, fontext, directory, fallback_to_default, rebuild_if_missing, - rc_params) + + prop = FontProperties._from_any(prop) + ffamily = prop.get_family() + + # maintain two dicts, one for available paths, + # the other for fallback paths + fpaths, fbpaths = OrderedDict(), OrderedDict() + for fidx in range(len(ffamily)): + prop = prop.copy() + + # set current prop's family + prop.set_family(ffamily[fidx]) + + fpath = self._findfont_cached( + FontProperties._from_any(prop), fontext, directory, + fallback_to_default, rebuild_if_missing, rc_params) + + # if fontfile isn't found, fpath will be a FontsPath object + if isinstance(fpath, FontsPath): + fbpaths.update(fpath.get_filepaths()) + else: + fpaths[ffamily[fidx]] = fpath + + # append fallback font(s) to the very end + fpaths.update(fbpaths) + + return FontsPath(fpaths) + @lru_cache() def _findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params): - prop = FontProperties._from_any(prop) - fname = prop.get_file() if fname is not None: return fname @@ -1401,7 +1438,10 @@ def is_opentype_cff_font(filename): @lru_cache(64) -def _get_font(filename, hinting_factor, *, _kerning_factor, thread_id): +def _get_font(filenames, hinting_factor, *, _kerning_factor, thread_id): + # TODO: allow multiple files (future PR) + # for now just pass the first element + filename = filenames[0] return ft2font.FT2Font( filename, hinting_factor, _kerning_factor=_kerning_factor) @@ -1417,11 +1457,20 @@ def _get_font(filename, hinting_factor, *, _kerning_factor, thread_id): def get_font(filename, hinting_factor=None): # Resolving the path avoids embedding the font twice in pdf/ps output if a # single font is selected using two different relative paths. - filename = _cached_realpath(filename) + if isinstance(filename, FontsPath): + filenames = [] + for fname in filename.get_filepaths().values(): + filenames.append(_cached_realpath(fname)) + else: + filenames = [_cached_realpath(filename)] if hinting_factor is None: hinting_factor = rcParams['text.hinting_factor'] + + # convert to tuple so its hashable + filenames = tuple(filenames) + # also key on the thread ID to prevent segfaults with multi-threading - return _get_font(filename, hinting_factor, + return _get_font(filenames, hinting_factor, _kerning_factor=rcParams['text.kerning_factor'], thread_id=threading.get_ident()) From 2b58d1603ead6079aa4ff3734fee61e5b403f9bc Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:57:03 +0530 Subject: [PATCH 02/15] Refactor and remove FontsPath class --- lib/matplotlib/font_manager.py | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index fd9b4c139a2e..672d4ea6fcc7 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1020,19 +1020,6 @@ def json_load(filename): return json.load(fh, object_hook=_json_decode) -class FontsPath: - """Class to hold the result of findfont""" - def __init__(self, file_paths): - self._filepaths = None - self.set_filepaths(file_paths) - - def set_filepaths(self, file_paths): - self._filepaths = file_paths - - def get_filepaths(self): - return self._filepaths - - def _normalize_font_family(family): if isinstance(family, str): family = [family] @@ -1335,16 +1322,16 @@ def findfont(self, prop, fontext='ttf', directory=None, FontProperties._from_any(prop), fontext, directory, fallback_to_default, rebuild_if_missing, rc_params) - # if fontfile isn't found, fpath will be a FontsPath object - if isinstance(fpath, FontsPath): - fbpaths.update(fpath.get_filepaths()) + # if fontfile isn't found, fpath will be an OrderedDict + if isinstance(fpath, OrderedDict): + fbpaths.update(fpath) else: fpaths[ffamily[fidx]] = fpath # append fallback font(s) to the very end fpaths.update(fbpaths) - return FontsPath(fpaths) + return fpaths @lru_cache() @@ -1457,9 +1444,9 @@ def _get_font(filenames, hinting_factor, *, _kerning_factor, thread_id): def get_font(filename, hinting_factor=None): # Resolving the path avoids embedding the font twice in pdf/ps output if a # single font is selected using two different relative paths. - if isinstance(filename, FontsPath): + if isinstance(filename, OrderedDict): filenames = [] - for fname in filename.get_filepaths().values(): + for fname in filename.values(): filenames.append(_cached_realpath(fname)) else: filenames = [_cached_realpath(filename)] From 1235063bd1609754540dec73343c99aeb3979391 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:58:37 +0530 Subject: [PATCH 03/15] Pass only first font for PDF backend --- lib/matplotlib/backends/backend_pdf.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 10063bd9a7b3..55138fddd7ea 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -829,11 +829,16 @@ def fontName(self, fontprop): if isinstance(fontprop, str): filename = fontprop - elif mpl.rcParams['pdf.use14corefonts']: - filename = findfont( - fontprop, fontext='afm', directory=RendererPdf._afm_font_dir) else: - filename = findfont(fontprop) + if mpl.rcParams['pdf.use14corefonts']: + filename = findfont( + fontprop, fontext='afm', directory=RendererPdf._afm_font_dir) + else: + filename = findfont(fontprop) + + # TODO: allow multiple fonts for PDF backend + # for now settle with the first element + filename = next(iter(filename.values())) Fx = self.fontNames.get(filename) if Fx is None: From df939d55e4879bbfb8f9d81da48a84f7361aa976 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:58:48 +0530 Subject: [PATCH 04/15] Pass only first font for mathtext --- lib/matplotlib/_mathtext.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index 3cc90e1f7501..e9306606d1e6 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -242,6 +242,9 @@ def destroy(self): def _get_font(self, font): if font in self.fontmap: basename = self.fontmap[font] + # TODO: allow multiple fonts + # for now settle with the first element + basename = next(iter(basename.values())) else: basename = font cached_font = self._fonts.get(basename) From 5215f1f16167350e433a1287d1b7c174b1f99e95 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:59:16 +0530 Subject: [PATCH 05/15] Fix check for cmr10 path --- lib/matplotlib/ticker.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 2831069ab222..0419111c6754 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -483,10 +483,12 @@ def __init__(self, useOffset=None, useMathText=None, useLocale=None): ), fallback_to_default=False, ) + # visit all values + ufont = ufont.values() except ValueError: ufont = None - if ufont == str(cbook._get_data_path("fonts/ttf/cmr10.ttf")): + if str(cbook._get_data_path("fonts/ttf/cmr10.ttf")) in ufont: _api.warn_external( "cmr10 font should ideally be used with " "mathtext, set axes.formatter.use_mathtext to True" From dc8e5ee57a4edc717c02bfbe9e232d64eb21e32f Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 18:59:44 +0530 Subject: [PATCH 06/15] Fix mathtext test with first font --- lib/matplotlib/tests/test_mathtext.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 22079ccf9874..63d020963f6e 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -225,6 +225,8 @@ def test_mathfont_rendering(baseline_images, fontset, index, text): def test_fontinfo(): fontpath = mpl.font_manager.findfont("DejaVu Sans") + # get the first element + fontpath = next(iter(fontpath.values())) font = mpl.ft2font.FT2Font(fontpath) table = font.get_sfnt_table("head") assert table['version'] == (1, 0) From fb43b67b859b5377dd05a15f4f7d6f2072b3f80b Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 19:19:53 +0530 Subject: [PATCH 07/15] Flake8 fixes --- lib/matplotlib/backends/backend_pdf.py | 6 +++--- lib/matplotlib/font_manager.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 55138fddd7ea..7b60257f90c3 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -830,9 +830,9 @@ def fontName(self, fontprop): if isinstance(fontprop, str): filename = fontprop else: - if mpl.rcParams['pdf.use14corefonts']: - filename = findfont( - fontprop, fontext='afm', directory=RendererPdf._afm_font_dir) + if mpl.rcParams["pdf.use14corefonts"]: + filename = findfont(fontprop, fontext="afm", + directory=RendererPdf._afm_font_dir) else: filename = findfont(fontprop) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 672d4ea6fcc7..0181b6d69361 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1333,7 +1333,6 @@ def findfont(self, prop, fontext='ttf', directory=None, return fpaths - @lru_cache() def _findfont_cached(self, prop, fontext, directory, fallback_to_default, rebuild_if_missing, rc_params): From 4aa661d4d1fc2fe0af03656861cfec097bfb5860 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 19:49:26 +0530 Subject: [PATCH 08/15] Fix check again --- lib/matplotlib/ticker.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 0419111c6754..6e11a5dda818 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -488,7 +488,10 @@ def __init__(self, useOffset=None, useMathText=None, useLocale=None): except ValueError: ufont = None - if str(cbook._get_data_path("fonts/ttf/cmr10.ttf")) in ufont: + if ( + ufont is not None and + str(cbook._get_data_path("fonts/ttf/cmr10.ttf")) in ufont + ): _api.warn_external( "cmr10 font should ideally be used with " "mathtext, set axes.formatter.use_mathtext to True" From af4cef6b69d5b244fa941e947d791e2ab135a578 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 19:49:46 +0530 Subject: [PATCH 09/15] Pass only first font for PGF --- lib/matplotlib/backends/backend_pgf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 575d2d263496..457c3fa1a9d5 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -50,7 +50,13 @@ def get_fontspec(): for family, command in zip(families, commands): # 1) Forward slashes also work on Windows, so don't mess with # backslashes. 2) The dirname needs to include a separator. - path = pathlib.Path(fm.findfont(family)) + path = fm.findfont(family) + + # TODO: Allow multiple fonts + # for now stick with the first font + path = next(iter(path.values())) + + path = pathlib.Path(path) latex_fontspec.append(r"\%s{%s}[Path=\detokenize{%s}]" % ( command, path.name, path.parent.as_posix() + "/")) From 9d7883167e82e70473e2454e426f43b60ca97354 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 20:07:06 +0530 Subject: [PATCH 10/15] Embed only first font --- lib/matplotlib/font_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 0181b6d69361..f36bb7e58bcd 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1098,7 +1098,9 @@ def addfont(self, path): def defaultFont(self): # Lazily evaluated (findfont then caches the result) to avoid including # the venv path in the json serialization. - return {ext: self.findfont(family, fontext=ext) + + # TODO: allow embedding multiple fonts + return {ext: next(iter(self.findfont(family, fontext=ext).values())) for ext, family in self.defaultFamily.items()} def get_default_weight(self): From a2da73d280002058858e36d99f33ea426cf4f516 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 20:07:39 +0530 Subject: [PATCH 11/15] Pass only first font for pdf_ps --- lib/matplotlib/backends/_backend_pdf_ps.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/backends/_backend_pdf_ps.py b/lib/matplotlib/backends/_backend_pdf_ps.py index 780e79bf71b8..a66c3d675972 100644 --- a/lib/matplotlib/backends/_backend_pdf_ps.py +++ b/lib/matplotlib/backends/_backend_pdf_ps.py @@ -108,6 +108,10 @@ def get_text_width_height_descent(self, s, prop, ismath): def _get_font_afm(self, prop): fname = font_manager.findfont( prop, fontext="afm", directory=self._afm_font_dir) + + # TODO: allow multiple font caching + # for now pass the first font + fname = next(iter(fname.values())) return _cached_get_afm_from_fname(fname) def _get_font_ttf(self, prop): From fb8c80a7519f086fdc36ef45f8e2efe4985b9e7c Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Wed, 23 Jun 2021 20:08:01 +0530 Subject: [PATCH 12/15] Fix font manager test --- lib/matplotlib/tests/test_font_manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_font_manager.py b/lib/matplotlib/tests/test_font_manager.py index 4cad797b3757..d5c9be39c47a 100644 --- a/lib/matplotlib/tests/test_font_manager.py +++ b/lib/matplotlib/tests/test_font_manager.py @@ -24,7 +24,8 @@ def test_font_priority(): 'font.sans-serif': ['cmmi10', 'Bitstream Vera Sans']}): font = findfont(FontProperties(family=["sans-serif"])) - assert Path(font).name == 'cmmi10.ttf' + # first font should be cmmi10.ttf + assert Path(next(iter(font.values()))).name == 'cmmi10.ttf' # Smoketest get_charmap, which isn't used internally anymore font = get_font(font) @@ -110,7 +111,7 @@ def test_utf16m_sfnt(): def test_find_ttc(): fp = FontProperties(family=["WenQuanYi Zen Hei"]) - if Path(findfont(fp)).name != "wqy-zenhei.ttc": + if "wqy-zenhei.ttc" not in map(lambda x: Path(x).name, findfont(fp)): pytest.skip("Font may be missing") fig, ax = plt.subplots() From 804a4571f43be0f8bf5e60bc1b82c98c423e89c7 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Thu, 24 Jun 2021 03:51:40 +0530 Subject: [PATCH 13/15] Fix text tests --- lib/matplotlib/tests/test_text.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index dccb74ba0038..cb1c5d64e288 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -27,7 +27,7 @@ def test_font_styles(): def find_matplotlib_font(**kw): prop = FontProperties(**kw) path = findfont(prop, directory=mpl.get_data_path()) - return FontProperties(fname=path) + return FontProperties(fname=next(iter(path.values()))) from matplotlib.font_manager import FontProperties, findfont warnings.filterwarnings( @@ -198,6 +198,7 @@ def test_antialiasing(): def test_afm_kerning(): fn = mpl.font_manager.findfont("Helvetica", fontext="afm") + fn = next(iter(fn.values())) with open(fn, 'rb') as fh: afm = mpl.afm.AFM(fh) assert afm.string_width_height('VAVAVAVAVAVA') == (7174.0, 718) From 1dd195cf38afe2c6d8a396015cf4c9b58a8883be Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Fri, 25 Jun 2021 17:03:22 +0530 Subject: [PATCH 14/15] Variable name fix --- lib/matplotlib/font_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index f36bb7e58bcd..2234bf29e37d 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1315,13 +1315,13 @@ def findfont(self, prop, fontext='ttf', directory=None, # the other for fallback paths fpaths, fbpaths = OrderedDict(), OrderedDict() for fidx in range(len(ffamily)): - prop = prop.copy() + cprop = prop.copy() # set current prop's family - prop.set_family(ffamily[fidx]) + cprop.set_family(ffamily[fidx]) fpath = self._findfont_cached( - FontProperties._from_any(prop), fontext, directory, + FontProperties._from_any(cprop), fontext, directory, fallback_to_default, rebuild_if_missing, rc_params) # if fontfile isn't found, fpath will be an OrderedDict From 6c4c4100f7619de8a064dab6a6aa9356195155b0 Mon Sep 17 00:00:00 2001 From: Aitik Gupta Date: Sat, 26 Jun 2021 03:19:06 +0530 Subject: [PATCH 15/15] Fix findfont examples --- examples/misc/logos2.py | 4 ++-- examples/text_labels_and_annotations/font_table.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/misc/logos2.py b/examples/misc/logos2.py index 528f09e92c18..bae838be6ad0 100644 --- a/examples/misc/logos2.py +++ b/examples/misc/logos2.py @@ -20,10 +20,10 @@ def get_font_properties(): # The original font is Calibri, if that is not installed, we fall back # to Carlito, which is metrically equivalent. - if 'Calibri' in matplotlib.font_manager.findfont('Calibri:bold'): + if 'Calibri' in matplotlib.font_manager.findfont('Calibri:bold').keys(): return matplotlib.font_manager.FontProperties(family='Calibri', weight='bold') - if 'Carlito' in matplotlib.font_manager.findfont('Carlito:bold'): + if 'Carlito' in matplotlib.font_manager.findfont('Carlito:bold').keys(): print('Original font not found. Falling back to Carlito. ' 'The logo text will not be in the correct font.') return matplotlib.font_manager.FontProperties(family='Carlito', diff --git a/examples/text_labels_and_annotations/font_table.py b/examples/text_labels_and_annotations/font_table.py index e9296430ac13..0ef5877c0d42 100644 --- a/examples/text_labels_and_annotations/font_table.py +++ b/examples/text_labels_and_annotations/font_table.py @@ -34,6 +34,7 @@ def print_glyphs(path): """ if path is None: path = fm.findfont(fm.FontProperties()) # The default font. + path = next(iter(path.values())) # Get the first filepath font = FT2Font(path) @@ -60,6 +61,7 @@ def draw_font_table(path): """ if path is None: path = fm.findfont(fm.FontProperties()) # The default font. + path = next(iter(path.values())) # Get the first filepath font = FT2Font(path) # A charmap is a mapping of "character codes" (in the sense of a character pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy