Girar el texto del eje en python matplotlib

314

No puedo entender cómo rotar el texto en el eje X. Es una marca de tiempo, por lo que a medida que aumenta el número de muestras, se acercan cada vez más hasta que se superponen. Me gustaría rotar el texto 90 grados para que las muestras se acerquen y no se superpongan.

A continuación es lo que tengo, funciona bien con la excepción de que no puedo entender cómo rotar el texto del eje X.

import sys

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import datetime

font = {'family' : 'normal',
        'weight' : 'bold',
        'size'   : 8}

matplotlib.rc('font', **font)

values = open('stats.csv', 'r').readlines()

time = [datetime.datetime.fromtimestamp(float(i.split(',')[0].strip())) for i in values[1:]]
delay = [float(i.split(',')[1].strip()) for i in values[1:]]

plt.plot(time, delay)
plt.grid(b='on')

plt.savefig('test.png')
tMC
fuente
3
Consulte esta respuesta para obtener información importante sobre la alineación de las etiquetas giradas con ha(alineación horizontal)
LondonRob

Respuestas:

513

Esto funciona para mi:

plt.xticks(rotation=90)
scottlittle
fuente
8
En caso de que alguien más esté usando mpld3 y se sienta frustrado porque ninguna de estas soluciones funciona. La rotación no es compatible con mpld3.
Beetree
44
Puntos extra por hacer que estos permanezcan dentro de la figura / ventana. Los míos están a medias afuera.
Gauthier
1
Llame a esto después de trazar. Es decir, primero ax.plot(...)entoncesplt.xticks(rotation=90)
CGFoX
161

Manera fácil

Como se describe aquí , hay un método existente en la matplotlib.pyplot figureclase que rota automáticamente las fechas de manera apropiada para su figura.

