3

I'm using 'text.usetex': True in matplotib. This is nice for plots with a linear scale. For a log-scale however, the y-ticks looks like this:

The minus signs in the exponents take a lot of horizontal space in a plot, which is not very nice. I want it to rather look like that:

That one is from gnuplot, and it's not using the tex-font. I would like to use matplotlib, have it rendered in tex, but the minus signs in 10^{-n} should be shorter. Is that possible?

thomasfermi
  • 1,183
  • 1
  • 10
  • 20

2 Answers2

5

The length of the minus sign is a decision of your LaTeX font - in math mode binary and unary minuses have the same length. According to this answer you can make your own labels. Try this:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib import ticker


mpl.rcParams['text.usetex']=True
mpl.rcParams['text.latex.unicode']=True

def my_formatter_fun(x, p):
    """ Own formatting function """
    return r"$10$\textsuperscript{%i}" % np.log10(x)  #  raw string to avoid "\\"


x = np.linspace(1e-6,1,1000)
y = x**2

fg = plt.figure(1); fg.clf()
ax = fg.add_subplot(1, 1, 1)
ax.semilogx(x, x**2)
ax.set_title("$10^{-3}$ versus $10$\\textsuperscript{-3} versus "
             "10\\textsuperscript{-3}")
# Use own formatter:
ax.get_xaxis().set_major_formatter(ticker.FuncFormatter(my_formatter_fun))

fg.canvas.draw()
plt.show()

to obtain: Resulting plot

Community
  • 1
  • 1
Dietrich
  • 5,241
  • 3
  • 24
  • 36
4

Dietrich gave you a nice answer, but if you want to keep all the functionality (non-base 10, non-integer exponents) of LogFormatter, then you might create your own formatter:

import matplotlib.ticker
import matplotlib
import re

# create a definition for the short hyphen
matplotlib.rcParams["text.latex.preamble"].append(r'\mathchardef\mhyphen="2D')

class MyLogFormatter(matplotlib.ticker.LogFormatterMathtext):
    def __call__(self, x, pos=None):
        # call the original LogFormatter
        rv = matplotlib.ticker.LogFormatterMathtext.__call__(self, x, pos)

        # check if we really use TeX
        if matplotlib.rcParams["text.usetex"]:
            # if we have the string ^{- there is a negative exponent
            # where the minus sign is replaced by the short hyphen
            rv = re.sub(r'\^\{-', r'^{\mhyphen', rv)

        return rv

The only thing this really does is to grab the output of the usual formatter, find the possible negative exponents and change the LaTeX code of the math minus into something else. Of course, if you invent some creative LaTex with \scalebox or something equivalent, you may do so.

This:

import matplotlib.pyplot as plt
import numpy as np

matplotlib.rcParams["text.usetex"] = True
fig = plt.figure()
ax = fig.add_subplot(111)
ax.semilogy(np.linspace(0,5,200), np.exp(np.linspace(-2,3,200)*np.log(10)))
ax.yaxis.set_major_formatter(MyLogFormatter())
fig.savefig("/tmp/shorthyphen.png")

creates:

enter image description here

The good thing about this solution is that it changes the output as minimally as possible.

DrV
  • 22,637
  • 7
  • 60
  • 72