Python - matplotlib - Пользовательская метка тика в научной нотации c при использовании масштаба журнала? - PullRequest
0 голосов
/ 16 апреля 2020

У меня проблемы с matplotlib (версия 3.1.3): я хотел бы добавить собственные тики и метки тиков на оси масштаба журнала, сохраняя при этом научную нотацию c.

Иначе говоря: я хочу добавить пользовательские галочки на оси шкалы лога и пометить их, используя старый добрый формат «% 1.1e» (или любые другие числа), но, например, вместо того, чтобы иметь '2.5e-02', я хотел бы иметь '2.5 x 10 ^ -2' (или '2.5 \ times 10 ^ {- 2}' в латексе).

Поэтому я начинаю с минимальной рабочей нагрузки кусок кода без пользовательских тиков:

import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB  VERSION : %s' % mpl.__version__)

plt.style.use("default")

# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x

fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
path = ax.plot(x, y)

plt.savefig('test.png')

, что дает:

enter image description here

Хорошо, но, как я уже сказал, я бы хотел добавить пользовательские галочки на оси. Точнее, я бы хотел установить ограничения для оси и определить одинаково логарифмические метки между этими пределами. Допустим, я хочу 4 галочки; он дает следующий фрагмент кода:

import matplotlib as mpl
import matplotlib.pyplot as plt
print('MATPLOTLIB  VERSION : %s' % mpl.__version__)

plt.style.use("default")

# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x

xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)

# XTICKS
nbdiv = 4
xTicks = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
  xTicks.append(xmax*pow(k,i))

# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)

plt.savefig('test_working_4.png')

, который обеспечивает следующий график:

enter image description here

Это вид результата I хотел получить. Однако, если количество тиков (nbdiv) изменяется, например, становится равным 5, я получаю:

enter image description here

И на этот раз только первый и последние галочки помечены. Похоже, что помечены только числа, которые равны (или, по крайней мере, близки) целой степени десяти (10 ^ n). Я попытался изменить формат тиков по умолчанию с помощью matplot.ticker.ScalarFormatter, но мне не удалось настроить его для решения этой проблемы. Я также попробовал LogFormatterMathText и LogFormatterSciNotation, это было не лучше.

Сама по себе проблема не кажется мне такой сложной, поэтому я не понимаю, почему у меня так много проблем ... Что я делаю не так? У кого-то есть ключи, чтобы я понял мои ошибки?

В любом случае, я благодарю за чтение и заранее благодарю вас за ваш ответ.

PS: Извините за возможные ошибки sh, это не мой родной язык.

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Решено, на основе вашего кода выше. Этот намного проще. Вам нужно использовать xticklabels.

%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from sympy import pretty_print as pp, latex
print('MATPLOTLIB  VERSION : %s' % mpl.__version__)

plt.style.use("default")

# DATA
x = [0.1, 0.075, 0.05, 0.025, 0.01, 0.0075, 0.005, 0.0025, 0.001, 0.00075, 0.0005, 0.00025, 0.0001, 7.5e-05, 5e-05, 2.5e-05, 1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10]
y = x

xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)

# XTICKS
nbdiv = 5
xTicks = []
xticklabels = []
k = pow((xmin/xmax),1./(nbdiv-1.))
for i in range(0,nbdiv):
  xTicks.append(xmax*pow(k,i))
  printstr = '{:.2e}'.format(xmax*pow(k,i))
  ls = printstr.split('e')
  xticklabels.append((ls[0]+' x $10^{'  +ls[1] + '}$'))

# PLOT
fig = plt.figure()
ax = plt.axes()
plt.loglog()
plt.minorticks_off()
plt.axis([xmin,xmax,ymin,ymax])
plt.xticks(xTicks)
path = ax.plot(x, y)

plt.savefig('test_working_4.png')
ax.set_xticklabels(xticklabels)

enter image description here

0 голосов
/ 16 апреля 2020

Извините за двойную публикацию, но я пришел с решением, которое, даже если неудовлетворительно , может быть полезным для других.

Я считаю мое решение неудовлетворительным, поскольку оно включает преобразование формата " hand "со следующей моей функцией (я не эксперт в Python, поэтому я уверен, что это можно упростить / оптимизировать):

def convert_e_format_to_latex(numberAsStr):
# CONVERTS THE STRING numberAsStr IN FORMAT '%X.Ye' TO A LATEX 'X \\times 10^{Y}'
  baseStr = list(numberAsStr)
  ind = 0
  i = 0
  flag = True
  nStr = len(baseStr)
  while (i < nStr and flag):
    if (baseStr[i] == 'e' or baseStr[i] == 'E'): # NOT USING FIND BECAUSE 'e' CAN ALSO BE CAPITAL
      ind = i
      flag = False
    i += 1
  if (flag):
    print('ERROR: badly formatted input number')
    return ''
  else:
    expo = str(int(''.join(baseStr[ind+1:nStr]))) # GET RID OF POTENTIAL ZEROS
    root = ''.join(baseStr[0:ind])
    indP = root.find('.')
    integerPart = int(root[0:indP]) #integer
    decimalPart = root[indP+1:ind] #string
    if (integerPart == 1): #DETECTING IF THE ROOT IS ONE (positive value)
      x = ''.center(ind-(indP+1),'0')
      if (decimalPart == x):
        return '$10^{'+expo+'}$'
      else:
        return '$'+str(integerPart)+'.'+decimalPart+' \\times 10^{'+expo+'}$'
    elif (integerPart== -1): #DETECTING IF THE ROOT IS ONE (positive value)
      x = ''.center(ind-(indP+1),'0')
      if (decimalPart == x):
        return '$-10^{'+expo+'}$'
      else:
        return '$'+str(integerPart)+'.'+decimalPart+' \\times 10^{'+expo+'}$'
    else:
      return '$'+str(integerPart)+'.'+decimalPart+' \\times 10^{'+expo+'}$'

Затем я добавлю в свой предыдущий фрагмент кода:

for i in range(0,nbdiv):
  xTicksStr.append(convert_e_format_to_latex('%1.1e'%xTicks[i]))

И я изменяю инструкцию xticks на графике, которая становится:

plt.xticks(xTicks,xTicksStr)

Это дает желаемый результат:

enter image description here

Это работает, но это так сложно ... Я почти уверен, что пропустил более простую функциональность. Что вы думаете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...