Caratteri in Matplotlib #

Matplotlib ha bisogno di caratteri per funzionare con il suo motore di testo, alcuni dei quali vengono spediti insieme all'installazione. Il carattere predefinito è DejaVu Sans che copre la maggior parte dei sistemi di scrittura europei. Tuttavia, gli utenti possono configurare i caratteri predefiniti e fornire i propri caratteri personalizzati. Vedere Personalizzazione delle proprietà del testo per i dettagli e Testo con glifi non latini in particolare per i glifi non supportati da DejaVu Sans.

Matplotlib fornisce anche un'opzione per scaricare il rendering del testo su un motore TeX ( usetex=True), vedere Rendering del testo con LaTeX .

Font in PDF e PostScript #

I caratteri hanno una lunga (e talvolta incompatibile) storia nell'informatica, portando a diverse piattaforme che supportano diversi tipi di caratteri. In pratica, ci sono 3 tipi di specifiche dei caratteri supportate da Matplotlib (oltre ai "caratteri principali" in pdf che sono spiegati più avanti nella guida):

Tipo di carattere #

Tipo 1 (PDF)

Tipo 3 (PDF/PS)

Tipo True (PDF)

Uno dei tipi più vecchi, introdotto da Adobe

Simile al Tipo 1 in termini di introduzione

Tipi più recenti dei precedenti, usati comunemente oggi, introdotti da Apple

Sottoinsieme ristretto di PostScript, le stringhe di caratteri sono in bytecode

Linguaggio PostScript completo, consente l'incorporamento di codice arbitrario (in teoria, persino il rendering dei frattali durante la rasterizzazione!)

Includi una macchina virtuale in grado di eseguire codice!

Questi caratteri supportano i suggerimenti sui caratteri

Non supporta i suggerimenti sui caratteri

Suggerimenti supportati (la macchina virtuale elabora i "suggerimenti")

Non sottoinsieme tramite Matplotlib

Subsetted tramite modulo esterno ttconv

Sottoinsieme tramite il modulo esterno fonttools

NOTA: Adobe disattiverà il supporto per la creazione con i font Type 1 nel gennaio 2023. Maggiori informazioni qui.

Altre specifiche dei caratteri supportate da Matplotlib:

  • Digitare 42 caratteri (PS):

  • Font OpenType:

    • OpenType è un nuovo standard per i caratteri di tipo digitale, sviluppato congiuntamente da Adobe e Microsoft

    • Generalmente contengono un set di caratteri molto più grande!

    • Supporto limitato con Matplotlib

Sottoimpostazione carattere #

I formati PDF e PostScript supportano l'incorporamento di caratteri nei file consentendo al programma di visualizzazione di visualizzare correttamente il testo, indipendentemente dai caratteri installati sul computer del visualizzatore e senza la necessità di pre-rasterizzare il testo. Ciò garantisce che se l'output viene ingrandito o ridimensionato, il testo non diventa pixelato. Tuttavia, l'incorporamento di caratteri completi nel file può portare a file di output di grandi dimensioni, in particolare con caratteri con molti glifi come quelli che supportano CJK (cinese/giapponese/coreano).

La soluzione a questo problema è creare un sottoinsieme dei caratteri utilizzati nel documento e incorporare solo i glifi effettivamente utilizzati. Questo ottiene sia testo vettoriale che file di piccole dimensioni. Il calcolo del sottoinsieme del carattere richiesto e la scrittura del nuovo carattere (ridotto) sono entrambi problemi complessi e quindi Matplotlib si basa su fontTools e su un fork fornito di ttconv .

Attualmente i font Type 3, Type 42 e TrueType sono sottoinsiemi. I caratteri di tipo 1 non lo sono.

Caratteri principali #

Oltre alla possibilità di incorporare font, come parte delle specifiche PostScript e PDF ci sono 14 Core Font che i visualizzatori conformi devono garantire siano disponibili. Se limiti il ​​tuo documento solo a questi caratteri, non devi incorporare alcuna informazione sui caratteri nel documento ma ottieni comunque testo vettoriale.

Ciò è particolarmente utile per generare documenti davvero leggeri .:

# trigger core fonts for PDF backend
plt.rcParams["pdf.use14corefonts"] = True
# trigger core fonts for PS backend
plt.rcParams["ps.useafm"] = True

