changing the font of the xthicklabels from a stylesheet in matplotlib - matplotlib

I want to use a non-standard font for labels on the axes of my matplotlib graph. I cannot assume users have installed the font, so I am providing the ttf file.
I have it working by doing the following:
fname = '/bla/bla/myfont.ttf'
ticks_font = matplotlib.font_manager.FontProperties(fname = fontPath, style='normal', size=12, weight='normal', stretch='normal')
for label in ax.get_xticklabels() :
label.set_fontproperties(ticks_font)
However, as I have many graphs with different styles, I want to move all layout to stylesheets. I've tried to do:
font.serif : '/bla/bla/myfont.ttf'
font.family :'serif'
But that doesn't seem to work.

Related

How to set a default font weight for x & y labels with matplotlib

Using matplotlib 3.0.1, I had to make a figure where all text had to be in Open Sans Light. As the figure is quite complex, with several panels etc, I wanted to set that up using matplotlib.pyplot.rc(..) to define the default font and font weight for all elements of the figure.
The code below provides a minimal example. Because not everybody might have Open Sans installed, here I use the default font and the 'bold' weight, instead of 'light', to make it more general. So I set the default font weight, and size, then I plot a basic axis with x and y labels and some extra text.
import matplotlib.pyplot as plt
plt.style.use('default')
plt.rc('font', weight='bold', size=15)
fig, ax = plt.subplots(num=1, clear=True)
ax.set(xlabel='x-label', ylabel='y-label')
ax.text(0.2,0.4,'Text')
I expect all bits of text to be in 'bold' font weight. The tick labels and the extra bit of text are, but the x-label and y-label are not. They are in the normal weight. Screen capture here.
The x and y labels seem to get the default font name and size, but not the default weight.
As a workaround, I tried to set a default font weight in the 'axes' options, but that does not seem to be possible. "axes.labelsize" affects the font size of the x,y labels, but the font weight cannot be separately specified.
So it seems the font size is inherited by the x and y labels, if not otherwise specified through axes.labelsize, but the font weight is not inherited by the labels, nor can it be specified as a default for the axes. Note that the font name behaves yet differently. It is inherited by the x, y labels but cannot have a different default in the 'axes' option.
Is there a logic, or is that a bug?
Is there a solution to this? Or do I have to directly set the font weight onto the x-label and y-label objects?

Set font for matplotlib ticks

I want the ticks in matplotlib to be typeset using Computer Modern sans-serif. How do I do this?
I would have expected this would do the trick, but it doesn't:
mpl.rcParams['font.family'] = 'computer modern sans serif'
Try this:
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = ['computer modern']
The font.family property has five values:
'serif' (e.g., Times),
'sans-serif' (e.g., Helvetica),
'cursive' (e.g., Zapf-Chancery),
'fantasy' (e.g., Western), and
'monospace' (e.g., Courier).
After setting the font family you provide a list of fonts for matplotlib to try to find in order.

matplotlib - savefig with usetex=True

I am having problems saving a figure created by matplotlib as a .eps or .ps when I enable usetex=True. This works when this is not enabled. Here's an example:
plt.plot([1,2,3], [1,2,3], 'b.')
plt.text(2,2,r'\textbf{(a)} \lambda_{1} value', usetex=True, fontsize=16, fontname='Times New Roman')
plt.savefig('check.eps')
I receive this error:
File "C:\Python27\lib\site-packages\matplotlib\backends\backend_ps.py", line 671, in draw_tex
thetext = 'psmarker%d' % self.textcnt
AttributeError: 'RendererPS' object has no attribute 'textcnt'
I also cannot set the font to Time New Roman using the text command when I enable usetex=True.
Even if it is a bit late, I would like to give an answer, if someone else searches for this error.
Saving eps files starts the RendererPS backend, which checks whether plt.rcParams['text.usetex'] is set to True to initialise its textcnt attribute. Since usetex is set only for the text object, the backend does not expect to have to handle LaTeX and throws an error when it tries to. These kind of inconsistencies concerning LaTeX rendering are sadly present in a number of places in matplotlib.
If you cannot achieve the text formatting with the standard matplotib functionality, one solution is to set usetex globally: plt.rcParams['text.usetex'] = True. This render all the text of the figure with LaTeX (e.g. also tick labels or axis labels). I would recommend to do this in any case, to have consistent visuals.
Concerning the font, the fontname argument only affects standard matplotlib formatting. For LaTeX rendering, you have to specify the font like you would do in LaTeX. To get a font like Times New Roman, you need to load the respective package e.g. mathptmx (the times package is deprecated) by plt.rcParams['text.latex.preamble'] = [r'\usepackage{mathptmx}']. Of course, the package has to be installed in your local LaTeX installation. The standard font family in matplotlib is sans-serif, so this has to be changed to serif with plt.rcParams['font.family'] = 'serif'.
The final code is:
import matplotlib.pyplot as plt
# LaTeX setup
plt.rcParams['text.latex.preamble'] = [r'\usepackage{mathptmx}'] # load times roman font
plt.rcParams['font.family'] = 'serif' # use serif font as default
plt.rcParams['text.usetex'] = True # enable LaTeX rendering globally
plt.plot([1,2,3], [1,2,3], 'b.')
plt.text(2,2,r'\textbf{(a)} $\lambda_1$ value', fontsize=16)
plt.savefig('check.eps')
Note, that you have to enclose the math variable in dollar signs $\lambda_1$, otherwise you get an error or warning in LaTeX. (Also, single character subscripts do not need to be enclosed in curly brackets).
As a side note: I encountered the same error, when trying to save a figure as eps after turning usetex off again.

