Ruota il testo dell'asse in matplotlib in pitone


314

Non riesco a capire come ruotare il testo sull'asse X. È un timestamp, quindi quando il numero di campioni aumenta, si avvicinano sempre di più fino a quando non si sovrappongono. Vorrei ruotare il testo di 90 gradi in modo che i campioni si avvicinino, non si sovrappongano.

Di seguito è quello che ho, funziona benissimo con l'eccezione che non riesco a capire come ruotare il testo dell'asse 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')

3
Vedi questa risposta per informazioni importanti sull'allineamento delle etichette ruotate con ha(allineamento orizzontale)
Londra,

Risposte:


513

Questo funziona per me:

plt.xticks(rotation=90)

8
Nel caso in cui qualcun altro stia usando mpld3 ed è frustrato dal fatto che nessuna di queste soluzioni funzioni. La rotazione non è supportata in mpld3.
Beetree,

4
Punti extra per farli rimanere all'interno della figura / finestra. I miei sono metà fuori.
Gauthier,

1
Chiamalo dopo aver tracciato. Cioè, prima ax.plot(...)poiplt.xticks(rotation=90)
CGFoX

161

Modo semplice

Come descritto qui , esiste un metodo esistente nella matplotlib.pyplot figureclasse che ruota automaticamente le date in modo appropriato per la tua figura.

Puoi chiamarlo dopo aver tracciato i tuoi dati (ad esempio ax.plot(dates,ydata):

fig.autofmt_xdate()

Se hai bisogno di formattare ulteriormente le etichette, controlla il link sopra.

Oggetti non datetime

Come da commento di languitar , il metodo che ho suggerito per il non datetime xticksnon si aggiorna correttamente durante lo zoom, ecc. Se non è un datetimeoggetto usato come dati dell'asse x, dovresti seguire la risposta di Tommy :

for tick in ax.get_xticklabels():
    tick.set_rotation(45)

3
Questo è il modo migliore perché è conciso, opera su tick generati automaticamente esistenti e regola i margini della trama in modo che sia leggibile. Altri metodi consentono alle zecche di uscire dalla pagina, richiedendo ulteriori azioni (come plt.tight_layouts ()) per modificarle.
EL_DON

Nel caso in cui sia stato utilizzato un localizzatore e un formatter, il metodo "altro" potrebbe interromperne l'effetto se applicato successivamente.
languitar

73

Molte risposte "corrette" qui, ma ne aggiungerò un'altra poiché ritengo che alcuni dettagli siano lasciati fuori da molti. L'OP ha richiesto una rotazione di 90 gradi, ma cambierò a 45 gradi perché quando si utilizza un angolo diverso da zero o 90, è necessario modificare anche l'allineamento orizzontale; altrimenti le tue etichette saranno decentrate e un po 'fuorvianti (e sto indovinando molte persone che vengono qui vogliono ruotare gli assi su qualcosa di diverso da 90).

Il codice più semplice / minimo

opzione 1

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

Come accennato in precedenza, ciò potrebbe non essere desiderabile se si preferisce adottare l'approccio orientato agli oggetti.

opzione 2

Un altro modo rapido (è destinato agli oggetti data ma sembra funzionare su qualsiasi etichetta; dubiti che questo sia raccomandato comunque):

fig.autofmt_xdate(rotation=45)

fig di solito si ottiene da:

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

Orientato agli oggetti / trattare direttamente con ax

Opzione 3a

Se hai l'elenco di etichette:

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

Opzione 3b

Se vuoi ottenere l'elenco delle etichette dalla trama corrente:

# 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')

Opzione 4

Simile a sopra, ma invece scorrere manualmente.

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

Opzione 5

Usiamo ancora pyplot(as plt) qui ma è orientato agli oggetti perché stiamo cambiando la proprietà di un axoggetto specifico .

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

Opzione 6

Questa opzione è semplice, ma AFAIK non è possibile impostare l'allineamento orizzontale dell'etichetta in questo modo, quindi un'altra opzione potrebbe essere migliore se l'angolo non è 90.

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

Modifica: si parla di questo "bug" esatto e una correzione è potenzialmente prevista per v3.2.0: https://github.com/matplotlib/matplotlib/issues/13774


65

Prova pyplot.setp. Penso che potresti fare qualcosa del genere:

x = range(len(time))
plt.xticks(x,  time)
locs, labels = plt.xticks()
plt.setp(labels, rotation=90)
plt.plot(x, delay)

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

Penso di aver perso un passo prima. L'esempio modificato aiuta? Sono tutt'altro che un esperto di matplotlib, potrebbe esserci un modo migliore.
opiethehokie,

1
Questo non sembra funzionare affatto. L'immagine (sulla mia macchina) viene completamente incasinata. linee nere su tutta l'immagine di output ... Sembra quasi un codice a barre. è molto strano.
tMC

Quale versione di matplotlib era questa? Con 1.2.0, setp(subplot(111).get_xticklabels(), rotation=90)funziona perfettamente con il backend Qt4Agg. Nel mio caso, viene ripristinato da plt.hist(), quindi lo chiamo dopo, anche se plt.plot()non lo ripristina, quindi dovresti essere a posto.
drevicko,

1
@tMC Con mpl 1.2.0, ho copiato il tuo codice (con alcuni dati fittizi), aggiunto locs, labels = plt.xticks() plt.setp(labels, rotation=90)poco prima plt.plot(time, delay)e ha funzionato bene.
drevicko,

54

Appart da

plt.xticks(rotation=90)

questo è anche possibile:

plt.xticks(rotation='vertical')

Funziona, ma l'altezza della trama ha qualche problema
Roberto Marzocchi

plt.xticks(rotation=45) plt.savefig(nomefile,dpi=150, optimize=True) plt.clf()
Roberto Marzocchi,

49

Ho trovato un esempio simile. Ancora una volta, la parola chiave di rotazione è ... beh, è ​​la chiave.

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

Sembra che funzioni, ma mostra il tempo in secondi dall'epoca- non il timestamp dadatetime
tMC

32

La mia risposta è ispirata dalla risposta di cjohnson318, ma non volevo fornire un elenco di etichette codificate; Volevo ruotare le etichette esistenti:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)

