Obróć tekst osi w python matplotlib

313

Nie mogę wymyślić, jak obrócić tekst na osi X. Jest to znacznik czasu, więc wraz ze wzrostem liczby próbek zbliżają się coraz bardziej, aż się pokrywają. Chciałbym obrócić tekst o 90 stopni, aby próbki nie zbliżały się do siebie, ponieważ zbliżają się do siebie.

Poniżej mam to, co działa, z tym wyjątkiem, że nie mogę wymyślić, jak obrócić tekst osi 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
źródło
3
Zobacz tę odpowiedź, aby uzyskać ważne informacje na temat wyrównywania obróconych etykiet za pomocą ha(wyrównanie w poziomie)
LondonRob

Odpowiedzi:

510

To działa dla mnie:

plt.xticks(rotation=90)
scottlittle
źródło
8
W przypadku, gdy ktokolwiek używa mpld3 i jest sfrustrowany, że żadne z tych rozwiązań nie działa. Rotacja nie jest obsługiwana w mpld3.
buraków
4
Dodatkowe punkty za ich utrzymanie pozostają wewnątrz figury / okna. Moje są w połowie na zewnątrz.
Gauthier,
1
Nazwij to po spiskowaniu. Czyli pierwszy ax.plot(...)potemplt.xticks(rotation=90)
CGFoX
161

Łatwy sposób

Jak opisano tutaj , istnieje matplotlib.pyplot figureklasa w klasie, która automatycznie obraca daty odpowiednio dla ciebie.

