10

I'd like my numbers in annotations be like {x}\cdot10^{y}, not as they are now: {x}E+{y}. Is there a suitable string formatter for this?

The most ideal solution for me would be to use a format string, like '%.2e', but with automatic conversion to the power of ten representation.

klmn
  • 113
  • 1
  • 1
  • 6
  • Maybe [this is the answer you are looking for](http://stackoverflow.com/questions/16529038/matplotlib-tick-axis-notation-with-superscript/16530841#16530841). – Schorsch Aug 19 '13 at 11:16
  • As for your request for defining a string format specifier (e.g. `%e`), I'm not totally sure, but I believe this is rather impossible without messing with the internals of Python (i.e. recompile Python from the source code, with your modifications). – sodd Aug 19 '13 at 12:44

3 Answers3

17

You can define your own string formatter for use with LaTeX or Mathtext. In the function sci_notation() defined below you can specify the number of significant decimal digits as well as how many decimal digits to print (default to the number of significant decimal digits). It is also possible to explicitly specify which exponent should be used.

from math import floor, log10

# Use LaTeX as text renderer to get text in true LaTeX
# If the two following lines are left out, Mathtext will be used
import matplotlib as mpl
mpl.rc('text', usetex=True)

import matplotlib.pyplot as plt

# Define function for string formatting of scientific notation
def sci_notation(num, decimal_digits=1, precision=None, exponent=None):
    """
    Returns a string representation of the scientific
    notation of the given number formatted for use with
    LaTeX or Mathtext, with specified number of significant
    decimal digits and precision (number of decimal digits
    to show). The exponent to be used can also be specified
    explicitly.
    """
    if exponent is None:
        exponent = int(floor(log10(abs(num))))
    coeff = round(num / float(10**exponent), decimal_digits)
    if precision is None:
        precision = decimal_digits

    return r"${0:.{2}f}\cdot10^{{{1:d}}}$".format(coeff, exponent, precision)

scinum = -3.456342e-12

# Annotation with exponent notation using `e` as separator
plt.annotate(scinum, (0.5,0.5), ha='center', fontsize=20)

# Annotation with scientific notation using `\cdot 10` as separator
plt.annotate(sci_notation(scinum,1), (0.5,0.4), ha='center', fontsize=20)

# Annotation with scientific notation using `\cdot 10` as separator
# with 1 significant decimal digit and 2 decimal digits shown as well
# as a given exponent.
plt.annotate(sci_notation(scinum,1,2,exponent=-14), (0.5,0.3), ha='center', fontsize=20)

plt.title('Scientific notation', fontsize=14)

plt.show()

enter image description here

sodd
  • 12,482
  • 3
  • 54
  • 62
1
def round_to_n(x, n):
    " Round x to n significant figures "
    return round(x, -int(py.floor(py.sign(x) * py.log10(abs(x)))) + n)

def str_fmt(x, n=2):
    " Format x into nice Latex rounding to n"
    power = int(py.log10(Round_To_n(x, 0)))
    f_SF = Round_To_n(x, n) * pow(10, -power)
    return r"${}\cdot 10^{}$".format(f_SF, power)

>>> x = 1203801.30201
>>> str_fmt(x)
$1.2\\cdot 10^6$

Many variations exist on how to parametrise this, e.g you could specify the exponent (y) rather than automatically generate it but the principle remains the same.

Greg
  • 11,654
  • 3
  • 44
  • 50
  • Thanks Greg! I've edited my question to add an interface to a user format string. I suppose I have to combine your code with a format string parser in order to define 'n'. Is there a simple solution? – klmn Aug 19 '13 at 12:34
1

Here is a fairly simple way to do it, though it may need to be adapted depending on the number of digits in the exponent:

x=17875.764
print(x)
print(((str("%.1e" % x)).replace("e", ' \\cdot 10^{ ')).replace("+0", "") + ' } ')
Mister Mak
  • 276
  • 1
  • 9