Форматирование метки метки метки метки Matplotlib
С matplotlib
, когда масштаб шкалы задан для оси, метод по умолчанию, обозначающий эту ось, имеет число, равное 10, например, например. 10 ^ 6. Есть ли простой способ изменить все эти ярлыки как их полное числовое представление? например. 1, 10, 100 и т.д.
Обратите внимание, что я не знаю, какой диапазон полномочий будет и хочет поддерживать произвольный диапазон (включая негативы).
Ответы
Ответ 1
Конечно, просто измените форматирование.
Например, если у нас есть этот сюжет:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 100000])
ax.loglog()
plt.show()
![enter image description here]()
Вы можете установить метки галочек вручную, но тогда места галочек и метки будут фиксироваться при масштабировании/панорамировании/и т.д. Поэтому лучше всего изменить форматер. По умолчанию в логарифмической шкале используется LogFormatter
, который будет форматировать значения в научной нотации. Чтобы изменить форматирование по умолчанию для линейных осей (ScalarFormatter
), используйте, например,
from matplotlib.ticker import ScalarFormatter
for axis in [ax.xaxis, ax.yaxis]:
axis.set_major_formatter(ScalarFormatter())
![enter image description here]()
Ответ 2
Я обнаружил, что использование ScalarFormatter
прекрасно, если все значения тиков больше или равны 1. Однако, если у вас есть тик с номером <1
, ScalarFormatter
печатает метку тика как 0
.
![enter image description here]()
Мы можем использовать FuncFormatter
из модуля matplotlib ticker
, чтобы решить эту проблему. Самый простой способ сделать это - использовать функцию lambda
и спецификатор формата g
(спасибо @lenz в комментариях).
import matplotlib.ticker as ticker
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '{:g}'.format(y)))
Обратите внимание, что в своем исходном ответе я не использовал формат g
, вместо этого я придумал эту функцию lambda
с FuncFormatter
, чтобы установить числа >= 1
в их целочисленные значения, а числа <1
в их десятичное значение с минимальным количеством требуемых десятичных знаков (т.е. 0.1, 0.01, 0.001
и т.д.). Предполагается, что вы устанавливаете галочки только на значения base10
.
import matplotlib.ticker as ticker
import numpy as np
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y,pos: ('{{:.{:1d}f}}'.format(int(np.maximum(-np.log10(y),0)))).format(y)))
![enter image description here]()
Для ясности, здесь эта лямбда-функция написана более многословно, но также более понятно:
def myLogFormat(y,pos):
# Find the number of decimal places required
decimalplaces = int(np.maximum(-np.log10(y),0)) # =0 for numbers >=1
# Insert that number into a format string
formatstring = '{{:.{:1d}f}}'.format(decimalplaces)
# Return the formatted tick label
return formatstring.format(y)
ax.yaxis.set_major_formatter(ticker.FuncFormatter(myLogFormat))
Ответ 3
Я нашел ответы Джо и Тома очень полезными, но в комментариях к этим ответам есть много полезных деталей. Вот краткое изложение двух сценариев:
Диапазоны выше 1
Вот пример кода, как у Джо, но с более высоким диапазоном:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()
plt.show()
Это показывает сюжет, подобный этому, используя научную запись: ![Default plot with scientific notation]()
Как и в ответе Джо, я использую ScalarFormatter
, но я также называю set_scientific(False)
. Это необходимо, когда шкала поднимается до 1000000 или выше.
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
formatter = ScalarFormatter()
formatter.set_scientific(False)
axis.set_major_formatter(formatter)
plt.show()
![Plot with integer ticks]()
Диапазоны ниже 1
Как и в ответе Тома, вот что происходит, когда диапазон опускается ниже 1:
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
formatter = ScalarFormatter()
formatter.set_scientific(False)
axis.set_major_formatter(formatter)
plt.show()
Это отображает первые два тика на оси х как нули.
![Plot with ticks labelled as zero]()
Переключение на FuncFormatter
обрабатывает это. Опять же, у меня были проблемы с числами 1000000 или выше, но добавление точности к строке формата решило эту проблему.
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
formatter = FuncFormatter(lambda y, _: '{:.16g}'.format(y))
axis.set_major_formatter(formatter)
plt.show()
![enter image description here]()
Ответ 4
относительно этих вопросов
What if я wanted to change the numbers to, 1, 5, 10, 20?
– aloha Jul 10 '15 at 13:26
Я хотел бы добавить галочки между ними, например, 50 200 и т.д., как я могу сделать это? Я попытался, set_xticks [50.0,200.0], но это, похоже, не работает! - ThePredator 3 августа '15 в 12:54
Но с ax.axis([1, 100, 1, 100]) ScalarFormatter выдает 1.0, 10.0,... что не то, что я хочу. Я хочу, чтобы это дать целые числа... - CPBL 7 декабря 15 в 20:22
вы можете решить эту проблему следующим образом с помощью MINOR:
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.set_yticks([0.00000025, 0.00000015, 0.00000035])
в моем приложении я использую эту схему форматирования, которая, я думаю, решает большинство проблем, связанных со скалярным форматированием журнала; то же самое можно сделать для данных> 1.0 или форматирования по оси x:
plt.ylabel('LOGARITHMIC PRICE SCALE')
plt.yscale('log')
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
#####################################################
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
line = plt.gca().get_lines()[n]
yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])
#####################################################
z = []
for i in [0.0000001, 0.00000015, 0.00000025, 0.00000035,
0.000001, 0.0000015, 0.0000025, 0.0000035,
0.00001, 0.000015, 0.000025, 0.000035,
0.0001, 0.00015, 0.00025, 0.00035,
0.001, 0.0015, 0.0025, 0.0035,
0.01, 0.015, 0.025, 0.035,
0.1, 0.15, 0.25, 0.35]:
if ymin<i<ymax:
z.append(i)
ax.set_yticks(z)
для комментариев по поводу "принудительного автомасштабирования" см.: Python matplotlib - логарифмическое автоматическое масштабирование
что дает:
![enter image description here]()
затем для создания машины общего пользования:
# user controls
#####################################################
sub_ticks = [10,11,12,14,16,18,22,25,35,45] # fill these midpoints
sub_range = [-8,8] # from 100000000 to 0.000000001
format = "%.8f" # standard float string formatting
# set scalar and string format floats
#####################################################
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter(format))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter(format))
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
line = plt.gca().get_lines()[n]
yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])
# add sub minor ticks
#####################################################
set_sub_formatter=[]
for i in sub_ticks:
for j in range(sub_range[0],sub_range[1]):
set_sub_formatter.append(i*10**j)
k = []
for l in set_sub_formatter:
if ymin<l<ymax:
k.append(l)
ax.set_yticks(k)
#####################################################
выходы:
![enter image description here]()