Modificar texto de etiqueta de marca

216

Quiero hacer algunas modificaciones a algunas etiquetas de marca seleccionadas en un gráfico.

Por ejemplo, si lo hago:

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

Se cambia el tamaño de fuente y la orientación de la etiqueta.

Sin embargo, si intentas:

label.set_text('Foo')

la etiqueta de marca no se modifica. También si lo hago:

print label.get_text()

No se imprime nada.

Aquí hay algo más extraño. Cuando probé esto:

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

Solo se imprimen cadenas vacías, pero el gráfico contiene marcas marcadas como '0.0', '0.5', '1.0', '1.5' y '2.0'.

hombre repo
fuente
¿Puede proporcionar la trama que utilizó para obtener la etiqueta?
Claudio
Obtiene etiquetas en blanco porque todavía no ha dibujado el lienzo. Si llama draw()antes de intentar imprimir las etiquetas, obtendrá lo que espera. Desafortunadamente, establecer etiquetas de marca individuales es un poco más difícil (lo que sucede es que el localizador y formateador de marca no se ha reiniciado y anula las cosas cuando usted set_text). Agregaré un ejemplo en un momento, si alguien no me gana. Sin embargo, tengo que tomar el autobús en este momento.
Joe Kington
@ JoeKington: ¡Genial! Esperamos ver su solución.
repoman
@repoman - Bueno, parece que hablé un poco demasiado pronto. Lo que tenía en mente funciona para versiones anteriores de matplotlib, pero no para la última versión. Necesito cavar un poco más. Dicho esto, esto no debería ser tan complicado como lo es ...
Joe Kington

Respuestas:

298

Advertencia: a menos que las etiquetas ya estén configuradas en una cadena (como suele ser el caso, por ejemplo, en un diagrama de caja), esto no funcionará con ninguna versión de matplotlib más nueva que 1.1.0. Si está trabajando desde el maestro github actual, esto no funcionará. Todavía no estoy seguro de cuál es el problema ... Puede ser un cambio no deseado, o puede no ser ...

Normalmente, harías algo en este sentido:

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

ingrese la descripción de la imagen aquí

Para comprender la razón por la que necesita pasar por tantos aros, necesita comprender un poco más sobre cómo está estructurado matplotlib.

Matplotlib evita deliberadamente realizar el posicionamiento "estático" de las garrapatas, etc., a menos que se indique explícitamente. La suposición es que querrá interactuar con la trama, por lo que los límites de la trama, las marcas, las marcas de verificación, etc. cambiarán dinámicamente.

Por lo tanto, no puede simplemente establecer el texto de una etiqueta de marca dada. De forma predeterminada, el Localizador y Formateador del eje lo restablece cada vez que se dibuja el gráfico.

Sin embargo, si los localizadores y formateadores están configurados para ser estáticos ( FixedLocatory FixedFormatter, respectivamente), las etiquetas de marca permanecen igual.

Esto es lo que set_*ticklabelso ax.*axis.set_ticklabelshace.

Esperemos que eso aclare un poco más por qué cambiar una etiqueta de marca individual es un poco complicado.

A menudo, lo que realmente quieres hacer es anotar una determinada posición. En ese caso, busca en su annotatelugar.

Joe Kington
fuente
10
¡Esto no parece funcionar con la versión actual (1.20)!
Andrew Jaffe
1
Si las etiquetas ya están configuradas en una cadena como, por ejemplo, en un diagrama de caja, esto todavía funciona. Esto puede ser obvio, pero dado que la primera línea de la respuesta es que no funciona en las versiones más recientes de matplotlib, los usuarios pueden omitirlo por completo (inicialmente lo hice). Quizás mencione esto brevemente.
joelostblom
2
creo que puedes condensarlo en plt.gca (). set_xticklabels (etiquetas)
alexey
¿Qué pasa si quiero que sea el fontweight de "testing" boldmientras otros usan el fontweight de "light"? ¿Hay una manera de hacerlo?
steven
1
para aquellos que usan esto en un cuaderno jupyter pueden beneficiarse al notar que fig.canvas.draw()es crucial
wander95
96

