Matplotlib and non-ascii characters - python

Never ending story about Matplotlib and non-ascii characters continues, indeed:
1) Localhost: Mac OS X: By default, some characters are missing (replaced with []). OK, after adding matplotlib.rc('font', family='Verdana') characters are displayed fine. However, when deploying to a production server things get broken once again.
2) Server: Linux (openSUSE, using: matplotlib.use('Agg'), serving png's and pdf's, Django app): Calling matplotlib.rc('font', family='Verdana') does not help now (WHY?). I even copied some core fonts from Mac to openSUSE to make sure they are the same.
What does help a bit is this:
import matplotlib.font_manager as fm
fp = fm.FontProperties(fname="/usr/share/fonts/truetype/Verdana.ttf")
# matplotlib.rcParams['font.family'] = fp.get_name()
matplotlib.rc('font', family=fp.get_name())
and then using per partes plt.title(_title, fontproperties=fp) for each plot/block. This is very tiring… And what is worse, it is not usable when working with legends. For example there is no way (is there?) to use it like that:
ax.legend([charts], [_label], fontproperties=fp)
and
ax.legend([charts], [_label], prop={'family': 'Verdana'}
does not have any effect (it works on Mac OS X, though).
Funny thing is that most of non-ascii characters are displayed fine (ščřž…), problems occur only with ě, ť, ď… Why is Matplotlib still having these issues with unicode? I would not mind back in 90's but it is 2015 and not being able to use diacritics properly is pain.
Why do the “hooks” work under OS X, yet do not have any effect in openSUSE server?

matplotlib not finding the correct fonts can be caused by stale font cache (this is a problem we need to solve better).
To find were your cache is do
import matplotlib.font_manager as fm
print(fm.cachedir) # or other way of getting the text out
And then delete the font-related contents in that directory. They will be rebuilt the next time you import matplotlib and (should) now contain the updated fonts.

Related

Python: unicode problem after using matplotlib

A few days ago, I need to draw a plot by using matplotlib, since it could not display the font properly, so I
edited matplotlibrc file, unhashtag "font.family" and "font.serif".
added specific font file to ttf.
deleted .matplotlib file.
Then I code:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
Now when I tried to use "to_csv" to write the dataframe into csv, there's a
unicode problem. It ran without problem before. So I changed those 3 steps back and still have a unicode problem.
Not sure if there's any problem of my setting.

Non-Ubuntu oriented pygame platformer not loading levels correctly on anything other than Ubuntu

I've been working on a pygame platformer, based on this. I wrote it on an Ubuntu machine, and it doesn't seem to work on other operating systems.
The generation code is something like this:
levelFile = tkFileDialog.askopenfile(mode='r', defaultextension='.lvl', filetypes=[('Level File', '*.lvl')], parent=tk)
level = levelFile.read().split("\n")
del level[len(level) - 1]
# Add platforms to array based on level string
I made a level in a text editor using ASCII characters to represent different tiles.
It works fine on my Ubuntu machine, but when run on a MacBook Air and a Windows laptop, it doesn't. The level layout doesn't load as expected (the tiles load in unexpected places, and the camera position is messed up).
Does anyone have any idea what is going on and how to fix it?
The line separators in your level file are OS-dependent if you create your file under linux it will use "\n" under windows "\r\n", so this could be a reason why it is not working. i think you should use os.linesep instead of "\n" to split the file into lines.
level = levelFile.read().split(os.linesep)

Disable tex interpreter in matplotlib

I would like to produce plots using matplotlib (through anaconda-spider installed on os x yosemite) and put labels on it not interpreted by tex.
Here is the sample code:
# -*- coding: utf-8 -*-
import matplotlib.pyplot as pp
my_rc_param = {'text.usetex': False}
pp.figure()
pp.rcParams.update(my_rc_param)
pp.plot(range(10))
pp.xlabel('$x$')
I would like to see exactly the string $x$ as x label. In turn, I get the math-mode latex x.
I have also tried, unsuccessfully, to put the following preamble:
from matplotlib import rc
rc('text', usetex=False)
Is there a way to force a plain interpreter?
Or should I consider this as a bug?
You are not getting any latex mode. You are simply using the mathtex feature of matplotlib. Using latex is a different thing. I checked whether it is possible to switch off mathtex for matplotlib, and there is a quiet recent issue on this (see here). However, the way to sort out this problem consist is avoiding the math just escaping the $ symbol with '\':
pp.xlabel('\$x\$')
Just remove all the stuff related to the text.usetex as you are trying to do a complete different thing here.

matplotlib font not found

I'm trying to use the font "Heuristica" in my matplotlib plots, but it won't show up.
I defined "Heuristica" on the first spot in the rcParameter font.serif --> no result
I changed font.family to "Heuristica" and got the message
findfont: FontFamily not found
that got me thinking, because Heuristica is installed and I can access it from other software without problems. So I used the fontManager and did:
import pylab as pl
la = pl.matplotlib.font_manager.FontManager()
lu = pl.matplotlib.font_manager.FontProperties(family = 'Heuristica')
la.findfont(lu)
and got:
Out[7]: 'C:\\Windows\\Fonts\\Heuristica-Regular.otf'
So obviously Heuristica can be found.
I looked up the available ttf-Fonts (How can i get list of font family(or Name of Font) in matplotlib) but Heuristica is not in this list.
I'd be glad about any help.
Well, mdboom solved the problem over at github, all the credit belongs to him:
When you add new fonts to your system, you need to delete your fontList.cache file in order for matplotlib to find them.
The reason it works on lines 4/5 in your example is because you are creating a FontManager from scratch (which goes out to the filesystem and hunts down all the fonts). Internally, when matplotlib later does its own font lookup, it is using a FontManager that has been loaded from a cache on disk in the fontList.cache file.
Long term, we have plans to switch to using the font lookup mechanisms of the OS to get around this problem, (see MEP14), but in the meantime, you'll need to remove the fontList.cache file everytime you want matplotlib to discover new fonts.
The file fontList.cache is located at your Userfolder --> .matplotlib/fontList.cache, for Windows that would normally be C:\Users\yourUsername\.matplotlib\fontList.cache
For some versions of Matplotlib, it may be necessary to clear the LRU cache of _get_fontconfig_fonts() (next to removing the fontList.cache file).
fm = matplotlib.font_manager
fm._get_fontconfig_fonts.cache_clear()
This function is responsible for calling, and caching, fc-list on a Linux/Unix system. If your font appears in fc-list, and not in Matplotlib's fonts, even after removing the fontList.cache file, this may be the culprit.

Matplotlib PDF export uses wrong font

I want to generate high-quality diagrams for a presentation. I’m using Python’s matplotlib to generate the graphics. Unfortunately, the PDF export seems to ignore my font settings.
I tried setting the font both by passing a FontProperties object to the text drawing functions and by setting the option globally. For the record, here is a MWE to reproduce the problem:
import scipy
import matplotlib
matplotlib.use('cairo')
import matplotlib.pylab as pylab
import matplotlib.font_manager as fm
data = scipy.arange(5)
for font in ['Helvetica', 'Gill Sans']:
fig = pylab.figure()
ax = fig.add_subplot(111)
ax.bar(data, data)
ax.set_xticks(data)
ax.set_xticklabels(data, fontproperties = fm.FontProperties(family = font))
pylab.savefig('foo-%s.pdf' % font)
In both cases, the produced output is identical and uses Helvetica (and yes, I do have both fonts installed).
Just to be sure, the following doesn’t help either:
matplotlib.rc('font', family = 'Gill Sans')
Finally, if I replace the backend, instead using the native viewer:
matplotlib.use('MacOSX')
I do get the correct font displayed – but only in the viewer GUI. The PDF output is once again wrong.
To be sure – I can set other fonts – but only other classes of font families: I can set serif fonts or fantasy or monospace. But all sans-serif fonts seem to default to Helvetica.
Basically, #Jouni’s is the right answer but since I still had some trouble getting it to work, here’s my final solution:
#!/usr/bin/env python2.6
import scipy
import matplotlib
matplotlib.use('cairo')
import matplotlib.pylab as pylab
import matplotlib.font_manager as fm
font = fm.FontProperties(
family = 'Gill Sans', fname = '/Library/Fonts/GillSans.ttc')
data = scipy.arange(5)
fig = pylab.figure()
ax = fig.add_subplot(111)
ax.bar(data, data)
ax.set_yticklabels(ax.get_yticks(), fontproperties = font)
ax.set_xticklabels(ax.get_xticks(), fontproperties = font)
pylab.savefig('foo.pdf')
Notice that the font has to be set explicitly using the fontproperties key. Apparently, there’s no rc setting for the fname property (at least I didn’t find it).
Giving a family key in the instantiation of font isn’t strictly necessary here, it will be ignored by the PDF backend.
This code works with the cairo backend only. Using MacOSX won’t work.
The "family" argument and the corresponding rc parameter are not meant to specify the name of the font can actually be used this way. There's an (arguably baroque) CSS-like font selection system that helps the same script work on different computers, selecting the closest font available. The usually recommended way to use e.g. Gill Sans is to add it to the front of the value of the rc parameter font.sans-serif (see sample rc file), and then set font.family to sans-serif.
This can be annoying if the font manager decides for some obscure reason that Gill Sans is not the closest match to your specification. A way to bypass the font selection logic is to use FontProperties(fname='/path/to/font.ttf') (docstring).
In your case, I suspect that the MacOSX backend uses fonts via the operating system's mechanisms and so automatically supports all kinds of fonts, but the pdf backend has its own font support code that doesn't support your version of Gill Sans.
This is an addition to the answers above if you came here for a non-cairo backend.
The pdf-backend of matplotlib does not yet support true type font collections (saved as .ttc files). See this issue.
The currently suggested workaround is to extract the font-of-interest from a .ttc file and save it as a .ttf file. And then use that font in the way described by Konrad Rudolph.
You can use the python-package fonttools to achieve this:
font = TTFont("/System/Library/Fonts/Helvetica.ttc", fontNumber=0)
font.save("Helvetica-regular.ttf")
As far as I can see, it is not possible to make this setting "global" by passing the path to this new .ttf file to the rc. If you are really desperate, you could try to extract all fonts from a .ttc into separate .ttf files, uninstall the .ttc and install the ttfs separately. To have the extracted font side-by-side with the original font from the .ttc, you need to change the font name with tools like FontForge. I haven't tested this, though.
Check if you are rendering the text with LaTeX, i.e., if text.usetex is set to True. Because LaTeX rendering only supports a few fonts, it largely ignores/overwrites your other fonts settings. This might be the cause.

Categories

Resources