Modificar texto do rótulo de marca

215

Quero fazer algumas modificações em alguns rótulos de carrapatos selecionados em um gráfico.

Por exemplo, se eu fizer:

label = axes.yaxis.get_major_ticks()[2].label
label.set_fontsize(size)
label.set_rotation('vertical')

o tamanho da fonte e a orientação do rótulo do tick são alterados.

No entanto, se tentar:

label.set_text('Foo')

o rótulo do carrapato não é modificado. Além disso, se eu fizer:

print label.get_text()

nada é impresso.

Aqui está um pouco mais de estranheza. Quando eu tentei isso:

 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()

Somente seqüências de caracteres vazias são impressas, mas o gráfico contém marcações marcadas como '0.0', '0.5', '1.0', '1.5' e '2.0'.

repoman
fonte
Você pode fornecer a plotagem usada para obter o rótulo?
Claudio
Você está recebendo rótulos em branco porque ainda não desenhou a tela. Se você ligar draw()antes de tentar imprimir as etiquetas, obterá o que espera. Infelizmente, a definição de rótulos de ticks individuais é um pouco mais difícil (o que está acontecendo é que o localizador e o formatador de ticks não foram redefinidos e substituem as coisas quando você set_text). Vou adicionar um exemplo daqui a pouco, se alguém não me vencer. Eu tenho que pegar o ônibus, no momento, no entanto.
31812 Joe Kington
@JoeKington: Ótimo! Ansioso para ver sua correção.
Repoman
@ repoman - Bem, parece que falei um pouco cedo demais. O que eu tinha em mente funciona para versões mais antigas do matplotlib, mas não para a versão mais recente. Eu preciso cavar um pouco mais. Dito isto, este não deve ser tão complicado como é ...
Joe Kington

Respostas:

298

Advertência: A menos que os ticklabels já estejam definidos como uma string (como é geralmente o caso, por exemplo, em um boxplot), isso não funcionará com nenhuma versão do matplotlib mais recente 1.1.0. Se você estiver trabalhando com o mestre atual do github, isso não funcionará. Ainda não tenho certeza de qual é o problema ... Pode ser uma alteração não intencional ou pode não ser ...

Normalmente, você faria algo assim:

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()

insira a descrição da imagem aqui

Para entender o motivo pelo qual você precisa passar por tantos obstáculos, você precisa entender um pouco mais sobre como o matplotlib está estruturado.

O Matplotlib evita deliberadamente o posicionamento "estático" de ticks, etc., a menos que seja explicitamente solicitado. Supõe-se que você deseje interagir com o enredo, e assim os limites do enredo, ticks, ticklabels etc. serão alterados dinamicamente.

Portanto, você não pode simplesmente definir o texto de um determinado rótulo de marca. Por padrão, é redefinido pelo Localizador e formatador do eixo toda vez que o gráfico é desenhado.

No entanto, se os localizadores e os formatadores estiverem definidos como estáticos ( FixedLocatore FixedFormatter, respectivamente), os rótulos dos marcadores permanecerão os mesmos.

Isto é o que set_*ticklabelsou ax.*axis.set_ticklabelsfaz.

Espero que isso torne um pouco mais claro o motivo pelo qual a alteração de um rótulo de marca individual é um pouco complicada.

Muitas vezes, o que você realmente deseja fazer é apenas anotar uma certa posição. Nesse caso, examine annotate.

Joe Kington
fonte
10
isso não parece funcionar com a versão atual (1.20)!
Andrew Jaffe
1
Se os ticklabels já estiverem definidos como uma string como em, por exemplo, um boxplot, isso ainda funcionará. Isso pode ser óbvio, mas como a primeira linha da resposta é que ela não está funcionando nas versões mais recentes do matplotlib, os usuários podem ignorá-la completamente (eu fiz inicialmente). Talvez mencione isso brevemente.
Joelostblom
2
eu acho que você pode condensá-lo para baixo para plt.gca () set_xticklabels (etiquetas).
alexey
e se eu quiser que o peso da fonte de "testing" seja boldenquanto outros usam o peso da fonte de "light". Existe uma forma de fazer isso?
Steven
1
para aqueles que usam isso em um notebook jupyter podem se beneficiar de observar que isso fig.canvas.draw()é crucial
wander95
95

Também é possível fazer isso com o pylab e o xticks

import matplotlib
import matplotlib.pyplot 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

rafaelvalle
fonte
Esta é uma solução simples e funciona com o pyplot 1.5.1. Isso deve ser votado.
wordsmith
Embora a pergunta não tenha solicitado isso, compreendo que este exemplo permite definir o local dos ticks ao mesmo tempo em que modifica seus rótulos.
Eclark 23/05
Nos documentos modernos do matplotlib : "o pylab está obsoleto e seu uso é fortemente desencorajado por causa da poluição do espaço para nome. Use o pyplot."
Nathaniel Jones
93