chars = "AFM ftw!"
fig, ax = plt.subplots()
ax.text(0.5, 0.5, chars)

fig.savefig("AFM_PDF.pdf", format="pdf")
fig.savefig("AFM_PS.ps", format="ps)

Font in SVG #

Il testo può essere inviato a SVG in due modi controllati da rcParams["svg.fonttype"](predefinito: 'path'):

  • come percorso ( 'path') nell'SVG

  • come stringa nell'SVG con lo stile del carattere sull'elemento ( 'none')

Durante il salvataggio tramite 'path'Matplotlib calcolerà il percorso dei glifi usati come percorsi vettoriali e li scriverà nell'output. Il vantaggio è che l'SVG avrà lo stesso aspetto su tutti i computer, indipendentemente dai font installati. Tuttavia il testo non sarà modificabile dopo il fatto. Al contrario, il salvataggio con 'none'risulterà in file più piccoli e il testo apparirà direttamente nel markup. Tuttavia, l'aspetto può variare in base al visualizzatore SVG e ai caratteri disponibili.

Font in Agg #

Per generare testo in formati raster tramite Agg, Matplotlib si affida a FreeType . Poiché il rendering esatto dei glifi cambia tra le versioni di FreeType, applichiamo a una versione specifica per i nostri test di confronto delle immagini.

Come Matplotlib seleziona i caratteri #

L'utilizzo interno di un font in Matplotlib è un processo in tre fasi:

  1. viene creato un FontPropertiesoggetto (in modo esplicito o implicito)

  2. in base FontPropertiesall'oggetto i metodi su FontManagervengono utilizzati per selezionare il carattere "migliore" più vicino di cui Matplotlib è a conoscenza (ad eccezione della 'none'modalità di SVG).

  3. il proxy Python per l'oggetto font viene utilizzato dal codice back-end per rendere il testo - i dettagli esatti dipendono dal back-end tramite font_manager.get_font.

L'algoritmo per selezionare il carattere "migliore" è una versione modificata dell'algoritmo specificato dalle specifiche CSS1 utilizzato dai browser web. Questo algoritmo prende in considerazione il nome della famiglia del carattere (es. "Arial", "Noto Sans CJK", "Hack", ...), la dimensione, lo stile e il peso. Oltre ai cognomi che si associano direttamente ai caratteri, ci sono cinque "cognomi di famiglia di caratteri generici" (serif, monospace, fantasy, corsivo e sans-serif) che verranno mappati internamente a uno qualsiasi di un set di caratteri.

Attualmente l'API pubblica per eseguire il passaggio 2 è FontManager.findfont(e quel metodo sull'istanza globale FontManagerè aliasato a livello di modulo come font_manager.findfont), che troverà solo un singolo carattere e restituirà il percorso assoluto del carattere sul filesystem.

Carattere di riserva #

Non esiste un font che copra l'intero spazio Unicode, quindi è possibile per gli utenti richiedere un mix di glifi che non può essere soddisfatto da un singolo font. Sebbene sia stato possibile utilizzare più caratteri all'interno di una figura, in Textistanze distinte, in precedenza non era possibile utilizzare più caratteri nella stessa Textistanza (come fa un browser web). A partire da Matplotlib 3.6 i backend Agg, SVG, PDF e PS eseguiranno il "fallback" attraverso più caratteri in una singola Textistanza:

fig, ax = plt.subplots()
ax.text(
    .5, .5, "There are 几个汉字 in between!",
    family=['DejaVu Sans', 'WenQuanYi Zen Hei'],
    ha='center'
)

( Codice sorgente , png )

../../_images/fonts-1.png

La stringa "Ci sono 几个汉字 in mezzo!" reso con 2 caratteri. #

Internamente questo viene implementato impostando la "famiglia di caratteri" sugli FontPropertiesoggetti su un elenco di famiglie di caratteri. Un'API (attualmente) privata estrae un elenco di percorsi a tutti i caratteri trovati e quindi costruisce un singolo ft2font.FT2Fontoggetto che è a conoscenza di tutti i caratteri. Ogni glifo della stringa viene visualizzato utilizzando il primo carattere nell'elenco che contiene quel glifo.

La maggior parte di questo lavoro è stata svolta da Aitik Gupta con il supporto di Google Summer of Code 2021.