Могу ли я показать десятичные знаки и научную нотацию на оси графика matplotlib с использованием Python 2.7?

Я рисую некоторые большие числа с matplotlib в программе pyqt, используя python 2.7. Я имею ось y, которая колеблется от 1e + 18 до 3e + 18 (обычно). Я бы хотел, чтобы каждая отметка показывала значения в научной нотации и с двумя знаками после запятой. Например, 2.35e + 18 вместо 2e + 18, потому что значения между 2e + 18 и 3e + 18 все еще читают только 2e + 18 для нескольких контрольных точек. Вот пример этой проблемы.

import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.linspace(0, 300, 20)
y = np.linspace(0,300, 20)
y = y*1e16
ax.plot(x,y)  
ax.get_xaxis().set_major_formatter(plt.LogFormatter(10,  labelOnlyBase=False))
ax.get_yaxis().set_major_formatter(plt.LogFormatter(10,  labelOnlyBase=False))
plt.show()

Ответ 1

Это действительно легко сделать, если вы используете matplotlib.ticker.FormatStrFormatter, а не LogFormatter. Следующий код будет обозначать все в формате '%.2e':

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick

fig = plt.figure()

ax = fig.add_subplot(111)

x = np.linspace(0, 300, 20)

y = np.linspace(0,300, 20)
y = y*1e16

ax.plot(x,y)

ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.2e'))

plt.show()

Example plot

Ответ 2

Чтобы получить красиво отформатированные метки в научной нотации, можно использовать возможности форматирования ScalarFormatter который использует MathText (Latex) и применяет его к меткам.

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker

fig, ax = plt.subplots()

x = np.linspace(0, 300, 20)
y = np.linspace(0,300, 20)
y = y*1e16

ax.plot(x,y)

f = mticker.ScalarFormatter(useOffset=False, useMathText=True)
g = lambda x,pos : "${}$".format(f._formatSciNotation('%1.10e' % x))
plt.gca().yaxis.set_major_formatter(mticker.FuncFormatter(g))

plt.show()

enter image description here

Хотя это может быть полезно во многих случаях, оно фактически не отвечает требованиям этого вопроса. Чтобы иметь равные цифры на всех ярлыках, можно использовать более индивидуальную версию.

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker

fig, ax = plt.subplots()

x = np.linspace(0, 300, 20)
y = np.linspace(0,300, 20)
y = y*1e16

ax.plot(x,y)

class MathTextSciFormatter(mticker.Formatter):
    def __init__(self, fmt="%1.2e"):
        self.fmt = fmt
    def __call__(self, x, pos=None):
        s = self.fmt % x
        decimal_point = '.'
        positive_sign = '+'
        tup = s.split('e')
        significand = tup[0].rstrip(decimal_point)
        sign = tup[1][0].replace(positive_sign, '')
        exponent = tup[1][1:].lstrip('0')
        if exponent:
            exponent = '10^{%s%s}' % (sign, exponent)
        if significand and exponent:
            s =  r'%s{\times}%s' % (significand, exponent)
        else:
            s =  r'%s%s' % (significand, exponent)
        return "${}$".format(s)

# Format with 2 decimal places
plt.gca().yaxis.set_major_formatter(MathTextSciFormatter("%1.2e"))

plt.show()

enter image description here