How to use unicode symbols in matplotlib?
Question:
import matplotlib.pyplot as pyplot
pyplot.figure()
pyplot.xlabel(u"u2736")
pyplot.show()
Here is the simplest code I can create to show my problem. The axis label symbol is meant to be a six-pointed star but it shows as a box. How do I change it so the star is shown? I’ve tried adding the comment:
#-*- coding: utf-8 -*-
like previous answers suggested but it didn’t work, as well as using matplotlib.rc
or matplotlib.rcParams
which also didn’t work. Help would be appreciated.
Answers:
You’ll need a font that has the given unicode character, STIX fonts should contain the star symbol. You’ll need to locate or download the STIX fonts, ofcourse any other ttf file with the given symbol should be fine.
import matplotlib.pyplot as pyplot
from matplotlib.font_manager import FontProperties
if __name__ == "__main__":
pyplot.figure()
prop = FontProperties()
prop.set_file('STIXGeneral.ttf')
pyplot.xlabel(u"u2736", fontproperties=prop)
pyplot.show()
To complement @arjenve’s answer. To plot a Unicode character, firstly, find which font contains this character, secondly, use that font to plot characters with Matplotlib
Find a font which contains the character
According to this post, we can use fontTools package to find which font contains the character we want to plot.
from fontTools.ttLib import TTFont
import matplotlib.font_manager as mfm
def char_in_font(unicode_char, font):
for cmap in font['cmap'].tables:
if cmap.isUnicode():
if ord(unicode_char) in cmap.cmap:
return True
return False
uni_char = u"✹"
# or uni_char = u"u2739"
font_info = [(f.fname, f.name) for f in mfm.fontManager.ttflist]
for i, font in enumerate(font_info):
if char_in_font(uni_char, TTFont(font[0])):
print(font[0], font[1])
This script will print a list of font paths and font names (all these fonts support that Unicode Character). Sample output shown below
Then, we can use the following script to plot this character (see image below)
import matplotlib.pyplot as plt
import matplotlib.font_manager as mfm
font_path = '/usr/share/fonts/gnu-free/FreeSerif.ttf'
prop = mfm.FontProperties(fname=font_path)
plt.text(0.5, 0.5, s=uni_char, fontproperties=prop, fontsize=20)
plt.show()
I was trying to implement @jdhao
code but it was constantly breaking because I also had type 0 fonts in my library.
So here’s a tweaked version of his code that does not break with type 0 fonts
and also enables finding several uni chars at once in the same font by providing the function a list
of uni chars instead of just 1 uni char.
For more details read the comments throughout the code.
#!/usr/bin/env python
from fontTools.ttLib import TTFont
import matplotlib.font_manager as mfm
def print_if_char_in_font(list_unichars, print_true_only=False):
def char_in_font(unicode_char, font):
if font.endswith('.ttc'): fontNo = 0 #default is for type -1 so type 0 fonts are going to break the code without this line
else: fontNo = -1
font=TTFont(font, fontNumber=fontNo)
for cmap in font['cmap'].tables:
if cmap.isUnicode():
for i in unicode_char: #tries to match all uni chars with font cmap
if ord(i) not in cmap.cmap:
return False
return True #returns true if all uni chars in given list were found successfully
font_info = [(f.fname, f.name) for f in mfm.fontManager.ttflist] #list of all font dirs & font names in system
for i, font in enumerate(font_info):
try:
if char_in_font(list_unichars, font[0]) == True: #calls for the defined searching func and checks if True
print('Yess!! loc:{0}; font name:{1}'.format(font[0], font[1])) #print statement if find is successful
elif print_true_only==False: print('No :( -- {0}'.format(font[1])) #print statement is find fails
except:
print('Error!! Unable to load: {0}, font name: {1}'.format(font[0], font[1])) #if unable to load(type 1 fonts?)
return
def main(): #this is newbie friendly code, only need to touch 'main' for it to work with your data!
uni_char = [u'1',u'2', u'*', u"✹"]
# uni_char = [u"✹"] #or [u"u2739"] #put inside list even if finding just one char!
print_if_char_in_font(uni_char, print_true_only=True) #print_true_only is just going to output fonts that satisfy the search
###e.g
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSansMono-Bold.ttf; font name:DejaVu Sans Mono
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSans.ttf; font name:DejaVu Sans
### print_true_only=False is going to output for all fonts including those which do not satisfy:
# No :( -- Times New Roman
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSans-Bold.ttf; font name:DejaVu Sans
# No :( -- Sitka Small
if __name__ == '__main__':
main()
import matplotlib.pyplot as pyplot
pyplot.figure()
pyplot.xlabel(u"u2736")
pyplot.show()
Here is the simplest code I can create to show my problem. The axis label symbol is meant to be a six-pointed star but it shows as a box. How do I change it so the star is shown? I’ve tried adding the comment:
#-*- coding: utf-8 -*-
like previous answers suggested but it didn’t work, as well as using matplotlib.rc
or matplotlib.rcParams
which also didn’t work. Help would be appreciated.
You’ll need a font that has the given unicode character, STIX fonts should contain the star symbol. You’ll need to locate or download the STIX fonts, ofcourse any other ttf file with the given symbol should be fine.
import matplotlib.pyplot as pyplot
from matplotlib.font_manager import FontProperties
if __name__ == "__main__":
pyplot.figure()
prop = FontProperties()
prop.set_file('STIXGeneral.ttf')
pyplot.xlabel(u"u2736", fontproperties=prop)
pyplot.show()
To complement @arjenve’s answer. To plot a Unicode character, firstly, find which font contains this character, secondly, use that font to plot characters with Matplotlib
Find a font which contains the character
According to this post, we can use fontTools package to find which font contains the character we want to plot.
from fontTools.ttLib import TTFont
import matplotlib.font_manager as mfm
def char_in_font(unicode_char, font):
for cmap in font['cmap'].tables:
if cmap.isUnicode():
if ord(unicode_char) in cmap.cmap:
return True
return False
uni_char = u"✹"
# or uni_char = u"u2739"
font_info = [(f.fname, f.name) for f in mfm.fontManager.ttflist]
for i, font in enumerate(font_info):
if char_in_font(uni_char, TTFont(font[0])):
print(font[0], font[1])
This script will print a list of font paths and font names (all these fonts support that Unicode Character). Sample output shown below
Then, we can use the following script to plot this character (see image below)
import matplotlib.pyplot as plt
import matplotlib.font_manager as mfm
font_path = '/usr/share/fonts/gnu-free/FreeSerif.ttf'
prop = mfm.FontProperties(fname=font_path)
plt.text(0.5, 0.5, s=uni_char, fontproperties=prop, fontsize=20)
plt.show()
I was trying to implement @jdhao
code but it was constantly breaking because I also had type 0 fonts in my library.
So here’s a tweaked version of his code that does not break with type 0 fonts
and also enables finding several uni chars at once in the same font by providing the function a list
of uni chars instead of just 1 uni char.
For more details read the comments throughout the code.
#!/usr/bin/env python
from fontTools.ttLib import TTFont
import matplotlib.font_manager as mfm
def print_if_char_in_font(list_unichars, print_true_only=False):
def char_in_font(unicode_char, font):
if font.endswith('.ttc'): fontNo = 0 #default is for type -1 so type 0 fonts are going to break the code without this line
else: fontNo = -1
font=TTFont(font, fontNumber=fontNo)
for cmap in font['cmap'].tables:
if cmap.isUnicode():
for i in unicode_char: #tries to match all uni chars with font cmap
if ord(i) not in cmap.cmap:
return False
return True #returns true if all uni chars in given list were found successfully
font_info = [(f.fname, f.name) for f in mfm.fontManager.ttflist] #list of all font dirs & font names in system
for i, font in enumerate(font_info):
try:
if char_in_font(list_unichars, font[0]) == True: #calls for the defined searching func and checks if True
print('Yess!! loc:{0}; font name:{1}'.format(font[0], font[1])) #print statement if find is successful
elif print_true_only==False: print('No :( -- {0}'.format(font[1])) #print statement is find fails
except:
print('Error!! Unable to load: {0}, font name: {1}'.format(font[0], font[1])) #if unable to load(type 1 fonts?)
return
def main(): #this is newbie friendly code, only need to touch 'main' for it to work with your data!
uni_char = [u'1',u'2', u'*', u"✹"]
# uni_char = [u"✹"] #or [u"u2739"] #put inside list even if finding just one char!
print_if_char_in_font(uni_char, print_true_only=True) #print_true_only is just going to output fonts that satisfy the search
###e.g
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSansMono-Bold.ttf; font name:DejaVu Sans Mono
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSans.ttf; font name:DejaVu Sans
### print_true_only=False is going to output for all fonts including those which do not satisfy:
# No :( -- Times New Roman
# Yess!! loc:C:UsersxxxAppDataLocalProgramsPythonPython310libsite-packagesmatplotlibmpl-datafontsttfDejaVuSans-Bold.ttf; font name:DejaVu Sans
# No :( -- Sitka Small
if __name__ == '__main__':
main()