Nas versões mais recentes de matplotlib, se você não definir os rótulos de ticks com vários strvalores, eles são ''por padrão (e quando o gráfico é desenhado, os rótulos são simplesmente os valores dos ticks). Sabendo disso, para obter a saída desejada, seria necessário algo como isto:

>>> 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()

e o resultado: insira a descrição da imagem aqui

e agora, se você verificar _xticklabels, eles não são mais um monte de ''.

>>> [item.get_text() for item in axes.get_xticklabels()]
['0.0', 'change', '1.0', '1.5', '2.0']

Ele funciona nas versões da 1.1.1rc1versão atual 2.0.

CT Zhu
fonte
Obrigado, esta é a resposta que eu estava procurando. Solução mais limpa IMO; basta fornecer set_xticklabelsuma lista mista de strings e objetos de tick.
Luke Davis
Esteja ciente de que, se os rótulos dos marcadores estiverem definidos como ints, eles serão alterados para flutuadores. Trabalhou facilmente, mas vale a pena notar.
Aproximando-se
Este funcionou ( ax.get_xticks().tolist()). A solução mais votada não ( ax.get_xtickslabels()). De alguma forma, não foi possível extrair os rótulos antes da plt.show()extração, embora eu tenha usado fig.canvas.draw()como sugerido.
CypherX
Para sua informação, nos documentos modernos do matplotlib : "o pylab está obsoleto e seu uso é fortemente desencorajado por causa da poluição do espaço de nome. Use o pyplot".
Nathaniel Jones
17

Já faz um tempo desde que essa pergunta foi feita. A partir de hoje ( matplotlib 2.2.2) e depois de algumas leituras e testes, acho que a melhor / melhor maneira é a seguinte:

Matplotlib tem um módulo chamado tickerque "contém classes para suporte de localização carrapato completamente configurável e formatação" . Para modificar um tick específico da plotagem, o seguinte funciona para mim:

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()

Histograma com valores aleatórios de uma distribuição normal

Embargo! xé o valor do tick e posé sua posição relativa em ordem no eixo. Observe que posaceita valores começando em 1, não 0como de costume durante a indexação.


No meu caso, eu estava tentando formatar o y-axishistograma com valores percentuais. mtickertem outra classe chamada PercentFormatterque pode fazer isso facilmente sem a necessidade de definir uma função separada como antes:

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()

Histograma com valores aleatórios de uma distribuição normal

Nesse caso, xmaxé o valor dos dados que corresponde a 100%. As porcentagens são calculadas como x / xmax * 100, é por isso que corrigimos xmax=1.0. Além disso, decimalsé o número de casas decimais após o ponto.

iipr
fonte
12

A classe de eixos possui uma função set_yticklabels que permite definir os rótulos dos ticks , da seguinte maneira:

#ax is the axes instance
group_labels = ['control', 'cold treatment',
             'hot treatment', 'another treatment',
             'the last one']

ax.set_xticklabels(group_labels)

Ainda estou trabalhando por que o seu exemplo acima não funcionou.

Stanri
fonte
3
Mas eu só quero alterar um único rótulo. O truque acima exige que você extraia todos os rótulos de marca e defina a desejada para um novo valor. Mas como posso extrair os rótulos dos marcadores quando label.get_text () não retorna nada?
repoman
11

Isso funciona:

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)

FEDERAIS

Soham
fonte
7

Isso também funciona no matplotlib 3:

x1 = [0,1,2,3]
squad = ['Fultz','Embiid','Dario','Simmons']

plt.xticks(x1, squad, rotation=45)
MichaelSB
fonte
5

Se você não trabalha com fige axdeseja modificar todos os rótulos (por exemplo, para normalização), pode fazer o seguinte:

labels, locations = plt.yticks()
plt.yticks(labels, labels/max(labels))
dopexxx
fonte
1

Tente o seguinte:

  fig,axis = plt.subplots(nrows=1,ncols=1,figsize=(13,6),sharex=True)
  axis.set_xticklabels(['0', 'testing', '10000', '20000', '30000'],fontsize=22)
Aymen Alsaadi
fonte
-4

você pode fazer:

for k in ax.get_xmajorticklabels():
    if some-condition:
        k.set_color(any_colour_you_like)

draw()
Hachi Manzur
fonte
Alguém pode explicar por que essa resposta é tão criticada?
Hlynur Davíð Hlynsson
@ HlynurDavíHlynsson Acho que não tem nada a ver com a questão. Bem, talvez com alguma edição ... Por favor, edite-o, se conseguir relacioná-lo com a pergunta. ;)
loved.by.Jesus