Change default background color for matplotlib plots

I am using ipython with matplotlib. Is it possible to configure the default background color for matplotlib plots? The curent (white) colour must come from somewhere. Is it possible to override it to, lets say, #CCCCCC?
Note: By default, I don't mean default for a given ipython notebook. I mean default for my matplotlib installation.
The solution suggested by #Ffisegydd works. however, after setting axes.facecolor : F4EAEA, I still get white edges around the plot:
How can I get rid of those?
UPDATE:
now I have following set in my /etc/matplotlibrc and I have restarted ipython notebook after each change;
axes.facecolor : F4EAEA
figure.facecolor : F4EAEA
figure.edgecolor : F4EAEA
savefig.facecolor : F4EAEA
savefig.edgecolor : F4EAEA
The plot looks the same as on the original screenshot. i.e. there is the white stripe around the plot.
UPDATE2:
I am using ipython, and I have following custom css in my ~/.config/ipython/profile_nbserver/static/custom/custom.css
div.output_area {
border-radius: 4px;
background: #F4EAEA !important;
border: thin solid #4a4a4a;
}
You need to set both the axes and figure background colors:
f = plt.figure(facecolor=".6")
ax = f.add_subplot(111, axisbg=".6")
ax.plot([0, 1, 2], [1, 0, 2])
There is additionally a distinction between the facecolor for the interactive plot and what gets saved; you also have to pass facecolor to f.savefig if you want a uniform background on the resulting file.
You can change the defaults with the following fields in the rcParams dictionary:
import matplotlib as mpl
mpl.rcParams["figure.facecolor"]
mpl.rcParams["axes.facecolor"]
mpl.rcParams["savefig.facecolor"]
Note that this works a little unexpectedly in the IPython notebook with an inline backend, where the "saved" version of the figure you see below the cell is not controlled by the figure parameter, but by the savefig paramter.
You can customise matplotlib in a variety of ways.
If you're looking to customise across your entire computer then matplotlib uses the "matplotlibrc" configuration file as a default.
If you wish to edit this to change the default axes facecolor (the technical term for the background) then you'll need to uncomment and adjust this line:
#axes.facecolor : white # axes background color
If you wish to set your background colour to #CCCCCC then you should change the line to:
axes.facecolor : CCCCCC # axes background color
N.B. if you re-install matplotlib this will be overwritten. To prevent this you can save it in "HOME/.matplotlib/matplotlibrc" as the example comments state.
Should you wish to change it to a different colour temporarily then simply add the following at the top of your script:
import matplotlib as mpl
mpl.rcParams['axes.facecolor'] = '111111' # Or any suitable colour...
If you should wish to modify an individual matplotlib.axes object then just use ax.set_axis_bgcolor('...').

How do I update the legend label spacing after legend font size is changed in matplotlib?

I'm writing a script that saves a figure with multiple formatting styles among which is the font size of legend text.
The legend.labelspacing in rcparams or the matplotlibrc file specifies the label spacing in fractions of the font size, so I might expect the actual spacing to change if the font size is changed. However, since the actual spacing is probably calculated when the legend is first created, any subsequent change to the font size of existing legend text objects has no effect on the label spacing. Is there a way to update the legend label spacing after an existing legend label object's font size has been changed? In summary here's is what I would like to do:
plot something with a legend
save the figure (format according to rcparams or matplotlibrc file)
change several formatting properties (line widths, font sizes, etc.)
save the figure again with the updated formatting properties, including re-adjusted legend label spacing
Is there a way to do this without changing the rcparams and then rebuilding the figure?
Just call legend() with labelspacing parameter, here is an example:
import pylab as pl
pl.plot([0,1],[0,1], label="a")
pl.plot([0,2],[0,2], label="b")
pl.legend()
pl.savefig("p1.png")
pl.legend(labelspacing=2)
pl.savefig("p2.png")
To reuse parameters:
import pylab as pl
pl.plot([0,1],[0,1], label="a")
pl.plot([0,2],[0,2], label="b")
params = dict(loc="right", prop=dict(size=9))
pl.legend(**params)
pl.savefig("p1.png")
params["labelspacing"] = 2
pl.legend(**params)
pl.savefig("p2.png")