@@ -948,24 +948,6 @@ def copy(self):
948
948
return new
949
949
950
950
951
- class FontsInterface :
952
- def __init__ (self , ordered_family ):
953
- self .set_orderedfamily (ordered_family )
954
-
955
- def set_orderedfamily (self , ordered_family ):
956
- self .families = []
957
- self .filepaths = []
958
- for key , value in ordered_family .items ():
959
- self .families .append (key )
960
- self .filepaths .append (value )
961
-
962
- def get_families (self ):
963
- return self .families
964
-
965
- def get_filepaths (self ):
966
- return self .filepaths
967
-
968
-
969
951
class _JSONEncoder (json .JSONEncoder ):
970
952
def default (self , o ):
971
953
if isinstance (o , FontManager ):
@@ -1333,36 +1315,97 @@ def findfont(self, prop, fontext='ttf', directory=None,
1333
1315
1334
1316
def find_fontsprop (self , prop , fontext = 'ttf' , directory = None ,
1335
1317
fallback_to_default = True , rebuild_if_missing = True ):
1318
+ """
1319
+ Find font families that most closely matches the given properties.
1320
+
1321
+ Parameters
1322
+ ----------
1323
+ prop : str or `~matplotlib.font_manager.FontProperties`
1324
+ The font properties to search for. This can be either a
1325
+ `.FontProperties` object or a string defining a
1326
+ `fontconfig patterns`_.
1327
+
1328
+ fontext : {'ttf', 'afm'}, default: 'ttf'
1329
+ The extension of the font file:
1330
+
1331
+ - 'ttf': TrueType and OpenType fonts (.ttf, .ttc, .otf)
1332
+ - 'afm': Adobe Font Metrics (.afm)
1333
+
1334
+ directory : str, optional
1335
+ If given, only search this directory and its subdirectories.
1336
+
1337
+ fallback_to_default : bool
1338
+ If True, will fallback to the default font family (usually
1339
+ "DejaVu Sans" or "Helvetica") if none of the families were found.
1340
+
1341
+ rebuild_if_missing : bool
1342
+ Whether to rebuild the font cache and search again if the first
1343
+ match appears to point to a nonexisting font (i.e., the font cache
1344
+ contains outdated entries).
1345
+
1346
+ Returns
1347
+ -------
1348
+ OrderedDict
1349
+ key, value pair of families and their corresponding filepaths.
1350
+
1351
+ Notes
1352
+ -----
1353
+ This is a plugin to original findfont API, which only returns a
1354
+ single font for given font properties. Instead, this API returns
1355
+ an OrderedDict containing multiple fonts and their filepaths which
1356
+ closely match the given font properties.
1357
+ Since this internally uses original API, there's no change
1358
+ to the logic of performing the nearest neighbor search.
1359
+ See `findfont` for more details.
1360
+
1361
+ """
1362
+
1363
+ rc_params = tuple (tuple (rcParams [key ]) for key in [
1364
+ "font.serif" , "font.sans-serif" , "font.cursive" , "font.fantasy" ,
1365
+ "font.monospace" ])
1336
1366
1337
1367
prop = FontProperties ._from_any (prop )
1338
1368
ffamily = prop .get_family ()
1339
1369
1340
- # maintain two dicts, one for available paths,
1341
- # the other for fallback paths
1342
- fpaths , fbpaths = OrderedDict (), OrderedDict ()
1370
+ fpaths = OrderedDict ()
1343
1371
for fidx in range (len (ffamily )):
1344
1372
cprop = prop .copy ()
1345
1373
1346
1374
# set current prop's family
1347
1375
cprop .set_family (ffamily [fidx ])
1348
1376
1349
1377
try :
1350
- fpath = self .findfont (cprop , fontext , directory ,
1351
- False , rebuild_if_missing )
1378
+ fpath = self ._findfont_cached (
1379
+ cprop , fontext , directory ,
1380
+ False , rebuild_if_missing , rc_params
1381
+ )
1352
1382
fpaths [ffamily [fidx ]] = fpath
1383
+ except ValueError :
1384
+ _log .warning (
1385
+ 'findfont: Font family [\' %s\' ] not found.' , ffamily [fidx ]
1386
+ )
1387
+ if ffamily [fidx ].lower () in font_family_aliases :
1388
+ _log .warning (
1389
+ "findfont: Generic family [%r] not found because "
1390
+ "none of the following families were found: %s" ,
1391
+ ffamily [fidx ],
1392
+ ", " .join (self ._expand_aliases (ffamily [fidx ]))
1393
+ )
1394
+
1395
+ if not fpaths :
1396
+ if fallback_to_default :
1397
+ dfamily = self .defaultFamily [fontext ]
1398
+ cprop = prop .copy ().set_family (dfamily )
1399
+ fpath = self ._findfont_cached (
1400
+ cprop , fontext , directory ,
1401
+ True , rebuild_if_missing , rc_params
1402
+ )
1403
+ fpaths [dfamily ] = fpath
1404
+ else :
1405
+ raise ValueError ("Failed to find any font, and fallback "
1406
+ "to the default font was disabled." )
1353
1407
1354
- except ValueError as e :
1355
- if fallback_to_default :
1356
- fpath = self .findfont (cprop , fontext , directory ,
1357
- True , rebuild_if_missing )
1358
- fbpaths .update ({self .defaultFamily [fontext ]: fpath })
1359
- else :
1360
- raise e
1361
-
1362
- # append fallback font(s) to the very end
1363
- fpaths .update (fbpaths )
1364
-
1365
- return FontsInterface (fpaths )
1408
+ return fpaths
1366
1409
1367
1410
@lru_cache ()
1368
1411
def _findfont_cached (self , prop , fontext , directory , fallback_to_default ,
@@ -1473,10 +1516,10 @@ def _get_font(fpaths, hinting_factor, *, _kerning_factor, thread_id):
1473
1516
def get_font (filename , hinting_factor = None ):
1474
1517
# Resolving the path avoids embedding the font twice in pdf/ps output if a
1475
1518
# single font is selected using two different relative paths.
1476
- if isinstance (filename , FontsInterface ):
1477
- paths = tuple ([ _cached_realpath (fname ) for fname in filename .get_filepaths ()] )
1519
+ if isinstance (filename , OrderedDict ):
1520
+ paths = tuple (_cached_realpath (fname ) for fname in filename .values () )
1478
1521
else :
1479
- paths = tuple ([ _cached_realpath (filename )] )
1522
+ paths = ( _cached_realpath (filename ), )
1480
1523
if hinting_factor is None :
1481
1524
hinting_factor = rcParams ['text.hinting_factor' ]
1482
1525
# also key on the thread ID to prevent segfaults with multi-threading
0 commit comments