I want to create a matplotlib figure with an x-axis label that is in Arial font, and has one word italicised.
I can create figures with x-axis labels in latex-font with one word italicised; I can also create figures with x-axis labels in Arial, as long as I have either the entire label italicised or the entire label normal; but I can't get part of the xlabel in Arial italicised and the other part in arial normal.
I'm mostly trying permutations of the following code:
from matplotlib import pyplot as plt
import numpy as n
import matplotlib
from matplotlib.font_manager import FontProperties
font = {'family' : 'Arial',
'weight' : 'medium',
'size' : 20,
'style' : 'normal'}
font0 = {'family' : 'Arial',
'weight' : 'medium',
'size' : 20,
'style' : 'italic'}
matplotlib.rcParams['mathtext.fontset'] = 'custom'
matplotlib.rcParams['mathtext.rm'] = 'Arial'
matplotlib.rcParams['mathtext.it'] = 'Arial'
matplotlib.rc('font', **font)
#matplotlib.rc('font', **font0)
matplotlib.rc('text', usetex=False)
plt.figure(); plt.plot(n.linspace(0,3,10), n.linspace(0,3,10))
plt.xlabel(r'$\mathit{italics}$ - rest normal')
from matplotlib.pyplot import *
# Need to use precise font names in rcParams; I found my fonts with
#>>> import matplotlib.font_manager
#>>> [f.name for f in matplotlib.font_manager.fontManager.ttflist]
rcParams['mathtext.fontset'] = 'custom'
rcParams['mathtext.it'] = 'Arial:italic'
rcParams['mathtext.rm'] = 'Arial'
fig, ay = subplots()
# Using the specialized math font elsewhere, plus a different font
xlabel(r"$\mathit{Italic}$ $\mathrm{and\ just\ Arial}$ and not-math-font",fontsize=18)
# No math formatting, for comparison
ylabel(r'Italic and just Arial and not-math-font', fontsize=18)
grid()
show()
Related
When I tried to polt a figure with matplotlib, I wrote the x axis label with both text and "math text". Because I have to write a chemical formula in the label, it was written as '$CO_2$ concentration'. The question is that I hope the font should be times new roman, but I cannot change the font in the dollar sign somehow. Is there anyone who can help me fix it? Thank you very much!
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
xf1 = pd.read_excel('1812_GPT.xlsx',sheetname= 'PVD_CO2CH4_600',usecols=[1])
deltapx1 = pd.read_excel('1812_GPT.xlsx',sheetname= 'PVD_CO2CH4_600',usecols=[3])
Px1 = pd.read_excel('1812_GPT.xlsx',sheetname= 'PVD_CO2CH4_600',usecols=[5])
ax1 = plt.subplot(111)
l1, = ax1.plot(xf1,Px1,'s',markerfacecolor='black')
font1 = {'family' : 'Times New Roman',
'weight' : 'normal',
'size' : 14,
}
ax1.set_xlabel(r'$CO_2$ pressure', font1)
ax1.set_ylabel(r'$CO_2$ concentration', font1)
plt.show()
This is the picture link, you may see the pic and find that "CO2" is not in Times new roman.
https://flic.kr/p/2dmh8pj
I don't think it's easily possible to change any mathtext to an arbitrary font. However, in case of "CO_2" that consists only of regular symbols, you may use \mathdefault{} to make the mathtext use the symbols from the regular font.
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "serif"
plt.rcParams["font.serif"] = ["Times New Roman"] + plt.rcParams["font.serif"]
fig, ax = plt.subplots()
ax.set_xlabel(r'$\mathdefault{CO_2}$ pressure')
ax.set_ylabel(r'$\mathdefault{CO_2}$ concentration')
plt.show()
Something like r"$\mathdefault{\sum_\alpha^\beta\frac{i}{9}}$ would still be rendered in the usual default math fontset (except the "i" and the 9, which are of course present in Times New Roman).
For the general case, you may also change the complete math fontset to any of the available, cm, stix, stixsans, dejavuserif, dejavusans. The closest to "Times New Roman" would be stix.
import matplotlib.pyplot as plt
rc = {"font.family" : "serif",
"mathtext.fontset" : "stix"}
plt.rcParams.update(rc)
plt.rcParams["font.serif"] = ["Times New Roman"] + plt.rcParams["font.serif"]
fig, ax = plt.subplots()
ax.set_xlabel(r'$CO_2$ pressure')
ax.set_ylabel(r'$CO_2$ concentration')
plt.show()
A general recommendation for reading would be the MathText tutorial.
I find it better to define the whole font family at once, rather than independently (assuming you want the same font). Give this a try
plt.rc('text', usetex=True )
plt.rc('font', family='Times New Roman', weight='normal', size=14)
plt.rcParams['mathtext.fontset'] = 'Times New Roman'
ax1.set_xlabel('$CO_2$ pressure')
ax1.set_ylabel('$CO_2$ concentration')
Is there a way in matplotlib to partially specify the color of a string?
Example:
plt.ylabel("Today is cloudy.")
How can I show "today" as red, "is" as green and "cloudy." as blue?
I only know how to do this non-interactively, and even then only with the 'PS' backend.
To do this, I would use Latex to format the text. Then I would include the 'color' package, and set your colors as you wish.
Here is an example of doing this:
import matplotlib
matplotlib.use('ps')
from matplotlib import rc
rc('text',usetex=True)
rc('text.latex', preamble='\usepackage{color}')
import matplotlib.pyplot as plt
plt.figure()
plt.ylabel(r'\textcolor{red}{Today} '+
r'\textcolor{green}{is} '+
r'\textcolor{blue}{cloudy.}')
plt.savefig('test.ps')
This results in (converted from ps to png using ImageMagick, so I could post it here):
Here's the interactive version. Edit: Fixed bug producing extra spaces in Matplotlib 3.
import matplotlib.pyplot as plt
from matplotlib import transforms
def rainbow_text(x,y,ls,lc,**kw):
"""
Take a list of strings ``ls`` and colors ``lc`` and place them next to each
other, with text ls[i] being shown in color lc[i].
This example shows how to do both vertical and horizontal text, and will
pass all keyword arguments to plt.text, so you can set the font size,
family, etc.
"""
t = plt.gca().transData
fig = plt.gcf()
plt.show()
#horizontal version
for s,c in zip(ls,lc):
text = plt.text(x,y,s+" ",color=c, transform=t, **kw)
text.draw(fig.canvas.get_renderer())
ex = text.get_window_extent()
t = transforms.offset_copy(text._transform, x=ex.width, units='dots')
#vertical version
for s,c in zip(ls,lc):
text = plt.text(x,y,s+" ",color=c, transform=t,
rotation=90,va='bottom',ha='center',**kw)
text.draw(fig.canvas.get_renderer())
ex = text.get_window_extent()
t = transforms.offset_copy(text._transform, y=ex.height, units='dots')
plt.figure()
rainbow_text(0.05,0.05,"all unicorns poop rainbows ! ! !".split(),
['red', 'orange', 'brown', 'green', 'blue', 'purple', 'black'],
size=20)
Extending Yann's answer, LaTeX coloring now also works with PDF export:
import matplotlib
from matplotlib.backends.backend_pgf import FigureCanvasPgf
matplotlib.backend_bases.register_backend('pdf', FigureCanvasPgf)
import matplotlib.pyplot as plt
pgf_with_latex = {
"text.usetex": True, # use LaTeX to write all text
"pgf.rcfonts": False, # Ignore Matplotlibrc
"pgf.preamble": [
r'\usepackage{color}' # xcolor for colours
]
}
matplotlib.rcParams.update(pgf_with_latex)
plt.figure()
plt.ylabel(r'\textcolor{red}{Today} '+
r'\textcolor{green}{is} '+
r'\textcolor{blue}{cloudy.}')
plt.savefig("test.pdf")
Note that this python script sometimes fails with Undefined control sequence errors in the first attempt. Running it again is then successful.
After trying all the methods above, I return back to my stupid but easy method, using plt.text. The only problem is that you need to adjust the spaces between each word. You may need to adjust the positions several times, but I still like this way, because it
saves you from installing tex compilers,
does not require any special backends, and
free you from configuring matplotlib rc and configure back, or it may slows down your other plots, due to usetex=True
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
label_x = -0.15
ax.text(label_x, 0.35, r"Today", color='red', rotation='vertical', transform=ax.transAxes)
ax.text(label_x, 0.5, r"is", color='green', rotation='vertical', transform=ax.transAxes)
ax.text(label_x, 0.55, r"cloudy", color='blue', rotation='vertical', transform=ax.transAxes)
I use matplotlib in iPython notebooks and I'm hoping to change the font-family to Gotham-Book. I have Gotham-Book installed on my machine but unfortunately, matplotlib cannot seem to find the font and keeps defaulting to a serif font. Any thoughts on how to get gotham-book working?
Here is the code I'm using.
import matplotlib.pylab as plt
plt.rcParams['font.family']=['gothambook','gotham','gotham-book','serif']
mpl.pylab.plot(range(10), mpl.pylab.sin(range(10)))
mpl.pylab.xlabel("GOTHAM BOOK FONT", size=20)
I can see the font is on my machine here:
In [12]:
matplotlib.font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
Out[12]:
['/usr/share/fonts/dejavu/DejaVuLGCSansMono-Oblique.ttf',
'/usr/share/fonts/dejavu/DejaVuLGCSansMono.ttf',
'/usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSans-ExtraLight.ttf',
'/usr/share/fonts/dejavu/DejaVuLGCSansMono-BoldOblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSans.ttf',
'/usr/local/share/fonts/gothambook/Gotham-Book.ttf',
'/usr/share/fonts/dejavu/DejaVuSansCondensed.ttf',
'/usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf',
'/usr/share/fonts/dejavu/DejaVuLGCSansMono-Bold.ttf',
'/usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf',
'/usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSansMono-Bold.ttf',
'/usr/share/fonts/dejavu/DejaVuSansCondensed-Bold.ttf',
'/usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf',
'/usr/share/fonts/dejavu/DejaVuSansMono.ttf']
I believe because even you ADDED the font.family to the rcParams but you haven't USED it on the xlabel:
mpl.pylab.xlabel("GOTHAM BOOK FONT", size=20)
Change it to this, should work:
mpl.pylab.xlabel("GOTHAM BOOK FONT", family='gothambook', size=20)
You can use fontdict to change the font settings on the xlabel, something like this works on mine:
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['font.family']
Out[1]: [u'sans-serif']
plt.rcParams['font.family'].append(u'Comic Sans MS')
font = {
'family' : 'Comic Sans MS',
'color' : 'blue',
'weight' : 'normal',
'size' : 18,
}
plt.plot(range(10), matplotlib.pylab.sin(range(10)))
plt.xlabel('Comic Sans MS FONT', fontdict=font)
Results:
Alternatively you can set parameters on the fly with this:
plt.xlabel('Comic Sans MS FONT', family='Comic Sans MS', fontsize=18, color='blue')
which will have same results, you can read more about the parameters on Text Properties
Hope this helps.
I am using matplotlib to create a graph for my thesis. I am using the following code:
import numpy as np
import numpy as np
import matplotlib as mpl
mpl.use('pgf')
fig_width_pt = 390 # Get this from LaTeX using \showthe\columnwidth
inches_per_pt = 1.0/72.27 # Convert pt to inch
golden_mean = (np.sqrt(5)-1.0)/2.0 # Aesthetic ratio
fig_width = fig_width_pt*inches_per_pt # width in inches
fig_height = fig_width*golden_mean # height in inches
fig_size = [fig_width,fig_height]
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": "serif",
"font.serif": [], # blank entries should cause plots to inherit fonts from the document
"font.sans-serif": [],
"font.monospace": [],
"axes.labelsize": 10, # LaTeX default is 10pt font.
"text.fontsize": 10,
"legend.fontsize": 8, # Make the legend/label fonts a little smaller
"xtick.labelsize": 8,
"ytick.labelsize": 8,
"figure.figsize": fig_size,
'axes.linewidth': .5,
'lines.linewidth': .5,
'patch.linewidth': .5,
"pgf.preamble": [
r"\usepackage[utf8x]{inputenc}", # use utf8 fonts becasue your computer can handle it :)
]
}
mpl.rcParams.update(pgf_with_latex)
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import colorsys
def savefig(filename):
plt.savefig('{}.pgf'.format(filename))
plt.savefig('{}.pdf'.format(filename))
# setup
title = 'Clustering after salting out'
ylabel = '% of total colloids'
xlabel = 'Cluster size'
xticklabels = ('1','2','3','4','5','6','7','5+')
legend = ['10min', '20min','30min']
# read data from files
# skipped this part for legibility
# calculations with data, skipped for legibility
# plot it in a bar plot
N = len(ys[0])
ind = np.arange(0, N+1, 1.2) # the x locations for the groups
width = 0.35 # the width of the bars
# generate colours
hsv_colours = [(x*1.0/N, 0.8, 0.8) for x in range(N)]
rgb_colours = map(lambda x: colorsys.hsv_to_rgb(*x), hsv_colours)
fig, ax = plt.subplots()
rects = [ax.bar([x+i*width for x in ind], y, width, color=rgb_colours[i], yerr=errors_percentage[i]) for i,y in enumerate(ys)]
# add some info
ax.set_ylabel(ylabel)
ax.set_xlabel(xlabel)
ax.set_title(title)
ax.set_xticks(ind+width)
ax.set_xticklabels(xticklabels)
ax.axis([0,7,0,60])
ax.legend(rects, legend)
savefig('tpm_cluster_statistics')
The output produced looks like this:
As you can see, the last bar of the bar plot is not totally filled. Do I need some other setting to get it working?
The goal is to create a PGF file for inclusion in a LaTex document. The PDF file is just for previewing. The partially filled bar is both in the PDF and in the PGF file.
Any help is greatly appreciated!
Edit:
In reply to tcaswell: this is a minimum working example that you can try on your computer:
import numpy as np
import numpy as np
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
}
mpl.rcParams.update(pgf_with_latex)
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import colorsys
def savefig(filename):
plt.savefig('{}.pgf'.format(filename))
plt.savefig('{}.pdf'.format(filename))
# setup
title = 'Title'
ylabel = 'x'
xlabel = 'y'
xticklabels = ('1','2','3','4','5','6','7','8')
legend = ['1', '2','3']
#data
ys = [[51.63593099345628, 28.911362284354553, 12.135633551457465, 4.521118381915526, 1.189767995240928, 0.7138607971445567, 0.41641879833432477, 0.4759071980963712], [46.66359871145882, 21.445006902899216, 14.496088357109988, 7.363092498849516, 4.1417395306028535, 3.313391624482283, 0.0, 2.577082374597331], [52.642595499738356, 22.39665096807954, 12.087912087912088, 7.744636316064887, 2.3547880690737837, 1.5698587127158554, 0.3663003663003663, 0.837257980115123]]
# plot it in a bar plot
N = len(ys[0])
ind = np.arange(0, N+1, 1.2) # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects = [ax.bar([x+i*width for x in ind], y, width) for i,y in enumerate(ys)]
# add some info
ax.set_ylabel(ylabel)
ax.set_xlabel(xlabel)
ax.set_title(title)
ax.set_xticks(ind+width)
ax.set_xticklabels(xticklabels)
ax.axis([0,7,0,60])
ax.legend(rects, legend)
savefig('tpm_cluster_statistics')
Then the result looks like this:
But when I remove these lines:
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
}
mpl.rcParams.update(pgf_with_latex)
And just show the output using plt.show(), the result does look correct.
I don't know what really causes it, but switching to just PDF output without the mpl.use('pgf') fixes the issue. For now I'll just stick to PDF, which is fine too. Thanks for all the help!
The following script:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as mpl
mpl.rc('font', family='sans-serif')
mpl.rc('text', usetex=True)
fig = mpl.figure()
ax = fig.add_subplot(1,1,1)
ax.text(0.2,0.5,r"Math font: $451^\circ$")
ax.text(0.2,0.7,r"Normal font (except for degree symbol): 451$^\circ$")
fig.savefig('test.png')
is an attempt to use a sans-serif font in matplotlib with LaTeX. The issue is that the math font is still a serif font (as indicated by the axis numbers, and as demonstrated by the labels in the center). Is there a way to set the math font to also be sans-serif?
I always have text.usetex = True in my matplotlibrc file. In addition to that, I use this as well:
mpl.rcParams['text.latex.preamble'] = [
r'\usepackage{siunitx}', # i need upright \micro symbols, but you need...
r'\sisetup{detect-all}', # ...this to force siunitx to actually use your fonts
r'\usepackage{helvet}', # set the normal font here
r'\usepackage{sansmath}', # load up the sansmath so that math -> helvet
r'\sansmath' # <- tricky! -- gotta actually tell tex to use!
]
Hope that helps.
The easiest way is to use matplotlib's internal TeX, e.g.:
import pylab as plt
params = {'text.usetex': False, 'mathtext.fontset': 'stixsans'}
plt.rcParams.update(params)
If you use an external LaTeX, you can use, e.g., CM Bright fonts:
params = {'text.usetex': True,
'text.latex.preamble': [r'\usepackage{cmbright}', r'\usepackage{amsmath}']}
plt.rcParams.update(params)
Note, that the CM Bright font is non-scalable, and you'll not be able to save PDF/PS!
Same with other options with external LaTeX I've found so far.
This will enable you to use the Computer Modern Sans font if you, as I, prefer it over Helvetica:
mpl.rcParams['text.usetex'] = True
mpl.rcParams['text.latex.preamble'] = [r'\usepackage[cm]{sfmath}']
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = 'cm'