Is there a non-math version of matplotlib.ticker.LogFormatterSciNotation?

Question:

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.
example plot

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.

Asked By: Ian

||

Answers:

You could subclass LogFormatterExponent to format the ticks with "10textsuperscript{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"10textsuperscript{{{}}}".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"))

enter image description here

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 str(power))
    # Python 2: Use `unicode(power)` instead of `str(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.

enter image description here

Answered By: Joooeey