También se puede hacer esto con pylab y 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
fuente
Esta es una solución simple y funciona con pyplot 1.5.1. Esto debería ser votado.
Wordsmith
Aunque la pregunta no preguntaba esto, agradezco que este ejemplo le permita establecer la ubicación de los ticks al mismo tiempo que modifica sus etiquetas.
eclark
De los documentos modernos de matplotlib : "pylab está en desuso y se desaconseja su uso debido a la contaminación del espacio de nombres. Utilice pyplot en su lugar".
Nathaniel Jones
93

En las versiones más recientes de matplotlib, si no establece las etiquetas de marca con un montón de strvalores, son'' por defecto (y cuando se dibuja el gráfico, las etiquetas son simplemente los valores de las marcas). Sabiendo eso, para obtener el resultado deseado requeriría algo como esto:

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

y el resultado: ingrese la descripción de la imagen aquí

y ahora si revisas el _xticklabels, ya no son muchos ''.

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

Funciona en las versiones de 1.1.1rc1a la versión actual 2.0.

CT Zhu
fuente
Gracias, esta es la respuesta que estaba buscando. Solución más limpia de la OMI; solo suministre set_xticklabelsuna lista mixta de cadenas y objetos de marca.
Luke Davis el
Tenga en cuenta que si las etiquetas de marca están configuradas como ints, esto las cambiará a flotantes. Fácilmente trabajado pero vale la pena señalar.
ApproachingDarknessFish
Este funcionó ( ax.get_xticks().tolist()). La solución más votada no lo hizo ( ax.get_xtickslabels()). De alguna manera no fue capaz de extraer las etiquetas antes de que plt.show()se eliminara, aunque lo usé fig.canvas.draw()como se sugirió.
CypherX
Para su información, de los documentos modernos de matplotlib : "pylab está en desuso y se desaconseja su uso debido a la contaminación del espacio de nombres. Utilice pyplot en su lugar".
Nathaniel Jones
17

Ha pasado un tiempo desde que se hizo esta pregunta. A partir de hoy ( matplotlib 2.2.2) y después de algunas lecturas y pruebas, creo que la mejor / adecuada es la siguiente:

Matplotlib tiene un módulo llamado tickerque "contiene clases para admitir localización y formateo de ticks completamente configurables" . Para modificar una marca específica de la trama, lo siguiente funciona para mí:

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 con valores aleatorios de una distribución normal.

¡Consideración! xes el valor de la marca y poses su posición relativa en orden en el eje. Tenga en cuenta que postoma valores que comienzan en 1, no 0como de costumbre al indexar.


En mi caso, estaba tratando de formatear el y-axishistograma con valores porcentuales. mtickertiene otra clase llamada PercentFormatterque puede hacer esto fácilmente sin la necesidad de definir una función 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 con valores aleatorios de una distribución normal.

En este caso xmaxes el valor de los datos que corresponde al 100%. Los porcentajes se calculan como x / xmax * 100, por eso lo arreglamos xmax=1.0. Además, decimalses el número de lugares decimales para colocar después del punto.

iipr
fuente
12

La clase de ejes tiene una función set_yticklabels que le permite establecer las etiquetas de marca, de esta manera:

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

ax.set_xticklabels(group_labels)

Todavía estoy trabajando en por qué su ejemplo anterior no funcionó.

Stanri
fuente
3
Pero solo quiero alterar una sola etiqueta. El truco anterior requiere que extraiga todas las etiquetas de marca y establezca la deseada en un nuevo valor. Pero, ¿cómo puedo extraer las etiquetas de marca cuando label.get_text () no devuelve nada?
repoman
11

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

Federales

Soham
fuente
7

Esto también funciona en matplotlib 3:

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

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

Si no se trabaja con figy axy desea modificar todas las etiquetas (por ejemplo, para la normalización) se puede hacer esto:

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

Prueba esto :

  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
fuente
-4

tu puedes hacer:

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

draw()
Hachi Manzur
fuente
¿Alguien puede explicar por qué esta respuesta está tan fuertemente rechazada?
Hlynur Davíð Hlynsson
@ HlynurDavíðHlynsson Creo que realmente no tiene nada que ver con la pregunta. Bueno, tal vez con algo de edición ... Edítelo, si logra relacionarlo con la pregunta. ;)
loved.by.Jesus