Изменить текст метки

Я хочу внести некоторые изменения в несколько выбранных меток на графике.

Например, если я делаю:

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()
Другие вопросы по тегам