Thursday, September 20, 2018

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

Leave a Comment

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.

2 Answers

Answers 1

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

Answers 2

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

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment