2013-10-19 2 views
1

this example과 비슷한 matplotlib 오류 막대 플롯의 범례 선택 도구를 코딩하려고합니다. 전설에서 errorbars/datapoints를 클릭하여 축에서의 가시성을 토글 할 수 있기를 원합니다. 문제는 plt.legend()에 의해 반환 된 범례 개체에 범례 만들기에 사용 된 아티스트에 대한 데이터가 포함되어 있지 않다는 것입니다. 예를 들면. 수행가 leg 개체를 사용하여 전설의 아티스트에 액세스하는 것은 불가능 보인다python matplotlib 오류 표시 범례 선택

import numpy as np 
import matplotlib.pyplot as plt 

fig, ax = plt.subplots() 
x = np.linspace(0,10,100) 
y = np.sin(x) + np.random.rand(100) 
yerr = np.random.rand(100) 

erbpl1 = ax.errorbar(x, y, yerr=yerr, fmt='o', label='A') 
erbpl2 = ax.errorbar(x, 0.02*y, yerr=yerr, fmt='o', label='B') 

leg = ax.legend() 

여기에서. 일반적으로 간단한 전설을 사용하면 다음과 같이 할 수 있습니다.

plt.plot(x, y, label='whatever') 
leg = plt.legend() 
proxy_lines = leg.get_lines() 

은 범례에 사용 된 Line2D 객체를 제공합니다. 그러나 오류 막대 플롯의 경우 leg.get_lines()은 빈 목록을 반환합니다. plt.errorbarmatplotlib.container.ErrorbarContainer 개체 (데이터 요소, 오류 막대 엔드 캡, 오류 막대 줄 포함)를 반환하기 때문에 이러한 종류의 의미가 있습니다. 나는 전설에 비슷한 데이터 컨테이너가있을 것으로 기대하지만, 나는 이것을 볼 수 없다. 가장 가까운 것은 leg.legendHandles으로 오류 막대 라인을 가리키고 데이터 포인트 나 엔드 캡은 가리키지 않습니다. 범례를 선택할 수있는 경우 사전을 사용하여 원래의 플롯에 매핑하고 다음 기능을 사용하여 오류 막대를 설정/해제 할 수 있습니다.

def toggle_errorbars(erb_pl): 
    points, caps, bars = erb_pl 
    vis = bars[0].get_visible() 
    for line in caps: 
     line.set_visible(not vis) 
    for bar in bars: 
     bar.set_visible(not vis) 
    return vis 

def onpick(event): 
    # on the pick event, find the orig line corresponding to the 
    # legend proxy line, and toggle the visibility 
    legline = event.artist 
    origline = lined[legline] 

    vis = toggle_errorbars(origline) 
    ## Change the alpha on the line in the legend so we can see what lines 
    ## have been toggled 
    if vis: 
     legline.set_alpha(.2) 
    else: 
     legline.set_alpha(1.) 
    fig.canvas.draw() 

제 질문은 오류 모음/다른 복잡한 범례에서 이벤트 선택을 할 수있는 해결 방법이 있습니까 ??

+0

어떤 matplotlib 버전을 사용하고 있습니까? 이것은 내 컴퓨터에서 예상대로 작동합니다 (현재 마스터에 매우 가깝습니다). – tacaswell

+0

matplotlib 1.3.0 – astroMonkey

+0

nm과 함께 python 3.2를 사용하고 있습니다. 너무 빠르게 읽었습니다. 명료하게 말하자면, 당신은 전설 속에서 예술가를 얻지 만, 이제는 그것을 골라 내고자합니다. 보일러 플레이트뿐만 아니라 실제 문제를 나타내는 코드를 포함해야합니다. – tacaswell

답변

1

이 마커가 pickable 수 :

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.legend_handler 

from matplotlib.container import ErrorbarContainer 

class re_order_errorbarHandler(matplotlib.legend_handler.HandlerErrorbar): 
    """ 
    Sub-class the standard error-bar handler 
    """ 
    def create_artists(self, *args, **kwargs): 
     # call the parent class function 
     a_list = matplotlib.legend_handler.HandlerErrorbar.create_artists(self, *args, **kwargs) 
     # re-order the artist list, only the first artist is added to the 
     # legend artist list, this is the one that corresponds to the markers 
     a_list = a_list[-1:] + a_list[:-1] 
     return a_list 

my_handler_map = {ErrorbarContainer: re_order_errorbarHandler(numpoints=2)} 

fig, ax = plt.subplots() 
x = np.linspace(0,10,100) 
y = np.sin(x) + np.random.rand(100) 
yerr = np.random.rand(100) 

erbpl1 = ax.errorbar(x, y, yerr=yerr, fmt='o', label='A') 
erbpl2 = ax.errorbar(x, 0.02*y, yerr=yerr, fmt='o', label='B') 

leg = ax.legend(handler_map=my_handler_map) 

lines = [erbpl1, erbpl2] 
lined = dict() 
# not strictly sure about ordering, but 
for legline, origline in zip(leg.legendHandles, lines): 
    legline.set_picker(5) # 5 pts tolerance 
    lined[legline] = origline 


def onpick(event): 
    # on the pick event, find the orig line corresponding to the 
    # legend proxy line, and toggle the visibility 
    legline = event.artist 
    origline = lined[legline] 
    for a in origline.get_children(): 
     vis = not a.get_visible() 
     a.set_visible(vis) 
    # Change the alpha on the line in the legend so we can see what lines 
    # have been toggled 
    if vis: 
     legline.set_alpha(1.0) 
    else: 
     legline.set_alpha(0.2) 
    fig.canvas.draw() 

fig.canvas.mpl_connect('pick_event', onpick) 

여기에서 일어나고있는 것은 ErrorbarContainers의 표준 핸들러가 연결 범례 항목 (바용 LineCollection, 모자에 대한 LineCollection, Line2D를 생성하기 위해 4 명 아티스트를 사용한다는 것입니다 마커는 Line2D). 아티스트를 생성하는 코드는 범례에 추가 된 아티스트 목록의 첫 번째 아티스트 만 반환합니다 (matplotlib.legend_handler.HandlerBase.__call__ 참조). 오류 막대 목록의 첫 번째 아티스트는 수직선 인 라인 콜렉션입니다.이 라인은 leg.legendHandles으로 끝납니다. 따기가 효과가 없었던 이유는 다른 예술가들에 의해 숨겨져있는 것 같습니다 (제 생각 엔).

HandlerErrorbar의 로컬 하위 클래스를 만들어서 leg.legendHandles에 저장된 아티스트가 마커를위한 Line2D 개체가되도록 아티스트 목록을 다시 정렬합니다.

이 동작을 기본 동작으로 만들기 위해 PR을 열 것입니다.

+0

굉장해! 이 답변을 주셔서 감사합니다! 내가 원했던 실제 동작은 오류 막대를 켜거나 끕니다. 위 코드 조각을 포함 시켰습니다. 유일한 단점은 여전히 ​​전설에서 마커에 대한 Line2D 만 선택할 수 있다는 것입니다. 다른 것은 잡을 것 같지 않습니다.이상적으로는 전설에있는 마커와 오류 막대를 모두 독립적으로 선택하고 싶지만이 솔루션으로 해결할 것입니다. 다시 한번 감사드립니다. – astroMonkey

+0

@apodemus 편집이 거부되었습니다. 이 코드를 질문에 넣어야합니다 (사용하려는 toggle_errorbar 및 on_pick 함수). – tacaswell

+0

질문에 추가됨 ... – astroMonkey