Możesz to nazwać po wykreśleniu swoich danych (tj . ax.plot(dates,ydata):

fig.autofmt_xdate()

Jeśli chcesz sformatować etykiety dalej, sprawdź powyższy link.

Obiekty inne niż data i godzina

Zgodnie languitar „s komentarz, metoda zasugerowałem dla non-datetime xticksnie aktualizuje poprawnie podczas powiększania, etc. Jeżeli nie jest to datetimeobiekt używany jako dane osi x, należy postępować Tommy ” s odpowiedź :

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
ryanjdillon
źródło
3
Jest to najlepszy sposób, ponieważ jest zwięzły, działa na istniejących automatycznie generowanych kleszczach i dostosowuje marginesy wydruku, aby był czytelny. Inne metody pozwalają paskom zejść ze strony, wymagając dalszych działań (takich jak plt.tight_layouts ()) w celu ich dostosowania.
EL_DON
W przypadku użycia lokalizatora i formatyzatora metoda „inna” może zepsuć efekt, jeśli zostanie zastosowana później.
languitar
73

Wiele „poprawnych” odpowiedzi tutaj, ale dodam jeszcze jedną, ponieważ uważam, że niektóre szczegóły zostały pominięte w kilku. OP poprosił o obrót o 90 stopni, ale zmienię na 45 stopni, ponieważ kiedy użyjesz kąta, który nie jest równy zero lub 90, powinieneś również zmienić wyrównanie w poziomie; w przeciwnym razie wasze etykiety będą niecentryczne i nieco mylące (i przypuszczam, że wiele osób, które tu przychodzą, chce obrócić osie do czegoś innego niż 90).

Najłatwiejszy / najmniejszy kod

opcja 1

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

Jak wspomniano wcześniej, może to nie być pożądane, jeśli wolisz podejście zorientowane obiektowo.

Opcja 2

Kolejny szybki sposób (przeznaczony dla obiektów daty, ale wydaje się, że działa na dowolnej etykiecie; wątpię jednak, by to było zalecane):

fig.autofmt_xdate(rotation=45)

fig zwykle otrzymujesz od:

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

Zorientowany obiektowo / Radzenie sobie bezpośrednio z ax

Opcja 3a

Jeśli masz listę etykiet:

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

Opcja 3b

Jeśli chcesz uzyskać listę etykiet z bieżącej działki:

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

Opcja 4

Podobne do powyższego, ale zamiast tego zapętlone ręcznie.

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

Opcja 5

Nadal używamy pyplot(as plt) tutaj, ale jest on zorientowany obiektowo, ponieważ zmieniamy właściwość określonego axobiektu.

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

Opcja 6

Ta opcja jest prosta, ale AFAIK nie można ustawić wyrównywania etykiety w poziomie w ten sposób, więc inna opcja może być lepsza, jeśli twój kąt nie wynosi 90.

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

Edycja: Dyskutowano na temat tego „błędu”, a potencjalna poprawka jest potencjalnie dostępna dla v3.2.0: https://github.com/matplotlib/matplotlib/issues/13774

getup8
źródło
65

Spróbuj pyplot.setp. Myślę, że możesz zrobić coś takiego:

x = range(len(time))
plt.xticks(x,  time)
locs, labels = plt.xticks()
plt.setp(labels, rotation=90)
plt.plot(x, delay)
opiethehokie
źródło
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
Myślę, że przegapiłem krok wcześniej. Czy edytowany przykład pomaga? Jednak daleko mi do eksperta od matplotlib, może być lepszy sposób.
opiethehokie
1
Wydaje się, że to w ogóle nie działa - obraz (na mojej maszynie) jest całkowicie pomieszany. czarne linie na całym obrazie wyjściowym ... Prawie wygląda jak kod kreskowy. to bardzo dziwne.
tMC
Która to wersja Matplotliba? W wersji 1.2.0 setp(subplot(111).get_xticklabels(), rotation=90)działa dobrze z backendem Qt4Agg. W moim przypadku zostanie zresetowany plt.hist(), więc nazywam go później, chociaż plt.plot()go nie resetuje, więc powinieneś być w porządku.
drevicko
1
@tMC Z mpl 1.2.0 skopiowałem twój kod (z niektórymi fikcyjnymi danymi), dodałem locs, labels = plt.xticks() plt.setp(labels, rotation=90)tuż przed plt.plot(time, delay)nim i działał dobrze.
drevicko
54

Oprócz

plt.xticks(rotation=90)

jest to również możliwe:

plt.xticks(rotation='vertical')
Mateusz
źródło
Działa, ale wysokość fabuły ma pewien problem
Roberto Marzocchi
plt.xticks(rotation=45) plt.savefig(nomefile,dpi=150, optimize=True) plt.clf()
Roberto Marzocchi
49

Wymyśliłem podobny przykład. Znów słowo kluczowe rotacji to… cóż, to klucz.

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
źródło
Wygląda na to, że działa, ale pokazuje czas w sekundach od epoki - nie znacznik czasu oddatetime
tMC
32

Moja odpowiedź jest zainspirowana odpowiedzią cjohnson318, ale nie chciałem podać zakodowanej listy etykiet; Chciałem obrócić istniejące etykiety:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Tommy
źródło
2
To już nie działa. Nie ma żadnego efektu.
zbyszek
31

Jeśli używasz plt:

plt.xticks(rotation=90)

W przypadku użycia pand lub dna morskiego do wykreślenia, przyjmując axza osie wykresu:

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

Inny sposób wykonania powyższego:

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Manavalan Gajapathy
źródło
Wszystkie te metody zostały już przedstawione w innych odpowiedziach. Co dodaje ta odpowiedź tutaj?
ImportanceOfBeingErnest
@ImportanceOfBeingErnest Ma to na celu pomóc osobom używającym pand lub dna morskiego, a nie bezpośrednio matplotlib, do kreślenia.
Manavalan Gajapathy
for tick in ax.get_xticklabels(): tick.set_rotation(45)zrobił dla mnie lewę.
AP
30

Jeśli chcesz zastosować obrót do obiektu osi, najłatwiej jest to zrobić tick_params. Na przykład.

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

Dokumentacja Matplotlib tutaj .

Jest to przydatne, gdy masz zestaw osi zwróconych przez plt.subplots, i jest to wygodniejsze niż używanie, set_xticksponieważ w takim przypadku musisz również ustawić etykiety znaczników, a także wygodniejsze niż te, które iterują się nad kleszczami (z oczywistych powodów)

kiril
źródło
1
Oprócz tego to rozwiązanie działa również w funkcji wykresu ramki danych pandy, ponieważ zwraca również obiekt osi. Sprawdź tutaj . Dość przydatna funkcja. pd_dataframe.plot().tick_params(axis='x', labelrotation=90).
metinsenturk
Jedynym problemem jest to, że nie mogę dowiedzieć się, jak prawidłowo wyrównać etykiety w poziomie, jeśli używam czegoś takiego labelrotation=30.
getup8
8
import pylab as pl
pl.xticks(rotation = 90)
Ishan Tomar
źródło
3

Będzie to zależeć od tego, co planujesz.

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)

W przypadku pand i dna morskiego, które dają ci obiekt 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)

Jeśli potrzebujesz obrócić etykiety, możesz także zmienić rozmiar czcionki, możesz font_scale=1.0to zrobić.

Isac Junior
źródło
2

Aby obrócić etykietę osi x o 90 stopni

for tick in ax.get_xticklabels():
    tick.set_rotation(45)
Mudit
źródło
Podoba mi się, jak krótka jest twoja odpowiedź, ale to, co napisałeś, nie jest poprawnym kodem Pythona. Nie jest dla mnie jasne, jak interpretować go jako prawidłowy kod Pythona.
Dave C
1

Najprostszym rozwiązaniem jest użycie:

plt.xticks(rotation=XX)

ale również

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

np. dla dat użyłem rotacji = 45 i dołu = 0,20, ale możesz wykonać test dla swoich danych

Roberto Marzocchi
źródło