I am using the pgf backend in matplotlib 1.5.3 to produce publication-quality figures. Here is how I set up the plotting script.
import matplotlib as mpl
mpl.use('pgf')
pgf_with_latex = { # setup matplotlib to use latex for output
"pgf.texsystem": "pdflatex", # change this if using xetex or lautex
"text.usetex": True, # use LaTeX to write all text
"font.family": "sans-serif",
"font.sans-serif": "Bitstream Vera Sans, Helvetica, Computer Modern Sans Serif",
"pgf.preamble": [
r"\usepackage[utf8x]{inputenc}", # use utf8 fonts because your computer can handle it :)
r"\usepackage[T1]{fontenc}", # plots will be generated using this preamble
r"\usepackage{textcomp}",
r"\usepackage{sfmath}", # sets math in sans-serif
]
}
mpl.rcParams.update(pgf_with_latex)
import matplotlib.pyplot as plt
def newfig():
plt.clf()
fig = plt.figure(figsize=(4, 2))
ax = fig.add_subplot(111)
return fig, ax
fig, ax = newfig()
ax.set_xlabel("Some x-label text")
plt.gcf().tight_layout()
plt.savefig(os.getcwd() + "/test.pdf")
plt.savefig(os.getcwd() + "/test.eps")
I am using the package sfmath to set all math environments in sans-serif. At the end I save in .pdf and .eps format. Here's the problem: While the pdfclearly uses sans-serif font everywhere, the eps file uses serif for all tick labels (not axis labels)! When I modify my LaTeX template to use sfmath it does not change the tick labels.
How can I prevent the epsfrom using serif font in the tick labels?
Edit: After a good day of experimenting, the only (barely) satisfying solution I found was to use .tiff as format, since this is also allowed by the journal. eps just seems to have problems and always turns out different than the pdf or other image formats.
Related
I am trying to change the font type (from deja-vu to lets' say comic sans or calibri) for the text that appears along with matplotlib's annotate function. However, though I can change the font for all the other elements in the plot, it won't change it for the annotated text. Any help? Below is what I'm working with and how I globally set the font. You'll notice the difference in fonts when comparing the style of "1" on the plots.
import numpy as np
import os, glob
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager
from matplotlib import rcParams
import pdb
matplotlib.font_manager._rebuild()
# THIS SETS ALL THE RELEVANT FONT STYLE FOR PLOTS
rcParams['font.family'] = 'sans-serif'
rcParams['font.weight'] = 'regular' #can omit this, it's the default
rcParams['font.sans-serif'] = ['calibri']
# test code
ax = plt.figure().add_subplot()
x,y = np.arange(10),np.arange(10)
ax.plot(x,y)
ax.annotate(r'$100^\circ$',
xy=(1.1, 0.1), xycoords='axes fraction',
xytext=(1.1, 0.8), textcoords='axes fraction',
arrowprops=dict(facecolor='black', shrink=0.01),
horizontalalignment='center', verticalalignment='top',
fontsize=15)
The problem is, it's a mathematical text... if you change regular text's font characteristics, you're not going to affect the fonts that Matplotlib uses for mathematical text.
Of course you can modify the font used in mathematical text (is there anything in Matplotlib that you cannot modify?)
Writing mathematical expressions
[...] Mathtext can use DejaVu Sans (default), DejaVu Serif, the Computer Modern fonts (from (La)TeX), STIX fonts (with are designed to blend well with Times), or a Unicode font that you provide. The mathtext font can be selected with the customization variable mathtext.fontset (see Customizing Matplotlib with style sheets and rcParams).
So I am using the pgf backendin matplotlib to include some automatically compiled references to some other parts of my Tex documents (figures, bibliography) in my TeX document.
import matplotlib
matplotlib.use('pgf')
import matplotlib.pyplot as plt
plt.figure()
plt.txt(0.0,0.5,r'Some text compiled in latex \cite{my_bib_tag}')
plt.savefig("myfig.pgf", bbox_inches="tight", pad_inches=0)
Then in my tex document I have the lines:
\usepackage[dvipsnames]{xcolor}
%yada yada yada
\begin{figure}
\input{myfig.pgf}
\end{figure}
It is working great but when I try to add some transparency to the text it doesn't work. For instance when setting:
plt.txt(0.0,0.5,r'Some text compiled in latex \cite{my_bib_tag}', alpha=0.5)
The text appears unchanged, and if I try to do it in the compilation by using \textcolorfrom the xcolor package (or any other commands in LateX, like the transparent package) I get parsing errors when compiling the Python.
I tried escaping characters but somehow I cannot make it work.
plt.txt(0.0,0.5,r'\textcolor{gray}{Some text compiled in latex \cite{my_bib_tag}}', alpha=0.5)
#raise ValueError !Undefined Control Sequence
EDIT 1: I tried adding the required package in the preamble, but it does not work when saving to pgf (with the pgf backend), it works using the Agg backend (I think it is expected behavior). But I need to save it in pgf to have the dynamic parsing of references.
import matplotlib
import matplotlib.pyplot as plt
matplotlib.rcParams["text.usetex"] = True
matplotlib.rcParams["text.latex.preamble"].append(r'\usepackage[dvipsnames]{xcolor}')
matplotlib.verbose.level = 'debug-annoying'
plt.figure()
plt.text(0.0,0.5,r'\textcolor{gray}{Some text compiled in latex \cite{my_bib_tag}}', alpha=0.5)
#works in .png, does not work in .pgf
#plt.savefig("myfig.png", bbox_inches="tight", pad_inches=0)
EDIT 2: A work around is to use the color param in plt.text but what if I would like to use more complicated LateX styling...
Thanks to #ImportanceOfBeingErnest I finally made it work with the pgf backend:
import matplotlib
matplotlib.use('pgf')
import matplotlib.pyplot as plt
pgf_with_custom_preamble = {
"text.usetex": True, # use inline math for ticks
"pgf.rcfonts": False, # don't setup fonts from rc parameters
"pgf.preamble": [
"\\usepackage[dvipsnames]{xcolor}", # load additional packages
]
}
matplotlib.rcParams.update(pgf_with_custom_preamble)
plt.figure()
plt.text(0.0,0.5,r'\textcolor{gray}{Some text compiled in latex \cite{my_biblio_tag}}')
plt.savefig("myfig.pgf", bbox_inches="tight", pad_inches=0)
I would like to view matplotlib plots inside Spyders IPython console in one size and save figures to a multipage PDF in a different size.
Currently I set the figure size as follows:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
Then I plot some figures and save them to a list for saving a PDF later on. This works just fine when used alone. The plots are approriately sized for viewing in Spyder IPython console.
At the end of my script I have a loop to go through each of the figures I want to save. In here I want to set the layout and figure size exactly for better printing on an A3 paper.
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.tight_layout()
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig)
The output PDF is just like I want it to be, but the problem is with the plots shown inside Spyder. Changing the figure size while saving also affects the plots viewed inside Spyder. And using the size of an A3 makes the plots way too big.
So the question is: How do I change the size of saved PDF figures without changing the size of figures shown inside Spyder?
As suggested by #ImportanceOfBeingErnest, changing the figure size back after saving should work and may probably solved you problem.
But, depending on your specific problem, it is possible that you are going to face scaling issues since the size of the figures saved in the pdf is much bigger than the size of those displayed in the IPython console. If you scale everything to look great on the pdf, then it is possible that everything is going to look too big in IPython as shown in the example below:
If you don't need the plot to be interactive in IPython, a solution may be to generate your figures to look good for the pdf and display a scaled bitmap version of them in the IPython console as shown in the code below:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
from IPython.display import Image, display
try: # Python 2
from cStringIO import StringIO as BytesIO
except ImportError: # Python 3
from io import BytesIO
# Generate a matplotlib figures that looks good on A3 format :
fig, ax = plt.subplots()
ax.plot(np.random.rand(150), np.random.rand(150), 'o', color='0.35', ms=25,
alpha=0.85)
ax.set_ylabel('ylabel', fontsize=46, labelpad=25)
ax.set_xlabel('xlabel', fontsize=46, labelpad=25)
ax.tick_params(axis='both', which='major', labelsize=30, pad=15,
direction='out', top=False, right=False, width=3, length=10)
for loc in ax.spines:
ax.spines[loc].set_linewidth(3)
# Save figure to pdf in A3 format:
w, h = 420/25.4, 297/25.4
with PdfPages('multi.pdf') as pdf:
fig.set_size_inches(w, h)
fig.tight_layout()
pdf.savefig(figure=fig)
plt.close(fig)
# Display in Ipython a sclaled bitmap using a buffer to save the png :
buf = BytesIO()
fig.savefig(buf, format='png', dpi=90)
display(Image(data=buf.getvalue(), format='png', width=450, height=450*h/w,
unconfined=True))
which shows in the IPython console as:
Thank you #ImportanceOfBeingErnest for pointing out the solution.
I went with a solution that allows me to set plt.rc in the beginning to my taste and then revert to the set values after exporting the figures to a PDF.
First I set the values I use:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
With these I can plot what I need with just the default values. Then I create the PDF with:
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig, bbox_inches='tight')
fig.set_size_inches(plt.rcParams.get('figure.figsize'))
With this I can get the fig.tight_layout() only on the exported figure and restore the figure size to the default value set earlier.
I set the font style in the matplotlibrc param file to Helvetica (sans serif) and I set text.usetex to 'True' but the axes fonts use serif fonts. How do I get the axes fonts to use sans serif?
Sometimes changing your .matplolibrc won't be enough. For example in OS X Helvetica is installed per default but stored as a .dfont file which is inaccessible to Matplotlib. If this is the case you need to convert it to .ttf and place it in the right folder so that matplotlib can see it. Please see here for more details.
Something like this will help you troubleshoot the issue:
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
path = '/home/username/Helvetica.ttf'
prop = font_manager.FontProperties(fname=path)
mpl.rcParams['font.family'] = prop.get_name()
fig, ax = plt.subplots()
ax.set_title('Test text', fontproperties=prop, size=40)
To see all fonts available to you:
import matplotlib.font_manager
print matplotlib.font_manager.findSystemFonts(fontpaths=None)
I ran into this problem as well, and it was resolved by setting an additional rcparam for the font itself. I.e. using this code gives me the problem you describe:
import matplotlib.pyplot as plt
params = {
'text.usetex': True,
'font.family': 'sans'
}
plt.rcParams.update(params)
Modifying by setting the 'font.sans' option resolved the problem for me:
import matplotlib.pyplot as plt
params = {
'text.usetex': True,
'font.family': 'sans',
'font.sans': 'cm'
}
plt.rcParams.update(params)
Is it possible with matplotlib to create a slanted fractions ( /sfrac{1}{1} in Latex)
I tried r'$/sfrac{1}{2}$', but I get nothing...
You will have to use real LaTeX as follows:
import matplotlib
import matplotlib.pyplot as plt
# Use LaTeX for rendering
matplotlib.rcParams["text.usetex"] = True
# load the xfrac package
matplotlib.rcParams["text.latex.preamble"].append(r'\usepackage{xfrac}')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([0,1],[1,0])
ax.text(.5, .5, r'$\sfrac{1}{2}$')
This creates:
You need to have a working LaTeX in your system plus of course the LaTeX xfrac package.