Изменить текст метки
Я хочу внести некоторые изменения в несколько выбранных меток на графике.
Например, если я делаю:
label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
label.set_rotation('vertical')
размер шрифта и ориентация метки галочки изменены.
Однако, если попытаться:
label.set_text('Foo')
метка галочки не изменяется. Также, если я делаю:
print label.get_text()
ничего не напечатано.
Вот еще странность. Когда я попробовал это:
from pylab import *
axes = figure().add_subplot(111)
t = arange(0.0, 2.0, 0.01)
s = sin(2*pi*t)
axes.plot(t, s)
for ticklabel in axes.get_xticklabels():
print ticklabel.get_text()
Печатаются только пустые строки, но график содержит метки, помеченные как "0.0", "0.5", "1.0", "1.5" и "2.0".
13 ответов
Предостережение: если тиклэйблы уже не установлены в строку (как это обычно имеет место, например, в блокпосте), это не будет работать с любой версией matplotlib, более новой, чем 1.1.0
, Если вы работаете с текущим мастером github, это не сработает. Я не уверен, в чем проблема еще... Это может быть непреднамеренное изменение, или это не может быть...
Обычно вы делаете что-то вроде этого:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# We need to draw the canvas, otherwise the labels won't be positioned and
# won't have values yet.
fig.canvas.draw()
labels = [item.get_text() for item in ax.get_xticklabels()]
labels[1] = 'Testing'
ax.set_xticklabels(labels)
plt.show()
Чтобы понять причину, по которой вам нужно прыгать через такое большое количество обручей, вам нужно немного больше понять, как структурирован matplotlib.
Matplotlib сознательно избегает "статического" позиционирования тиков и т. Д., Если это явно не указано. Предполагается, что вы захотите взаимодействовать с сюжетом, и поэтому границы сюжета, галочки, метки и т. Д. Будут динамически изменяться.
Следовательно, вы не можете просто установить текст данной метки. По умолчанию он сбрасывается локатором и форматером оси каждый раз при построении графика.
Однако, если локаторы и форматеры установлены как статические (FixedLocator
а также FixedFormatter
соответственно), то метки останутся прежними.
Это то, что set_*ticklabels
или же ax.*axis.set_ticklabels
делает.
Надеюсь, что это делает более понятным, почему изменение индивидуальной метки тика немного запутано.
Часто, что вы действительно хотите сделать, это просто аннотировать определенную позицию. В этом случае посмотрите в annotate
вместо.
Можно также сделать это с pylab и xticks
import pylab as plt
x = [0,1,2]
y = [90,40,65]
labels = ['high', 'low', 37337]
plt.plot(x,y, 'r')
plt.xticks(x, labels, rotation='vertical')
plt.show()
http://matplotlib.org/examples/ticks_and_spines/ticklabels_demo_rotation.html
В новых версиях matplotlib
, если вы не установите метки галочки с кучей str
ценности, они ''
по умолчанию (и когда график рисуется, метки - это просто значения тиков). Зная это, чтобы получить желаемый результат, потребуется что-то вроде этого:
>>> from pylab import *
>>> axes = figure().add_subplot(111)
>>> a=axes.get_xticks().tolist()
>>> a[1]='change'
>>> axes.set_xticklabels(a)
[<matplotlib.text.Text object at 0x539aa50>, <matplotlib.text.Text object at 0x53a0c90>,
<matplotlib.text.Text object at 0x53a73d0>, <matplotlib.text.Text object at 0x53a7a50>,
<matplotlib.text.Text object at 0x53aa110>, <matplotlib.text.Text object at 0x53aa790>]
>>> plt.show()
и результат:
и теперь, если вы проверите _xticklabels
, они больше не куча ''
,
>>> [item.get_text() for item in axes.get_xticklabels()]
['0.0', 'change', '1.0', '1.5', '2.0']
Работает в версиях от 1.1.1rc1
к текущей версии 2.0
,
Прошло много времени с тех пор, как был задан этот вопрос. По состоянию на сегодня (matplotlib 2.2.2
) и после некоторого чтения и испытаний, я думаю, что лучший / правильный способ заключается в следующем:
Matplotlib имеет модуль с именем ticker
это "содержит классы для поддержки полностью настраиваемого определения и форматирования тиков". Чтобы изменить конкретный тик из графика, у меня работает следующее:
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
def update_ticks(x, pos):
if x == 0:
return 'Mean'
elif pos == 6:
return 'pos is 6'
else:
return x
data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
ax.hist(data, bins=25, edgecolor='black')
ax.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
plt.show()
Предостережение! x
это значение галочки и pos
это его относительное положение по порядку на оси. Заметить, что pos
принимает значения, начиная с 1
, не в 0
как обычно при индексации.
В моем случае я пытался отформатировать y-axis
гистограммы с процентными значениями. mticker
имеет другой класс с именем PercentFormatter
это может сделать это легко без необходимости определять отдельную функцию, как раньше:
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
data = np.random.normal(0, 1, 1000)
fig, ax = plt.subplots()
weights = np.ones_like(data) / len(data)
ax.hist(data, bins=25, weights=weights, edgecolor='black')
ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0, decimals=1))
plt.show()
В этом случае xmax
это значение данных, которое соответствует 100%. Проценты рассчитываются как x / xmax * 100
вот почему мы исправляем xmax=1.0
, Также, decimals
количество знаков после запятой после точки.
Это работает:
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(1,1)
x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']
ax1.set_xticks(x1)
ax1.set_xticklabels(squad, minor=False, rotation=45)
Класс axes имеет функцию set_yticklabels, которая позволяет вам устанавливать метки тиков, например:
#ax is the axes instance
group_labels = ['control', 'cold treatment',
'hot treatment', 'another treatment',
'the last one']
ax.set_xticklabels(group_labels)
Я все еще работаю над тем, почему ваш пример выше не сработал.
Это также работает в matplotlib 3:
x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']
plt.xticks(x1, squad, rotation=45)
Если вы не работаете с fig
а также ax
и вы хотите изменить все метки (например, для нормализации), вы можете сделать это:
labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))
Здесь мы намерены изменить некоторые метки галочек вMatplotlib
но без побочных эффектов, который работает чисто и сохраняет смещение научных обозначений. Ни одна из проблем, обсуждаемых в некоторых других ответах, не встречается в этом решении.
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rcParams
rcParams['axes.formatter.use_mathtext'] = True
class CustomScalarFormatter(matplotlib.ticker.ScalarFormatter):
def __init__(self, useOffset=None, useMathText=None, useLocale=None, replace_values=([],[])):
super().__init__(useOffset=None, useMathText=None, useLocale=None)
self.replace_values = replace_values
def __call__(self, x, pos=None):
"""
Return the format for tick value *x* at position *pos*.
"""
if len(self.locs) == 0:
return ''
elif x in self.replace_values[0]:
idx = self.replace_values[0].index(x)
return str(self.replace_values[1][idx])
else:
xp = (x - self.offset) / (10. ** self.orderOfMagnitude)
if abs(xp) < 1e-8:
xp = 0
return self._format_maybe_minus_and_locale(self.format, xp)
z = np.linspace(0, 5000, 100)
fig, ax = plt.subplots()
xmajorformatter = CustomScalarFormatter(replace_values=([2000,0],['$x_0$','']))
ymajorformatter = CustomScalarFormatter(replace_values=([1E7,0],['$y_0$','']))
ax.xaxis.set_major_formatter(xmajorformatter)
ax.yaxis.set_major_formatter(ymajorformatter)
ax.plot(z,z**2)
plt.show()
Что мы сделали здесь, так это создали производный классmatplotlib.ticker.ScalarFormatter
класс, который matplotlib использует по умолчанию для форматирования меток. Код скопирован из исходников matplotlib, но в нем копируется и модифицируется только функция. Следующий
elif x in self.replace_values[0]:
idx = self.replace_values[0].index(x)
return str(self.replace_values[1][idx])
добавлены ли новые строки в__call__
функция, которая выполняет работу по замене. Преимущество производного класса заключается в том, что он наследует все функции базового класса, такие как нотация смещения, метки экспоненциальной нотации, если значения велики. Результат:
Попробуй это:
fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(13,6),sharex=True)
axis.set_xticklabels(['0', 'testing', '10000', '20000', '30000'],fontsize=22)
-
matplotlib.axes.Axes.set_xticks
, илиmatplotlib.axes.Axes.set_yticks
для оси Y можно использовать для изменения меток и меток, начинающихся сmatplotlib 3.5.0
. Это для объектно-ориентированного интерфейса.- Если использовать
pyplot
интерфейс на основе состояния , используйтеplt.xticks
илиplt.yticks
, как показано в других ответах. - В общих чертах передать a/чисел в
ticks
параметр, аlist
/array
строки кlabels
параметр.
- Если использовать
- В этом случае ось X состоит из непрерывных числовых значений, поэтому нет заданных текстовых меток, как подробно описано в этом ответе . Это не тот случай, когда графики имеют дискретные деления (например, прямоугольная диаграмма, столбчатая диаграмма).
-
[Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, ''), Text(0, 0, '')]
возвращаетсяax.get_xticklabels()
-
[-0.25 0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. 2.25]
возвращаетсяax.get_xticks()
-
type(ax.get_xticks())
является<class 'numpy.ndarray'>
-
type(ax.get_xticks()[0])
является<class 'numpy.float64'>
-
-
- Поскольку OP пытается заменить числовую метку на , все значения в
ndarray
должны быть преобразованы вstr
тип, и значение, которое нужно изменить, может быть обновлено. - Протестировано в
python 3.10
иmatplotlib 3.5.2
import numpy as np
import matplotlib.pyplot as plt
# create figure and axes
fig, ax = plt.subplots(figsize=(8, 6))
# plot data
t = np.arange(0.0, 2.0, 0.01)
s = np.sin(2*np.pi*t)
# plot
ax.plot(t, s)
# get the xticks, which are the numeric location of the ticks
xticks = ax.get_xticks()
# get the xticks and convert the values in the array to str type
xticklabels = list(map(str, ax.get_xticks()))
# update the string to be changed
xticklabels[1] = 'Test'
# set the xticks and the labels
_ = ax.set_xticks(xticks, xticklabels)
- Обратите внимание, что смещение по оси x не сохраняется при изменении xticklabels. Однако правильное значение отображается без смещения.
# create figure and axes
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 6), sharex=False)
# plot data
t = np.linspace(0, 1500000, 100)
s = t**2
# plot
ax1.plot(t, s)
ax2.plot(t, s)
# get the xticks, which are the numeric location of the ticks
xticks = ax2.get_xticks()
# get the xticks and convert the values in the array to str type
xticklabels = list(map(str, ax2.get_xticks()))
# update the string to be changed
xticklabels[1] = 'Test'
# set the xticks and the labels
_ = ax2.set_xticks(xticks, xticklabels, rotation=90)
Я заметил, что все опубликованные здесь решения, использующие
set_xticklabels()
не сохраняют смещение, которое является коэффициентом масштабирования, применяемым к значениям отметок для создания более привлекательных меток отметок. Например, если тики имеют порядок 0,00001 (1e-5), matplotlib автоматически добавит коэффициент масштабирования (или
offset
) из
1e-5
, поэтому результирующие метки могут оказаться
1 2 3 4
, скорее, чем
1e-5 2e-5 3e-5 4e-5
.
Ниже приводится пример:
В
x
массив
np.array([1, 2, 3, 4])/1e6
, и
y
является
y=x**2
. Так что оба значения очень маленькие.
Левый столбец: вручную измените 1-й и 3-й ярлыки, как предлагает @Joe Kington. Обратите внимание, что смещение потеряно.
Средний столбец: аналогично предложению @iipr, с использованием
FuncFormatter
.
Правый столбец: предложенное мной решение для сохранения смещения.
Полный код здесь:
import matplotlib.pyplot as plt
import numpy as np
# create some *small* data to plot
x = np.arange(5)/1e6
y = x**2
fig, axes = plt.subplots(1, 3, figsize=(10,6))
#------------------The set_xticklabels() solution------------------
ax1 = axes[0]
ax1.plot(x, y)
fig.canvas.draw()
labels = [item.get_text() for item in ax1.get_xticklabels()]
# Modify specific labels
labels[1] = 'Testing'
labels[3] = 'Testing2'
ax1.set_xticklabels(labels)
ax1.set_title('set_xticklabels()')
#--------------FuncFormatter solution--------------
import matplotlib.ticker as mticker
def update_ticks(x, pos):
if pos==1:
return 'testing'
elif pos==3:
return 'testing2'
else:
return x
ax2=axes[1]
ax2.plot(x,y)
ax2.xaxis.set_major_formatter(mticker.FuncFormatter(update_ticks))
ax2.set_title('Func Formatter')
#-------------------My solution-------------------
def changeLabels(axis, pos, newlabels):
'''Change specific x/y tick labels
Args:
axis (Axis): .xaxis or .yaxis obj.
pos (list): indices for labels to change.
newlabels (list): new labels corresponding to indices in <pos>.
'''
if len(pos) != len(newlabels):
raise Exception("Length of <pos> doesn't equal that of <newlabels>.")
ticks = axis.get_majorticklocs()
# get the default tick formatter
formatter = axis.get_major_formatter()
# format the ticks into strings
labels = formatter.format_ticks(ticks)
# Modify specific labels
for pii, lii in zip(pos, newlabels):
labels[pii] = lii
# Update the ticks and ticklabels. Order is important here.
# Need to first get the offset (1e-6 in this case):
offset = formatter.get_offset()
# Then set the modified labels:
axis.set_ticklabels(labels)
# In doing so, matplotlib creates a new FixedFormatter and sets it to the xaxis
# and the new FixedFormatter has no offset. So we need to query the
# formatter again and re-assign the offset:
axis.get_major_formatter().set_offset_string(offset)
return
ax3 = axes[2]
ax3.plot(x, y)
changeLabels(ax3.xaxis, [1, 3], ['Testing', 'Testing2'])
ax3.set_title('With offset')
fig.show()
plt.savefig('tick_labels.png')
Предупреждение: похоже, что решения, использующие
set_xticklabels()
, включая мою собственную, полагается на
FixedFormatter
, который статичен и не реагирует на изменение размера фигуры. Чтобы наблюдать эффект, измените рисунок на меньший размер, например
fig, axes = plt.subplots(1, 3, figsize=(6,6))
и увеличьте окно рисунка. Вы заметите, что только средний столбец реагирует на изменение размера и добавляет больше меток по мере увеличения числа. В левом и правом столбце будут пустые метки для галочки (см. Рисунок ниже).
Предостережение 2: я также заметил, что если ваши значения тиков являются плавающими, вызов
set_xticklabels(ticks)
напрямую может дать вам уродливые строки, например
1.499999999998
вместо
1.5
.
Ты можешь сделать:
for k in ax.get_xmajorticklabels():
if some-condition:
k.set_color(any_colour_you_like)
draw()