Puede llamarlo después de trazar sus datos (es decir ax.plot(dates,ydata):

fig.autofmt_xdate()

Si necesita formatear más las etiquetas, consulte el enlace de arriba.

Objetos que no son de fecha y hora

Según el comentario de languitar , el método que sugerí para que no sea datetime xticksno se actualizaría correctamente al hacer zoom, etc. Si no se trata de un datetimeobjeto utilizado como datos del eje x, debe seguir la respuesta de Tommy :

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
ryanjdillon
fuente
3
Esta es la mejor manera porque es conciso, funciona con ticks existentes generados automáticamente y ajusta los márgenes de trazado para que sea legible. Otros métodos permiten que los ticks salgan de la página, lo que requiere una acción adicional (como plt.tight_layouts ()) para ajustarlos.
EL_DON
En caso de que haya utilizado un localizador y formateador, el método "otro" podría romper su efecto si se aplica después.
languitar
73

Aquí hay muchas respuestas "correctas", pero agregaré una más ya que creo que algunos detalles quedan fuera de varios. El OP solicitó una rotación de 90 grados, pero cambiaré a 45 grados porque cuando usa un ángulo que no es cero o 90, también debe cambiar la alineación horizontal; de lo contrario, sus etiquetas estarán descentradas y serán un poco engañosas (y supongo que muchas personas que vienen aquí quieren rotar los ejes a algo que no sea 90).

Código más fácil / menos

Opción 1

plt.xticks(rotation=45, ha='right')

Como se mencionó anteriormente, eso puede no ser deseable si prefiere adoptar el enfoque orientado a objetos.

opcion 2

Otra forma rápida (está destinado a objetos de fecha pero parece funcionar en cualquier etiqueta; sin embargo, dudo que esto se recomiende):

fig.autofmt_xdate(rotation=45)

fig normalmente obtendrías de:

  • fig = plt.figure()
  • fig, ax = plt.subplots()
  • fig = ax.figure

Orientado a objetos / Tratar directamente con ax

Opcion 3a

Si tiene la lista de etiquetas:

labels = ['One', 'Two', 'Three']
ax.set_xticklabels(labels, rotation=45, ha='right')

Opción 3b

Si desea obtener la lista de etiquetas del diagrama actual:

# Unfortunately you need to draw your figure first to assign the labels,
# otherwise get_xticklabels() will return empty strings.
plt.draw()
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')

Opcion 4

Similar a lo anterior, pero en lugar de hacerlo manualmente.

for label in ax.get_xticklabels():
  label.set_rotation(45)
  label.set_ha('right')

Opción 5

Todavía usamos pyplot(como plt) aquí, pero está orientado a objetos porque estamos cambiando la propiedad de un axobjeto específico .

plt.setp(ax.get_xticklabels(), rotation=45, ha='right')

Opcion 6

Esta opción es simple, pero AFAIK no puede configurar la alineación horizontal de la etiqueta de esta manera, por lo que otra opción podría ser mejor si su ángulo no es 90.

ax.tick_params(axis='x', labelrotation=45)

Editar: Hay una discusión sobre este "error" exacto y una solución está potencialmente programada para v3.2.0: https://github.com/matplotlib/matplotlib/issues/13774

getup8
fuente
65

Prueba pyplot.setp. Creo que podrías hacer algo como esto:

x = range(len(time))
plt.xticks(x,  time)
locs, labels = plt.xticks()
plt.setp(labels, rotation=90)
plt.plot(x, delay)
opiethehokie
fuente
2
Traceback (most recent call last): File "plotter.py", line 23, in <module> plt.setp(time, rotation=90) File "/usr/lib64/python2.7/site-packages/matplotlib/pyplot.py", line 183, in setp ret = _setp(*args, **kwargs) File "/usr/lib64/python2.7/site-packages/matplotlib/artist.py", line 1199, in setp func = getattr(o, funcName) AttributeError: 'datetime.datetime' object has no attribute 'set_rotation'
tMC
Creo que me perdí un paso antes. ¿Ayuda el ejemplo editado? Sin embargo, estoy lejos de ser un experto en matplotlib, podría haber una mejor manera.
opiethehokie
1
Esto no parece funcionar en absoluto: la imagen (en mi máquina) se desordena completamente. líneas negras en toda la imagen de salida ... Casi parece un código de barras. Es muy extraño.
tMC
¿Qué versión de matplotlib fue esta? Con 1.2.0, setp(subplot(111).get_xticklabels(), rotation=90)funciona bien con el backend Qt4Agg. En mi caso, se restablece plt.hist(), así que lo llamo después, aunque plt.plot()no lo restablece, por lo que debería estar bien.
drevicko
1
@tMC Con mpl 1.2.0, copié su código (con algunos datos ficticios), lo agregué locs, labels = plt.xticks() plt.setp(labels, rotation=90)justo antes plt.plot(time, delay)y funcionó bien.
drevicko
54

Aparte de

plt.xticks(rotation=90)

Esto también es posible:

plt.xticks(rotation='vertical')
Mateo
fuente
Funciona, pero la altura de la trama tiene algún problema
Roberto Marzocchi
plt.xticks(rotation=45) plt.savefig(nomefile,dpi=150, optimize=True) plt.clf()
Roberto Marzocchi
49

Se me ocurrió un ejemplo similar. Nuevamente, la palabra clave de rotación es ... bueno, es clave.

from pylab import *
fig = figure()
ax = fig.add_subplot(111)
ax.bar( [0,1,2], [1,3,5] )
ax.set_xticks( [ 0.5, 1.5, 2.5 ] )
ax.set_xticklabels( ['tom','dick','harry'], rotation=45 ) ;
cjohnson318
fuente
Esto parece que funciona, pero muestra el tiempo en segundos desde la época-no la marca de tiempo dedatetime
tMC
32

Mi respuesta está inspirada en la respuesta de cjohnson318, pero no quería proporcionar una lista codificada de etiquetas; Quería rotar las etiquetas existentes:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Tommy
fuente
2
Esto ya no parece funcionar. No hay ningún efecto en absoluto.
zbyszek
31

Si usa plt:

plt.xticks(rotation=90)

En caso de utilizar pandas o nacidos para trazar, asumiendo axcomo ejes para la trama:

ax.set_xticklabels(ax.get_xticklabels(), rotation=90)

Otra forma de hacer lo anterior:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Gajapatía de Manavalan
fuente
Todos esos métodos ya se han mostrado en otras respuestas. ¿Qué es esta respuesta agregando aquí?
ImportanceOfBeingErnest
@ImportanceOfBeingErnest Está destinado a ayudar a aquellos que usan pandas o nacidos en el mar, y no directamente a matplotlib, para trazar.
Manavalan Gajapathy
for tick in ax.get_xticklabels(): tick.set_rotation(45)hizo el truco para mí
AP
30

Si desea aplicar rotación en el objeto de ejes, la forma más fácil es usarlo tick_params. Por ejemplo.

ax.tick_params(axis='x', labelrotation=90)

Referencia de documentación de Matplotlib aquí .

Esto es útil cuando tiene una matriz de ejes como los devueltos plt.subplots, y es más conveniente que usarlo set_xticksporque en ese caso también necesita establecer las etiquetas de marca, y también más conveniente que las que iteran sobre las marcas (por razones obvias)

Kiril
fuente
1
Además de eso, esta solución también funciona en la función de trazado del marco de datos de pandas, ya que también devuelve el objeto ejes. Mira aquí . Función bastante práctica. pd_dataframe.plot().tick_params(axis='x', labelrotation=90).
metinsenturk
El único problema con esto es que no puedo entender cómo alinear horizontalmente las etiquetas correctamente si uso algo como labelrotation=30.
getup8
8
import pylab as pl
pl.xticks(rotation = 90)
Ishan Tomar
fuente
3

Dependerá de lo que estés tramando.

import matplotlib.pyplot as plt

 x=['long_text_for_a_label_a',
    'long_text_for_a_label_b',
    'long_text_for_a_label_c']
y=[1,2,3]
myplot = plt.plot(x,y)
for item in myplot.axes.get_xticklabels():
    item.set_rotation(90)

Para los pandas y los nacidos en el mar que te dan un objeto Axes:

df = pd.DataFrame(x,y)
#pandas
myplot = df.plot.bar()
#seaborn 
myplotsns =sns.barplot(y='0',  x=df.index, data=df)
# you can get xticklabels without .axes cause the object are already a 
# isntance of it
for item in myplot.get_xticklabels():
    item.set_rotation(90)

Si necesita rotar etiquetas, es posible que también necesite cambiar el tamaño de fuente, puede font_scale=1.0hacerlo.

Isac Junior
fuente
2

Para rotar la etiqueta del eje x a 90 grados

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Mudit
fuente
Me gusta lo corta que es tu respuesta, pero lo que publicaste no es un código válido de Python. No me queda claro cómo interpretarlo como código válido de Python.
Dave C
1

La solución más simple es usar:

plt.xticks(rotation=XX)

pero también

# Tweak spacing to prevent clipping of tick-labels
plt.subplots_adjust(bottom=X.XX)

Por ejemplo, para las fechas, utilicé la rotación = 45 y la parte inferior = 0.20, pero puede hacer alguna prueba para sus datos

Roberto Marzocchi
fuente