Đánh dấu ngày và xoay trong matplotlib


175

Tôi đang gặp vấn đề khi cố gắng để đánh dấu ngày của tôi được xoay trong matplotlib. Một chương trình mẫu nhỏ dưới đây. Nếu tôi cố gắng xoay bọ ve ở cuối, bọ ve sẽ không bị xoay. Nếu tôi cố gắng xoay các dấu tick như được hiển thị dưới nhận xét 'sự cố', thì matplot lib gặp sự cố.

Điều này chỉ xảy ra nếu giá trị x là ngày. Nếu tôi thay thế biến datesbằng biến ttrong cuộc gọi đến avail_plot, xticks(rotation=70)cuộc gọi sẽ hoạt động tốt bên trong avail_plot.

Có ý kiến ​​gì không?

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
Tạo một cốt truyện có ngày trên trục x là một nhiệm vụ phổ biến như vậy - thật xấu hổ khi không có ví dụ đầy đủ hơn ngoài kia.
alexw 13/03/2016

Tôi tự hỏi liệu đây có phải là bản sao của stackoverflow.com/questions/10998621/ không
ImportanceOfByingErnest

Câu trả lời:


249

Nếu bạn thích cách tiếp cận không hướng đối tượng, hãy di chuyển plt.xticks(rotation=70)sang phải trước hai avail_plotcuộc gọi, ví dụ:

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

Điều này đặt thuộc tính xoay trước khi thiết lập nhãn. Vì bạn có hai trục ở đây, plt.xticksbị lẫn lộn sau khi bạn thực hiện hai ô. Tại thời điểm khi plt.xtickskhông làm gì cả, plt.gca()không không cung cấp cho bạn các trục bạn muốn thay đổi, và vì vậy plt.xticks, hoạt động trên các trục hiện tại, sẽ không làm việc.

Đối với cách tiếp cận hướng đối tượng không sử dụng plt.xticks, bạn có thể sử dụng

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

sau hai avail_plotcuộc gọi. Điều này đặt xoay trên các trục chính xác cụ thể.


11
Một điều tiện dụng khác: khi bạn gọi, plt.setpbạn có thể đặt nhiều tham số bằng cách chỉ định chúng làm đối số từ khóa bổ sung. các horizontalalignmentkwarg đặc biệt hữu ích khi bạn xoay nhãn đánh dấu:plt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70, horizontalalignment='right' )
8one6

31
Tôi không thích giải pháp này vì nó pha trộn các phương pháp pyplot và hướng đối tượng. Bạn chỉ có thể gọi ax.tick_params(axis='x', rotation=70)ở bất cứ nơi nào.
Ted Petrou

3
@TedPetrou Ý bạn là gì khi "trộn" ở đây? các plt.setpgiải pháp là hoàn toàn hướng đối tượng. Nếu bạn không thích thực tế là có một số plttrong đó, hãy sử dụng from matplotlib.artist import setp; setp(ax.get_xticklabels(), rotation=90)thay thế.
ImportanceOfByingErnest

@ImportanceOfByingErnest Dòng mã đầu tiên sử dụng plt.xtickslà pyplot. Các tài liệu chính nó nói không trộn phong cách. plt.setpdài dòng hơn nhưng cũng không phải là phong cách hướng đối tượng điển hình. Câu trả lời của bạn chắc chắn là tốt nhất ở đây. Về cơ bản, bất cứ thứ gì có chức năng đều không hướng đối tượng. Không quan trọng bạn có nhập setphay không.
Ted Petrou

Phần lớn mã của câu hỏi sử dụng pyplot, như yticks, và mã không có rìu được xác định ở bên ngoài avail_plot...
cge

113

Giải pháp hoạt động cho matplotlib 2.1+

Có tồn tại một phương thức trục tick_paramscó thể thay đổi thuộc tính đánh dấu. Nó cũng tồn tại như một phương thức trục nhưset_tick_params

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

Hoặc là

ax.xaxis.set_tick_params(rotation=45)

Là một lưu ý phụ, giải pháp hiện tại trộn giao diện trạng thái (sử dụng pyplot) với giao diện hướng đối tượng bằng cách sử dụng lệnh plt.xticks(rotation=70). Vì mã trong câu hỏi sử dụng cách tiếp cận hướng đối tượng, tốt nhất nên tuân theo cách tiếp cận đó xuyên suốt. Các giải pháp cho một giải pháp rõ ràng tốt vớiplt.setp( axs[1].xaxis.get_majorticklabels(), rotation=70 )


Có thể thay đổi vòng quay mặc định cho tất cả các ô không? Tôi nghĩ rằng tôi cần thay đổi điều này trên mỗi cốt truyện tôi thực hiện.
Chogg

42

Một giải pháp dễ dàng tránh vòng lặp trên ticklabes là chỉ sử dụng

fig.autofmt_xdate()

Lệnh này tự động xoay nhãn xaxis và điều chỉnh vị trí của chúng. Các giá trị mặc định là góc xoay 30 ° và căn chỉnh ngang "bên phải". Nhưng chúng có thể được thay đổi trong lệnh gọi hàm

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

Đối bottomsố bổ sung tương đương với cài đặt plt.subplots_adjust(bottom=bottom), cho phép đặt phần đệm trục dưới cùng thành giá trị lớn hơn để lưu trữ các ticklabels được xoay.

Vì vậy, về cơ bản ở đây bạn có tất cả các cài đặt bạn cần để có một trục ngày đẹp trong một lệnh.

Một ví dụ tốt có thể được tìm thấy trên trang matplotlib.


Câu trả lời chính xác! Cảm ơn!
Abramodj

bạn có thể điều khiển tham số 'rotation_mode' thông qua chức năng này không?
TheoryX

1
@TheoryX Không. Nếu bạn cần rotation_mode, bạn cần sử dụng plt.setpcách tiếp cận hoặc lặp lại các dấu tick (về cơ bản là giống nhau).
ImportanceOfByingErnest

Có, đó là một giải pháp dễ dàng chỉ khi trục x xuất hiện ở dưới cùng của biểu đồ. Tuy nhiên, khi trục x ở trên cùng của biểu đồ hoặc khi có hai trục x ( twinx), nó sẽ điều chỉnh sự liên kết giữa các dấu tick và nhãn tick. Trong trường hợp đó, giải pháp của Ted Petrou là tốt hơn.
Śubham

@ Ubham Đúng. Đây chủ yếu là một phím tắt cho tất cả các giải pháp khác cho trường hợp phổ biến nhất.
ImportanceOfByingErnest

18

Một cách khác để áp dụng horizontalalignmentrotationcho mỗi nhãn đánh dấu là thực hiện một forvòng lặp trên nhãn đánh dấu bạn muốn thay đổi:

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

nhập mô tả hình ảnh ở đây

Và đây là một ví dụ nếu bạn muốn kiểm soát vị trí của bọ ve lớn và nhỏ:

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

nhập mô tả hình ảnh ở đây


1
Điều này làm việc cho tôi trên matplotlib v1.5.1 (Tôi bị mắc kẹt trên phiên bản kế thừa của matplotlib tại nơi làm việc, đừng hỏi tại sao)
Eddy

Tôi vừa thử nghiệm với python3.6 và matplotlib v2.2.2 và nó cũng hoạt động.
Pablo Reyes

2

Đơn giản chỉ cần sử dụng

ax.set_xticklabels(label_list, rotation=45)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.