2015-08-14 27 views
10

Có ai đó có thể biết nếu có thể xoay một chú thích trên một ô trong matplotlib? Tôi đã thực hiện một âm mưu đơn giản với đoạn mã dưới đây, và chỉnh sửa đồ thị trong sơn để hiển thị những gì tôi muốn.Xoay vòng quay huyền thoại Matplotlib

plt.plot([4,5,6], label = 'test') 
ax = plt.gca() 
ax.legend() 
plt.show() 

http://www.abraham.dreamhosters.com/Capture.PNG

+4

Có một câu hỏi về danh sách matplotlib gửi thư, và câu trả lời là không thể với hiện tại (2009) thực hiện của huyền thoại (https://www.mail-archive.com/[email protected]/msg10474.html). Tôi đã không bao giờ gặp phải một lựa chọn như vậy trong khi sử dụng các phiên bản matplotlib gần đây, có lẽ nó vẫn không thể. –

+0

Cảm ơn Chris - Tôi đã tìm thấy cùng một chuỗi và nên bao gồm điều này trong bài đăng gốc của tôi. –

Trả lời

1

tôi đã dành một vài giờ làm bại hoại này ngày hôm qua, và làm một chút về sự tiến bộ vì vậy tôi sẽ chia sẻ dưới đây cùng với một số gợi ý di chuyển về phía trước.

Đầu tiên, có vẻ như chúng ta chắc chắn có thể xoay và dịch hộp giới hạn (bbox) hoặc khung xung quanh chú giải. Trong ví dụ đầu tiên dưới đây bạn có thể thấy rằng một transform có thể được áp dụng, mặc dù yêu cầu một số số bản dịch lớn kỳ lạ sau khi áp dụng xoay 90 độ. Tuy nhiên, thực sự có vấn đề trong việc lưu khung chú giải đã dịch vào một tệp hình ảnh vì vậy tôi phải chụp ảnh màn hình từ sổ ghi chép IPython. Tôi cũng đã thêm một số nhận xét.

import matplotlib.pyplot as plt 
%matplotlib inline 
import numpy as np 
import matplotlib.transforms 

fig = plt.figure() 
ax = fig.add_subplot('121') #make room for second subplot, where we are actually placing the legend 
ax2 = fig.add_subplot('122') #blank subplot to make space for legend 
ax2.axis('off') 
ax.plot([4,5,6], label = 'test') 

transform = matplotlib.transforms.Affine2D(matrix=np.eye(3)) #start with the identity transform, which does nothing 
transform.rotate_deg(90) #add the desired 90 degree rotation 
transform.translate(410,11) #for some reason we need to play with some pretty extreme translation values to position the rotated legend 

legend = ax.legend(bbox_to_anchor=[1.5,1.0]) 
legend.set_title('test title') 
legend.get_frame().set_transform(transform) #This actually works! But, only for the frame of the legend (see below) 
frame = legend.get_frame() 
fig.subplots_adjust(wspace = 0.4, right = 0.9) 
fig.savefig('rotate_legend_1.png',bbox_extra_artists=(legend,frame),bbox_inches='tight', dpi = 300) #even with the extra bbox parameters the legend frame is still getting clipped 

enter image description here

Tiếp theo, tôi nghĩ rằng nó sẽ được thông minh để khám phá những get_methods() các linh kiện truyền thuyết khác. Bạn có thể phân loại thông qua những điều này với dir(legend)legend.__dict__ v.v. Đặc biệt, tôi nhận thấy rằng bạn có thể làm điều này: legend.get_title().set_transform(transform), điều này dường như ngụ ý rằng chúng tôi có thể dịch văn bản chú giải (và không chỉ là khung như trên). Chúng ta hãy xem những gì sẽ xảy ra khi tôi đã cố gắng rằng:

tiêu đề
fig2 = plt.figure() 
ax = fig2.add_subplot('121') 
ax2 = fig2.add_subplot('122') 
ax2.axis('off') 
ax.plot([4,5,6], label = 'test') 

transform = matplotlib.transforms.Affine2D(matrix=np.eye(3)) 
transform.rotate_deg(90) 
transform.translate(410,11) 

legend = ax.legend(bbox_to_anchor=[1.5,1.0]) 
legend.set_title('test title') 
legend.get_frame().set_transform(transform) 
legend.get_title().set_transform(transform) #one would expect this to apply the same transformation to the title text in the legend, rotating it 90 degrees and translating it 

frame = legend.get_frame() 
fig2.subplots_adjust(wspace = 0.4, right = 0.9) 
fig2.savefig('rotate_legend_1.png',bbox_extra_artists=(legend,frame),bbox_inches='tight', dpi = 300) 

enter image description here

Truyền thuyết dường như đã biến mất trong ảnh chụp màn hình từ máy tính xách tay IPython. Nhưng, nếu chúng ta nhìn vào các tập tin lưu danh hiệu huyền thoại tại là ở góc dưới bên trái và dường như đã bỏ qua các thành phần quay của sự biến đổi (tại sao?):

enter image description here

Tôi có trục trặc kỹ thuật tương tự với loại này của phương pháp:

bbox = matplotlib.transforms.Bbox([[0.,1],[1,1]]) 
trans_bbox = matplotlib.transforms.TransformedBbox(bbox, transform) 
legend.set_bbox_to_anchor(trans_bbox) 

ghi chú và lời đề nghị khác:

  1. Nó có thể là một ý tưởng hợp lý để thâm nhập vào sự khác biệt trong hành vi được tween tiêu đề chú giải và đối tượng khung - tại sao cả hai đều chấp nhận biến đổi, nhưng chỉ khung chấp nhận một vòng quay? Có lẽ nó sẽ có thể phân lớp đối tượng chú giải trong mã nguồn và thực hiện một số điều chỉnh.
  2. Chúng tôi cũng cần tìm giải pháp cho khung chú giải được chuyển đổi/dịch không được lưu vào đầu ra, ngay cả sau khi thực hiện theo các đề xuất liên quan khác nhau về SO (tức là, Matplotlib savefig with a legend outside the plot).
+0

Cảm ơn bạn đã khám phá điều này! –

1

Tôi đã đi đến một vấn đề tương tự và giải quyết nó bằng cách viết hàm legendAsLatex tạo mã latex được sử dụng làm nhãn của trục y. Hàm thu thập màu, điểm đánh dấu, kiểu đường kẻ và nhãn được cung cấp cho hàm lô. Nó đòi hỏi phải cho phép latex và tải các gói cần thiết. Đây là mã để tạo ra cốt truyện của bạn với các đường cong phụ sử dụng cả hai trục thẳng đứng.

from matplotlib import pyplot as plt 
import matplotlib.colors as cor 

plt.rc('text', usetex=True) 
plt.rc('text.latex', preamble=r'\usepackage{amsmath} \usepackage{wasysym}'+ 
    r'\usepackage[dvipsnames]{xcolor} \usepackage{MnSymbol} \usepackage{txfonts}') 

def legendAsLatex(axes, rotation=90) : 
    '''Generate a latex code to be used instead of the legend. 
     Uses the label, color, marker and linestyle provided to the pyplot.plot. 
     The marker and the linestyle must be defined using the one or two character 
      abreviations shown in the help of pyplot.plot. 
     Rotation of the markers must be multiple of 90. 
    ''' 
    latexLine = {'-':'\\textbf{\Large ---}', 
     '-.':'\\textbf{\Large --\:\!$\\boldsymbol{\cdot}$\:\!--}', 
     '--':'\\textbf{\Large --\,--}',':':'\\textbf{\Large -\:\!-}'} 
    latexSymbol = {'o':'medbullet', 'd':'diamond', 's':'filledmedsquare', 
     'D':'Diamondblack', '*':'bigstar', '+':'boldsymbol{\plus}', 
     'x':'boldsymbol{\\times}', 'p':'pentagon', 'h':'hexagon', 
     ',':'boldsymbol{\cdot}', '_':'boldsymbol{\minus}','<':'LHD', 
     '>':'RHD','v':'blacktriangledown', '^':'blacktriangle'} 
    rot90=['^','<','v','>'] 
    di = [0,-1,2,1][rotation%360//90] 
    latexSymbol.update({rot90[i]:latexSymbol[rot90[(i+di)%4]] for i in range(4)}) 
    return ', '.join(['\\textcolor[rgb]{'\ 
      + ','.join([str(x) for x in cor.to_rgb(handle.get_color())]) +'}{' 
      + '$\\'+latexSymbol.get(handle.get_marker(),';')+'$' 
      + latexLine.get(handle.get_linestyle(),'') + '} ' + label 
       for handle,label in zip(*axes.get_legend_handles_labels())]) 

ax = plt.axes() 
ax.plot(range(0,10), 'b-', label = 'Blue line') 
ax.plot(range(10,0,-1), 'sm', label = 'Magenta squares') 
ax.set_ylabel(legendAsLatex(ax)) 

ax2 = plt.twinx() 
ax2.plot([x**0.5 for x in range(0,10)], 'ro', label = 'Red circles') 
ax2.plot([x**0.5 for x in range(10,0,-1)],'g--', label = 'Green dashed line') 
ax2.set_ylabel(legendAsLatex(ax2)) 

plt.savefig('legend.eps') 

plt.close() 

hình được tạo ra bởi các mã:

enter image description here

+0

Điều này thật tuyệt vời. Tôi đã sử dụng một đoạn mã tương tự nhưng ít phổ biến hơn cho các số liệu của mình. Tôi sẽ kết hợp một số ý tưởng của bạn vào chức năng của tôi. –

+0

Cảm ơn bạn, @MadPhysicist. Bạn có thể muốn kiểm tra phiên bản tôi vừa tải lên. Nó đơn giản hơn, giao dịch chính xác với màu sắc và chấp nhận nhiều góc quay hơn. – bmello

+0

Không chắc chắn nếu nó quan trọng, nhưng bạn có thể 'rot90' thành một dict keyed bởi' rotation% 360' thay vì đi qua con quái vật đó 'if'. –

Các vấn đề liên quan