2
Questo non sembra funzionare più. Non c'è alcun effetto.
zbyszek,

31

Se si utilizza plt:

plt.xticks(rotation=90)

In caso di utilizzo di Panda o Seaborn per la trama, assumendo axcome assi per la trama:

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

Un altro modo di fare quanto sopra:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)

Tutti questi metodi sono già stati mostrati in altre risposte. Cosa aggiunge questa risposta qui?
ImportanceOfBeingErnest

@ImportanceOfBeingErnest È pensato per aiutare coloro che usano i panda o i nati marini, e non direttamente matplotlib, per la stampa.
Manavalan Gajapathy

for tick in ax.get_xticklabels(): tick.set_rotation(45)ha fatto il trucco per me.
AP

30

Se si desidera applicare la rotazione sull'oggetto degli assi, si sta utilizzando il modo più semplice tick_params. Per esempio.

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

Riferimento della documentazione di Matplotlib qui .

Ciò è utile quando si ha una matrice di assi restituiti da plt.subplots, ed è più conveniente dell'uso set_xticksperché in quel caso è necessario impostare anche le etichette dei tick e anche più conveniente di quelli che si ripetono sui tick (per ovvi motivi)


1
Oltre a ciò, questa soluzione funziona anche nella funzione di stampa di Panda Dataframe poiché restituisce anche gli oggetti degli assi. Controllare qui . Funzione abbastanza utile. pd_dataframe.plot().tick_params(axis='x', labelrotation=90).
metinsenturk,

L'unico problema con questo è che non riesco a capire come allineare orizzontalmente correttamente le etichette se uso qualcosa di simile labelrotation=30.
getup8


3

Dipenderà da cosa stai 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)

Per i panda e i nati marini che ti danno un oggetto 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)

Se è necessario ruotare le etichette, potrebbe essere necessario modificare anche la dimensione del carattere, è possibile utilizzare font_scale=1.0per farlo.


2

Per ruotare l'etichetta dell'asse x di 90 gradi

for tick in ax.get_xticklabels():
    tick.set_rotation(45)

Mi piace quanto sia breve la tua risposta, ma ciò che hai pubblicato non è un codice Python valido. Non mi è chiaro come interpretarlo come codice Python valido.
Dave C

1

La soluzione più semplice è usare:

plt.xticks(rotation=XX)

ma anche

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

ad es. per le date in cui ho usato la rotazione = 45 e il fondo = 0,20 ma puoi fare dei test per i tuoi dati

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.