2013-04-29 1 views
2

하나의 플롯에 여러 데이터 세트를 플롯해야합니다. 하나 이상의 플롯을 비교하기 위해 하나 이상의 플롯을 강조 표시하는 것이 유용합니다. 이를 위해 라인을 직접 선택하거나 범례에서 해당 항목을 클릭 할 때 플롯의 선 스타일을 ":" (배경 그림)과 "-" (플롯으로 강조 표시) 사이에서 전환합니다.범례가 축 외부에있는 경우 마우스 클릭시 더블 이벤트가 등록됩니다.

bbox_to_anchor을 사용하여 축을 벗어난 범례를 움직이기 전까지는 완벽하게 작동합니다. 그런 다음 범례 선을 한 번 클릭하면 두 번의 클릭 이벤트가 연속적으로 트리거되어 토글 효과를 취소합니다.

pick_event의 올바른 동작을 유지하면서 범례를 축 외부에 배치하려면 어떻게해야합니까?

줄거리를 클릭하면 플롯 선을 클릭하면 '강조 표시'와 '강조 표시되지 않음'사이를 토글하는 반면, 범례 선을 클릭하면 작전 표시 줄이 잠시 전환되어 이전 상태로 돌아갑니다.

import pylab 
import numpy 

# Create data for plotting 
t = numpy.linspace(0, 1.0, 100) 
a = numpy.sin(2*numpy.pi*t) 

# Set up figure 
fig = pylab.figure() 
ax = pylab.subplot(111) 

# Plot figures  
lines = []  
for i in range(5): 
    line = ax.plot(t, (i+1)*a, linestyle=':', picker=5, label='line%d'%(i+1)) 
    lines.append(line[0]) # Save plot lines 

# Create legend 
leg = ax.legend(bbox_to_anchor=(1.01, 1), loc=2) # Does not work as expected 
# leg = ax.legend() # Works!! 

# Get legend lines 
leglines = leg.get_lines() 
# Set event for legend lines 
for line in leglines: 
    line.set_picker(5) 

# Create a 2 way mapping between legend lines <-> plot lines  
line2leg = dict(zip(lines+leglines, leglines+lines)) 

# Define event function 
def onpick(event): 
    thisline = event.artist 

    if thisline.get_linestyle()==':': 
     print ": -> -" # For debugging 
     thisline.set_linestyle('-') 
     line2leg[thisline].set_linestyle('-') 
    else: 
     print "- -> :" # For debugging 
     thisline.set_linestyle(':') 
     line2leg[thisline].set_linestyle(':') 
    fig.canvas.draw() 

# connect event function  
fig.canvas.mpl_connect('pick_event', onpick) 
pylab.show() 
+0

호기심입니다.같은 픽업 이벤트가 두 번 처리되는 것처럼 보이지 않습니다. 두 이벤트를 생성하는 것이 아니라, 이것이 버그라고 생각하게합니다. – tacaswell

+0

@tcaswell 동일한 픽업 이벤트인지 아니면 같은 종류의 2 개인지를 어떻게 알 수 있습니까? 이벤트가 생성됩니까? – Dhara

+0

'onpick'에'print event' 라인을 추가하면 인쇄 할 때 같은 메모리 주소를가집니다. – tacaswell

답변

3

경우 다음과 원숭이 패치 Artist.pick :

matplotlib.artist.Artist.orig_pick = matplotlib.artist.Artist.pick 
def nu_pick(self, me): 
    print self 
    matplotlib.artist.Artist.orig_pick(self, me) 

matplotlib.artist.Artist.pick = nu_pick 

당신은 예술가가 선택 이벤트를 재귀 적 방법을 볼 수 있습니다. (각각 Artist 개체는 자체적으로 pick을 호출하고 모든 개체는 자식 임). 이해가 안되는 이유 때문에 전설의 그리기 영역에 각 행의 사본이 2 개 있습니다 (내부와 외부 모두 다르게 동작합니다).

import pylab 
import numpy 

# Create data for plotting 
t = numpy.linspace(0, 1.0, 100) 
a = numpy.sin(2*numpy.pi*t) 

# Set up figure 
fig = pylab.figure() 
ax = pylab.subplot(111) 

# Plot figures  
lines = []  
for i in range(5): 
    line = ax.plot(t, (i+1)*a, linestyle=':', picker=5, label='line%d'%(i+1)) 
    lines.append(line[0]) # Save plot lines 

# Create legend 
leg = ax.legend(bbox_to_anchor=(1.01, 1), loc=2) # Does not work as expected 
#leg = ax.legend() # Works!! 

# Get legend lines 
leglines = leg.get_lines() 
# Set event for legend lines 
for line in leglines: 
    line.set_picker(5) 

# Create a 2 way mapping between legend lines <-> plot lines  
line2leg = dict(zip(lines+leglines, leglines+lines)) 
count_dict = dict((l, 0) for l in lines) 
# Define event function 
def onpick(event): 
    thisline = event.artist 
    print event 
    print thisline 
    if thisline in lines: 
     print 'lines' 
     count_dict[thisline] = 0 
    elif thisline in leglines: 
     print 'leglines' 
     thisline = line2leg[thisline] 
     count_dict[thisline] += 1 
    print 'added' 
    if (count_dict[thisline] % 2) == 1: 
     print count_dict[thisline] 
     return 
    print 'tested' 
    if thisline.get_linestyle()==':': 
     print ": -> -" # For debugging 
     thisline.set_linestyle('-') 
     line2leg[thisline].set_linestyle('-') 
    else: 
     print "- -> :" # For debugging 
     thisline.set_linestyle(':') 
     line2leg[thisline].set_linestyle(':') 
    fig.canvas.draw() 

# connect event function  
fig.canvas.mpl_connect('pick_event', onpick) 
pylab.show() 

(나는 내 ​​모든 드 도청 문에서 왼쪽) :

하는 방법입니다-해키 솔루션은 단지 leglines 명중 된 횟수를 카운트 만 이상한 사람에 전환하는 것입니다.

github에서 문제를 만들고 싶지 않다면 버그입니다.

+0

감사합니다. 다른 사람들이 토론에 유용한 것을 추가 할 수 있는지 알아보기 위해 조금만 더 열어 두겠습니다. – Dhara

+0

github에서 [this] (https://github.com/matplotlib/matplotlib/issues/1962) 문제가 생성되었습니다. – Dhara

3

전설의 예술가를 만나면 범례에 bbox_to_anchor 세트가있는 범례의 하위 트리에 두 번있는 것으로 나타났습니다.

나는이 새로운 장치에 대해 here에 물었고, 새로운 mouseevent를 보았고 콜백으로 이미 처리 된 아티스트를 추적했다.

사람이 나는 이것이 버그 모르겠어요이 "기능"

을 처리하는 더 우아한 방법이 생각하면 내가 의견을 요청했습니다. 그러나 어린이 라인이 .lines 속성에 있고 포장 상자 데이터 구조의 깊숙한 곳에있는 전설에 고유 한 것처럼 보입니다. get_children 메소드는이 두 가지를 모두 찾습니다. 다행히도 사본이 아닌 동일한 객체이므로 이미 처리 된 행을 확인할 수 있습니다.

+0

전설 작성 코드의 버그라고 생각합니다. 그것을 그리는 데 한 번만 예술가가 필요하고'bbox_to_anchor'를 설정할 때 이런 식으로 행동을 바꾸면 안됩니다. – tacaswell

3

tcaswell의 솔루션 계산 이벤트와 유사한 또 다른 접근법입니다. 원래의 legend picking example에 3 줄만 추가되었습니다. 그것은 파이썬의 함수 속성을 사용합니다.

def onpick(event): 
    if onpick.count % 2 == 0: #### LINE ADDED #### 
     # 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 = not origline.get_visible() 
     origline.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() 
    onpick.count += 1 #### LINE ADDED #### 

onpick.count = 0 #### LINE ADDED #### 
관련 문제