Как использовать символ Font Awesome в качестве маркера в matplotlib - PullRequest
0 голосов
/ 20 октября 2018

Можно ли использовать потрясающий значок шрифта в качестве маркера на диаграмме рассеяния с помощью matplotlib?Или можно использовать его как шрифт и поставить значок как «текст»?


Этот вопрос изначально задавался здесь , нобыл закрыт по неизвестной причине.Поскольку я считаю это действительной и полезной проблемой, которая нигде не решалась в Stackoverflow и, безусловно, заслуживает ответа, я просто задам ее снова.

1 Ответ

0 голосов
/ 20 октября 2018

FontAwesome доступен с здесь .Он предоставляет свои иконки в виде векторной графики, а также шрифта otf.

Использовать шрифт FontAwesome otf

Matplotlib не может изначально читать векторную графику, но может загружать otf-шрифты .После загрузки пакета FontAwesome вы можете получить доступ к шрифту через объект matplotlib.font_manager.FontProperties, например,

fp = FontProperties(fname=r"C:\Windows\Fonts\Font Awesome 5 Free-Solid-900.otf") 

Создание текстов

FontProperties может быть вводом для текстовых объектов matplotlib

plt.text(.6, .4, "\uf16c", fontproperties=fp)

К сожалению, использование FontAwesome лигатур невозможно.Следовательно, отдельные символы должны быть доступны с помощью их ключа UTF8.Это немного громоздко, но шпаргалка может пригодиться здесь.Хранение этих необходимых символов в словаре со значимым именем может иметь смысл.

Пример:

from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt

fp1 = FontProperties(fname=r"C:\Windows\Fonts\Font Awesome 5 Brands-Regular-400.otf")
fp2 = FontProperties(fname=r"C:\Windows\Fonts\Font Awesome 5 Free-Solid-900.otf")

symbols = dict(cloud = "\uf6c4", campground = "\uf6bb", hiking = "\uf6ec",
               mountain = "\uf6fc", tree = "\uf1bb", fish = "\uf578",
               stackoverflow = "\uf16c")

fig, (ax, ax2) = plt.subplots(ncols=2, figsize=(6.2, 2.2), sharey=True)
ax.text(.5, .5, symbols["stackoverflow"], fontproperties=fp1, size=100, 
         color="orange", ha="center", va="center")


ax2.stackplot([0,.3,.55,.6,.65,1],[.1,.2,.2,.2,.2,.15],[.3,.2,.2,.3,.2,.2],
              colors=["paleturquoise", "palegreen"])
ax2.axis([0,1,0,1])
ax2.text(.6, .4, symbols["mountain"], fontproperties=fp2, size=16, ha="center")
ax2.text(.09, .23, symbols["campground"], fontproperties=fp2, size=13)
ax2.text(.22, .27, symbols["hiking"], fontproperties=fp2, size=14)
ax2.text(.7, .24, symbols["tree"], fontproperties=fp2, size=14,color="forestgreen")
ax2.text(.8, .33, symbols["tree"], fontproperties=fp2, size=14,color="forestgreen")
ax2.text(.88, .28, symbols["tree"], fontproperties=fp2, size=14,color="forestgreen")
ax2.text(.35, .03, symbols["fish"], fontproperties=fp2, size=14,)
ax2.text(.2, .7, symbols["cloud"], fontproperties=fp2, size=28,)

plt.show()

enter image description here

Создание маркеров

Создание большого количества текстов, как указано выше, не очень удобно.Иметь значки в качестве маркеров было бы лучше для определенных приложений.Matplotlib действительно имеет возможность использовать символы utf в качестве маркеров, однако, только через функциональность mathtext.Получение шрифта otf для использования в качестве mathfont в matplotlib было неудачным в моих испытаниях.

Альтернативой является создание matplotlib.path.Path из символа.Это можно сделать с помощью экземпляра matplotlib.textpath.TextToPath, который, к сожалению, не документирован.У TextToPath есть метод get_text_path, который принимает свойство шрифта и строку в качестве входных данных и возвращает вершины и коды, из которых можно создать Path.Path можно использовать в качестве маркера , например, для графика scatter.

v, codes = TextToPath().get_text_path(fp, \uf6fc)
path = Path(v, codes, closed=False)
plt.scatter(..., marker=path)

Некоторые примеры:

import numpy as np; np.random.seed(32)
from matplotlib.path import Path
from matplotlib.textpath import TextToPath
from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt

fp = FontProperties(fname=r"C:\Windows\Fonts\Font Awesome 5 Free-Solid-900.otf")

symbols = dict(cloud = "\uf6c4", campground = "\uf6bb", hiking = "\uf6ec",
               mountain = "\uf6fc", tree = "\uf1bb", fish = "\uf578",
               stackoverflow = "\uf16c")

fig, ax = plt.subplots()

def get_marker(symbol):
    v, codes = TextToPath().get_text_path(fp, symbol)
    v = np.array(v)
    mean = np.mean([np.max(v,axis=0), np.min(v, axis=0)], axis=0)
    return Path(v-mean, codes, closed=False)

x = np.random.randn(4,10)
c = np.random.rand(10)
s = np.random.randint(120,500, size=10)
plt.scatter(*x[:2], s=s, c=c, marker=get_marker(symbols["cloud"]), 
            edgecolors="none", linewidth=2)
plt.scatter(*x[2:], s=s, c=c, marker=get_marker(symbols["fish"]), 
            edgecolors="none", linewidth=2)   

plt.show()

enter image description here

...