Фінікові кліщі та обертання в matplotlib


175

У мене виникає проблема, що намагається повернути мої кліщі на фінішну обробку в matplotlib. Нижче наведена невелика прикладна програма. Якщо я спробую обертати кліщі в кінці, кліщі не обертаються. Якщо я спробую обертати кліщі, як показано в коментарі "збої", тоді матбло вибивається.

Це відбувається лише в тому випадку, якщо значення x є датами. Якщо я замінюю змінну datesзмінною tу виклику до avail_plot, xticks(rotation=70)виклик всередині працює просто чудово avail_plot.

Будь-які ідеї?

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

def avail_plot(ax, x, y, label, lcolor):
    ax.plot(x,y,'b')
    ax.set_ylabel(label, rotation='horizontal', color=lcolor)
    ax.get_yaxis().set_ticks([])

    #crashes
    #plt.xticks(rotation=70)

    ax2 = ax.twinx()
    ax2.plot(x, [1 for a in y], 'b')
    ax2.get_yaxis().set_ticks([])
    ax2.set_ylabel('testing')

f, axs = plt.subplots(2, sharex=True, sharey=True)
t = np.arange(0.01, 5, 1)
s1 = np.exp(t)
start = dt.datetime.now()
dates=[]
for val in t:
    next_val = start + dt.timedelta(0,val)
    dates.append(next_val)
    start = next_val

avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')
plt.subplots_adjust(hspace=0, bottom=0.3)
plt.yticks([0.5,],("",""))
#doesn't crash, but does not rotate the xticks
#plt.xticks(rotation=70)
plt.show()

3
Створення сюжету з датами на осі x - це таке поширене завдання - прикро, що там немає більш повних прикладів.
alexw

Мені цікаво, чи це не дублікат stackoverflow.com/questions/10998621/…
ВажливістьOfBeingErnest

Відповіді:


249

Якщо ви віддаєте перевагу не об’єктно-орієнтованому підходу, перед двома дзвінками рухайтеся plt.xticks(rotation=70)праворуч , наприкладavail_plot

plt.xticks(rotation=70)
avail_plot(axs[0], dates, s1, 'testing', 'green')
avail_plot(axs[1], dates, s1, 'testing2', 'red')

Це встановлює властивість обертання перед встановленням міток. Оскільки у вас тут дві осі, plt.xticksплутайтесь після того, як ви зробили два сюжети. У той момент , коли plt.xticksнічого не робити, plt.gca()нічого НЕ дадуть вам осі , які ви хочете змінити, і так plt.xticks, що діє на поточних осях, не працюватиме.

Якщо не використовується об'єктно-орієнтований підхід plt.xticks, ви можете використовувати

plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )

після двох avail_plotдзвінків. Це спеціально встановлює обертання на правильних осях.


11
Ще одна зручна річ: під час дзвінка plt.setpви можете встановити кілька параметрів, вказавши їх як додаткові аргументи ключових слів. horizontalalignmentkwarg особливо корисно , коли ви повернете кліщ етикетку:plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70, horizontalalignment='right' )
8one6

32
Мені не подобається це рішення, оскільки воно змішує підходи «піплот» та об’єкт-орієнтовані. Ви можете просто зателефонувати ax.tick_params(axis='x', rotation=70)в будь-яке місце.
Тед Петру

3
@ TedPetrou Що ви маєте на увазі під "змішуванням" тут? plt.setpрозчин повністю об'єктно - орієнтованим. Якщо вам не подобається, що в ньому є щось plt, скористайтеся from matplotlib.artist import setp; setp(ax.get_xticklabels(), rotation=90)натомість.
ВажливістьOfBeingErnest

@ImportanceOfBeingErnest Перший рядок коду використовує, plt.xticksякий є pyplot. Сама документація говорить, що не змішувати стилі. plt.setpє більш багатослівним, але не типовим об'єктно-орієнтованим стилем. Ваша відповідь, безумовно, найкраща тут. В основному, що-небудь з функцією не орієнтоване на об'єкти. Не має значення, імпортуєте ви його setpчи ні.
Тед Петру

Значна частина коду запитання використовує pyplot, як yticks, а в коді зовсім не визначено сокиру за межами avail_plot...
cge

113

Рішення працює для matplotlib 2.1+

