Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 294
Ian Avatar asked Sep 11 '18 14:09

Ian


People also ask

What is Matplotlib ticker logformatter?

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.

How do I find the location of a tick in Matplotlib?

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.

How do I use funcformatter in Matplotlib?

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.

What is Matplotlib in Python?

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.


2 Answers

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"))

enter image description here

like image 113
ImportanceOfBeingErnest Avatar answered Oct 18 '22 22:10

ImportanceOfBeingErnest


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.

enter image description here

like image 23
Joooeey Avatar answered Oct 18 '22 22:10

Joooeey