I'm trying to use Matplotlib graphs as part of a camera-ready submission, and the publishing house requires the use of Type 1 fonts only.
I'm finding that the PDF backend happily outputs Type-1 fonts for simple graphs with linear Y axes, but outputs Type-3 fonts for logarithmic Y axes.
Using a logarithmic yscale incurs the use of mathtext, which seems to use Type 3 fonts, presumably because of the default use of exponential notation. I can use an ugly hack to get around this - using pyplot.yticks() to force the axis ticks to not use exponents - but this would require moving the plot region to accommodate large labels (like 10 ^ 6) or writing the axes as 10, 100, 1K, etc. so they fit.
I've tested the example below with the matplotlib master branch as of today, as well as 1.1.1, which produces the same behavior, so I don't know that this is a bug, probably just unexpected behavior.
#!/usr/bin/env python
# Simple program to test for type 1 fonts.
# Generate a line graph w/linear and log Y axes.
from matplotlib import rc, rcParams
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
#rc('font',**{'family':'sans-serif','sans-serif':['computer modern sans serif']})
# These lines are needed to get type-1 results:
# http://nerdjusttyped.blogspot.com/2010/07/type-1-fonts-and-matplotlib-figures.html
rcParams['ps.useafm'] = True
rcParams['pdf.use14corefonts'] = True
rcParams['text.usetex'] = False
import matplotlib.pyplot as plt
YSCALES = ['linear', 'log']
def plot(filename, yscale):
plt.figure(1)
xvals = range(1, 2)
yvals = xvals
plt.plot(xvals, yvals)
plt.yscale(yscale)
plt.savefig(filename + '.pdf')
if __name__ == '__main__':
for yscale in YSCALES:
plot('linegraph-' + yscale, yscale)
Does anyone know a clean way to get Type 1 fonts with log axes?
Thanks!
This is the code I use for camera-ready submissions:
from matplotlib import pyplot as plt
def SetPlotRC():
#If fonttype = 1 doesn't work with LaTeX, try fonttype 42.
plt.rc('pdf',fonttype = 1)
plt.rc('ps',fonttype = 1)
def ApplyFont(ax):
ticks = ax.get_xticklabels() + ax.get_yticklabels()
text_size = 14.0
for t in ticks:
t.set_fontname('Times New Roman')
t.set_fontsize(text_size)
txt = ax.get_xlabel()
txt_obj = ax.set_xlabel(txt)
txt_obj.set_fontname('Times New Roman')
txt_obj.set_fontsize(text_size)
txt = ax.get_ylabel()
txt_obj = ax.set_ylabel(txt)
txt_obj.set_fontname('Times New Roman')
txt_obj.set_fontsize(text_size)
txt = ax.get_title()
txt_obj = ax.set_title(txt)
txt_obj.set_fontname('Times New Roman')
txt_obj.set_fontsize(text_size)
The fonts won't appear until you run savefig
Example:
import numpy as np
SetPlotRC()
t = np.arange(0, 2*np.pi, 0.01)
y = np.sin(t)
plt.plot(t,y)
plt.xlabel("Time")
plt.ylabel("Signal")
plt.title("Sine Wave")
ApplyFont(plt.gca())
plt.savefig("sine.pdf")
The preferred method to get Type 1 fonts via matplotlib seems to be to use TeX for typesetting. Doing so results in all axis being typeset in the default math font, which is typically undesired but which can be avoided by using TeX-commands.
Long story short, I found this solution:
import matplotlib.pyplot as mp
import numpy as np
mp.rcParams['text.usetex'] = True #Let TeX do the typsetting
mp.rcParams['text.latex.preamble'] = [r'\usepackage{sansmath}', r'\sansmath'] #Force sans-serif math mode (for axes labels)
mp.rcParams['font.family'] = 'sans-serif' # ... for regular text
mp.rcParams['font.sans-serif'] = 'Helvetica, Avant Garde, Computer Modern Sans serif' # Choose a nice font here
fig = mp.figure()
dim = [0.1, 0.1, 0.8, 0.8]
ax = fig.add_axes(dim)
ax.text(0.001, 0.1, 'Sample Text')
ax.set_xlim(10**-4, 10**0)
ax.set_ylim(10**-2, 10**2)
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel('$\mu_0$ (mA)')
ax.set_ylabel('R (m)')
t = np.arange(10**-4, 10**0, 10**-4)
y = 10*t
mp.plot(t,y)
mp.savefig('tmp.png', dpi=300)
Then results in this
Inspired by: https://stackoverflow.com/a/20709149/4189024 and http://wiki.scipy.org/Cookbook/Matplotlib/UsingTex
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With