Існує метод осей, tick_paramsякий може змінювати властивості галочок. Він також існує як метод осі якset_tick_params

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

Або

ax.xaxis.set_tick_params(rotation=45)

Як бічна примітка, поточне рішення змішує стаціонарний інтерфейс (використовуючи pyplot) з об'єктно-орієнтованим інтерфейсом за допомогою команди plt.xticks(rotation=70). Оскільки код у запитанні використовує об'єктно-орієнтований підхід, найкраще дотримуватися цього підходу впродовж усього. Рішення дає хороше явне рішення зplt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )


Чи можна змінити обертання за замовчуванням для всіх ділянок? Я думаю, що мені потрібно змінити це на кожному зробленому сюжетом.
Чогг

42

Просте рішення, яке дозволяє уникнути перекидання на тикачів, - це просто використовувати

fig.autofmt_xdate()

Ця команда автоматично обертає мітки xaxis і регулює їх положення. Значеннями за замовчуванням є кут повороту на 30 ° та горизонтальне вирівнювання "праворуч". Але їх можна змінити у виклику функції

fig.autofmt_xdate(bottom=0.2, rotation=30, ha='right')

Додатковий bottomаргумент еквівалентний налаштуванню plt.subplots_adjust(bottom=bottom), що дозволяє встановити нижню вісь осей на більшу величину для розміщення повернутих галочок.

Тому в основному тут ви маєте всі налаштування, щоб мати гарну вісь дати в одній команді.

Хороший приклад можна знайти на сторінці Matplotlib.


Чудова відповідь! Дякую!
Абрамодж

чи можете ви керувати параметром 'rotation_mode' через цю функцію?
TheoryX

1
@TheoryX Ні. Якщо вам потрібен rotation_mode, вам потрібно або скористатися plt.setpпідходом, або перевести петлю на кліщі (що по суті те саме).
ВажливістьOfBeingErnest

Так, це просте рішення лише тоді, коли вісь x присутня внизу графіка. Однак, коли вісь x знаходиться у верхній частині графіка або при наявності двох осей x ( twinx), вона накручує вирівнювання між кліщами та мітками галочок. У цьому випадку рішення Теда Петру краще.
Śubham

@ Śubham Правильно. Це в основному ярлик до всіх інших рішень для найбільш поширеного випадку.
ВажливістьBeingErnest

18

Ще один спосіб застосувати horizontalalignmentі rotationдо кожної мітки - це forпетля над мітками, які ви хочете змінити:

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]
hours_value = np.random.random(len(hours))
days_value = np.random.random(len(days))

fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
axs[0].plot(hours,hours_value)
axs[1].plot(days,days_value)

for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
    label.set_rotation(30)
    label.set_horizontalalignment("right")

введіть тут опис зображення

Ось приклад, якщо ви хочете контролювати розташування основних і другорядних кліщів:

import numpy as np
import matplotlib.pyplot as plt
import datetime as dt

fig, axs = plt.subplots(2)
fig.subplots_adjust(hspace=0.75)
now = dt.datetime.now()
hours = [now + dt.timedelta(minutes=x) for x in range(0,24*60,10)]
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)]

axs[0].plot(hours,np.random.random(len(hours)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.HourLocator(byhour = range(0,25,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[0].xaxis.set_major_locator(x_major_lct)
axs[0].xaxis.set_minor_locator(x_minor_lct)
axs[0].xaxis.set_major_formatter(x_fmt)
axs[0].set_xlabel("minor ticks set to every hour, major ticks start with 00:00")

axs[1].plot(days,np.random.random(len(days)))
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True)
x_minor_lct = matplotlib.dates.DayLocator(bymonthday = range(0,32,1))
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct)
axs[1].xaxis.set_major_locator(x_major_lct)
axs[1].xaxis.set_minor_locator(x_minor_lct)
axs[1].xaxis.set_major_formatter(x_fmt)
axs[1].set_xlabel("minor ticks set to every day, major ticks show first day of month")
for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels():
    label.set_rotation(30)
    label.set_horizontalalignment("right")

введіть тут опис зображення


1
Це працювало для мене на matplotlib v1.5.1 (я застряг у застарілій версії matplotlib на роботі, не питай, чому)
Едді,

Я щойно тестував python3.6 та matplotlib v2.2.2, і він теж працює.
Пабло Рейєс

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.