I am trying to plot a graph with a logarithmic y-axis using pgf_with_latex
, i.e. all text formatting is done by pdflatex. In my matplotlib rc Parameters I define a font to be used. Here comes my problem: The standard matplotlib.ticker.LogFormatterSciNotation
formatter used math text and therefore a math font, which does not fit the rest of the fonts (sans-serif).
How can I format the y-axis labels using a formatter from matplotlib.ticker
so that I get the labels formatted as powers of 10 with superscripted powers? To be more specific: How do I get these yticklabels formatted the same way but with the font from the xticklabels?
I already tried using different formatters provided by matplotlib.ticker
, but none of them has the exponents written the way I want.
Here is an example of what I mean with a MWE below.
import matplotlib as mpl
mpl.use('pgf')
pgf_with_latex = {
"pgf.texsystem": "pdflatex",
"font.family": "sans-serif",
"text.usetex": False,
"pgf.preamble": [
r"\usepackage[utf8x]{inputenc}",
r"\usepackage{tgheros}", # TeX Gyre Heros sans serif
r"\usepackage[T1]{fontenc}"
]
}
mpl.rcParams.update(pgf_with_latex)
import matplotlib.pyplot as plt
fig = plt.figure(figsize=[3, 2])
ax = fig.add_subplot(111)
ax.set_yscale("log")
ax.minorticks_off()
ax.set_xlabel("sans-serif font label")
ax.set_ylabel("math font label")
plt.gca().set_ylim([1, 10000])
plt.gcf().tight_layout()
plt.savefig('{}.pdf'.format("test"))
Caution: A TeX distribution has to be installed on your system to run this. I used MikTex 2.9. Also Python 3.6.2 and matplotlib 2.1.2.
Matplotlib is a multi-platform data visualization library built on NumPy arrays and designed to work with the broader SciPy stack. The matplotlib.ticker.LogFormatter class is used for formatting ticks on a log or symlog scale. It is either instantiated directly or is subclassed.
The matplotlib.ticker.LinearLocator class is used to determine the tick locations. At its first call the function tries to set up the number of ticks to make a nice tick partitioning.
For function input, a FuncFormatter with the input function will be generated and used. See Major and minor ticks for an example of setting major and minor ticks. See the matplotlib.dates module for more information and examples of using date locators and formatters.
Matplotlib is an amazing visualization library in Python for 2D plots of arrays. Matplotlib is a multi-platform data visualization library built on NumPy arrays and designed to work with the broader SciPy stack.
You could subclass LogFormatterExponent
to format the ticks with "10\textsuperscript{x}"
where x
is the exponent. This would not use math mode tex, i.e. no $
signs around the text, and therefore would use the textfont specified in the preamble (in this case the font without serifs).
import matplotlib as mpl
from matplotlib.ticker import LogFormatterExponent
mpl.use('pgf')
pgf_with_latex = {
"pgf.texsystem": "pdflatex",
"font.family": "sans-serif",
"text.usetex": False,
"pgf.preamble": [
r"\usepackage[utf8x]{inputenc}",
r"\usepackage{tgheros}", # TeX Gyre Heros sans serif
r"\usepackage[T1]{fontenc}"
]
}
mpl.rcParams.update(pgf_with_latex)
import matplotlib.pyplot as plt
class LogFormatterTexTextMode(LogFormatterExponent):
def __call__(self, x, pos=None):
x = LogFormatterExponent.__call__(self, x,pos)
s = r"10\textsuperscript{{{}}}".format(x)
return s
fig = plt.figure(figsize=[3, 2])
ax = fig.add_subplot(111)
ax.set_yscale("log")
ax.yaxis.set_major_formatter(LogFormatterTexTextMode())
ax.minorticks_off()
ax.set_xlabel("sans-serif font label")
ax.set_ylabel("text mode tex label")
plt.gca().set_ylim([0.01, 20000])
plt.gcf().tight_layout()
plt.savefig('{}.pdf'.format("test"))
You can define your own FuncFormatter that does the scientific notation in unicode.
An almost complete converter to superscript was given in this answer. I just added the minus.
Here's an implementation:
# -*- coding: utf-8 -*-
from math import log10
SUPERSCRIPTS = dict(zip(u"-0123456789", u"⁻⁰¹²³⁴⁵⁶⁷⁸⁹"))
def unicode_sci_notation(x, pos):
"""Scientific notation of number with unicode"""
power = int(log10(x))
mantissa = x/(10**power)
superscript = u''.join(SUPERSCRIPTS[c] for c in unicode(power))
if mantissa == 1:
return '10%s' % superscript
else:
return '%.2f x 10%s' % (mantissa, superscript)
formatter = mpl.ticker.FuncFormatter(unicode_sci_notation)
ax.yaxis.set_major_formatter(formatter)
To do it this way, you need to specify coding: utf-8 at the top of your script. If you don't want that, you can escape the unicode characters as explained in the answer I linked.
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