2016-11-18 217 views
4

這是我試圖改變從矩形一個barplot傳說方:Matplotlib自定義圖例顯示正方形而不是矩形

import matplotlib.patches as patches 

rect1 = patches.Rectangle((0,0),1,1,facecolor='#FF605E') 
rect2 = patches.Rectangle((0,0),1,1,facecolor='#64B2DF') 
plt.legend((rect1, rect2), ('2016', '2015')) 

但是,當我繪製這個,我仍然看到矩形,而不是正方形:

enter image description here

我如何能做到這一點有什麼建議?


我試圖通過@ImportanceOfBeingErnest和@furas提供兩種解決方案,這裏的結果:

@ ImportanceOfBeingErnest的解決方案是最容易做的:

plt.rcParams['legend.handlelength'] = 1 
plt.rcParams['legend.handleheight'] = 1.125 

下面是結果:

enter image description here

我最後的代碼如下所示:

plt.legend((df.columns[1], df.columns[0]), handlelength=1, handleheight=1) # the df.columns = the legend text 

@ furas的解決方案產生這個,我不知道爲什麼文本是從矩形漸行漸遠,但我可以肯定的差距能以某種方式被改變:

enter image description here

+1

Concverning的最後一個點的位置:在解決方案從@furas它使用傳統的handler_map補丁改變是二次。然而,與矩形(因此更寬)的補丁相比,文本的填充保持不變。默認情況下,這個填充是'0.8',但你可以像使用'plt.rcParams ['legend.handletextpad'] = 0'這樣使用rcParams來設置它來減少間距。在這種情況下,你可能會設置一些負數,「-0.8」可能是不錯的選擇。 – ImportanceOfBeingErnest

回答

2

Matplotlib提供rcParams

legend.handlelength : 2. # the length of the legend lines in fraction of fontsize 
legend.handleheight : 0.7 # the height of the legend handle in fraction of fontsize 

你可以設置呼叫內plt.legend()

plt.legend(handlelength=1, handleheight=1)

或使用rcParams在腳本的開頭

import matplotlib 
matplotlib.rcParams['legend.handlelength'] = 1 
matplotlib.rcParams['legend.handleheight'] = 1 

不幸的是提供平等handlelength=1, handleheight=1不會給一個完美的rectange。看來handlelength=1, handleheight=1.125會完成這項工作,但這可能取決於正在使用的字體。


另一種方法是,如果要使用代理藝術家,可以使用plot/scatter方法中的方形標記。

bar1 = plt.plot([], marker="s", markersize=15, linestyle="", label="2015") 

並將其提供給圖例legend(handles=[bar1])。使用這種方法需要設置matplotlib.rcParams['legend.numpoints'] = 1,否則兩個標記將出現在圖例中。


下面是兩種方法

import matplotlib.pyplot as plt 
plt.rcParams['legend.handlelength'] = 1 
plt.rcParams['legend.handleheight'] = 1.125 
plt.rcParams['legend.numpoints'] = 1 


fig, ax = plt.subplots(ncols=2, figsize=(5,2.5)) 

# Method 1: Set the handlesizes already in the rcParams 
ax[0].set_title("Setting handlesize") 
ax[0].bar([0,2], [6,3], width=0.7, color="#a30e73", label="2015", align="center") 
ax[0].bar([1,3], [3,2], width=0.7, color="#0943a8", label="2016", align="center") 
ax[0].legend() 

# Method 2: use proxy markers. (Needs legend.numpoints to be 1) 
ax[1].set_title("Proxy markers") 
ax[1].bar([0,2], [6,3], width=0.7, color="#a30e73", align="center") 
ax[1].bar([1,3], [3,2], width=0.7, color="#0943a8", align="center") 
b1, =ax[1].plot([], marker="s", markersize=15, linestyle="", color="#a30e73", label="2015") 
b2, =ax[1].plot([], marker="s", markersize=15, linestyle="", color="#0943a8", label="2016") 
ax[1].legend(handles=[b1, b2]) 

[a.set_xticks([0,1,2,3]) for a in ax] 
plt.show() 

一個完整的例子生產

enter image description here

2

看來他們改變它很久以前的事 - 現在有些元素不能被直接使用在傳說中。

現在需要handlerImplementing a custom legend handler

import matplotlib.pyplot as plt 
import matplotlib.patches as patches 
from matplotlib.legend_handler import HandlerPatch 

# --- handlers --- 

class HandlerRect(HandlerPatch): 

    def create_artists(self, legend, orig_handle, 
         xdescent, ydescent, width, height, 
         fontsize, trans): 

     x = width//2 
     y = 0 
     w = h = 10 

     # create 
     p = patches.Rectangle(xy=(x, y), width=w, height=h) 

     # update with data from oryginal object 
     self.update_prop(p, orig_handle, legend) 

     # move xy to legend 
     p.set_transform(trans) 

     return [p] 


class HandlerCircle(HandlerPatch): 

    def create_artists(self, legend, orig_handle, 
         xdescent, ydescent, width, height, 
         fontsize, trans): 

     r = 5 
     x = r + width//2 
     y = height//2 

     # create 
     p = patches.Circle(xy=(x, y), radius=r) 

     # update with data from oryginal object 
     self.update_prop(p, orig_handle, legend) 

     # move xy to legend 
     p.set_transform(trans) 

     return [p] 

# --- main --- 

rect = patches.Rectangle((0,0), 1, 1, facecolor='#FF605E') 
circ = patches.Circle((0,0), 1, facecolor='#64B2DF') 

plt.legend((rect, circ), ('2016', '2015'), 
      handler_map={ 
       patches.Rectangle: HandlerRect(), 
       patches.Circle: HandlerCircle(), 
      }) 

plt.show() 

傳奇儲備到位矩形,此方法不改變它,有這麼多的空的空間。

enter image description here

+0

非常感謝您的解決方案。我試過了,請看原始帖子的更新 – Cheng

+1

@Cheng'legend'預留矩形的位置,這個方法不會改變這個地方 - 所以你可以看到差距 - 但你可以使用'xy =(width // 2 ,0)'移動suqare。順便說一句:這種方法可以讓你使用圓而不是suqare。 – furas