2017-10-13 4 views
0

Matplotlib의 대화 형 슬라이더가있는 플롯을 구현하려고합니다. 슬라이더를 구현하기 위해 Interactive matplotlib plot with two sliders의 제안을 사용했습니다. 이제 슬라이더가 바뀌는 지점의 주석을 이동하려고합니다. 내가 알아낼 수없는 이상한 행동이있는 것 같습니다.matplotlib의 주석 객체 처리

다음은 작동하는 예제 코드입니다. 이 코드는 세 번째 서브 플롯에 점을 생성하고 슬라이더가 변경되면 점이 이동합니다. 점과 함께 움직이는 점에 대한 주석이 있습니다. 그러나 현재 예에서는 오래된 주석이 제거되지 않으므로 원하지 않습니다.

나는 이것을 고치려고 몇 가지 시도했다. 예 : 나는 주석이 달린 코드가 '!!'으로 표시 될 것으로 기대했을 것이다. 작업을 수행하려면 이전 주석을 제거한 다음 나중에 새 주석을 추가하십시오. 그러나 주석 처리되지 않은 경우 슬라이더가 변경 될 때 주석에 아무런 변화가 없습니다.

나는 Remove annotation while keeping plot matplotlib, Python and Remove annotation from figureRemove and Re-Add Object in matplotlib | Toggle Object appearance matplotlib을 읽었습니다. 거기에서 제안을 구현하려고했습니다. 즉 주석의 좌표를 변경하거나 주석을 아티스트 개체로 추가하려고했습니다. 두 사람 중 누구도하지 못했습니다.

내가 근본적으로 잘못된 것이 있습니까? 어노테이션의 객체 변수가 파이썬에서 어떻게 처리되는지 이해하지 못한다.

한 가지 더 의견 : 코드 구조를 너무 많이 변경하지 않는 것이 좋습니다 (특히 sympy 사용). 오류를 재현하기 위해이 최소한의 예제를 만들기 위해 많은 것을 제거했지만 다른 플롯의 구조가 필요합니다. 광고 qAnnotation.remove() 주석을

import numpy as np 
import sympy as sp 
import matplotlib.pyplot as plt 
import matplotlib 
from matplotlib.widgets import Slider, Button, RadioButtons 

## Define variable symbols ## 
var1 = sp.Symbol('var1') 

## Define initial value ## 
var1_init = 5 

## Marker position functions ## 
def positionY(var1): 
    return var1 

def positionX(var1): 
    return var1 

## plot ## 
axis_color = 'lightgoldenrodyellow' 

fig = plt.figure() 
ax = fig.add_subplot(131) 
ax2 = fig.add_subplot(132) 
ax3 = fig.add_subplot(133) 

# Adjust the subplots region to leave some space for the slider 
fig.subplots_adjust(left=0.25, bottom=0.3) 

# Draw the initial plot 
marker_coord = (positionX(var1_init),positionY(var1_init)) 
[qMarker1] = ax3.plot(marker_coord[0],marker_coord[1],'ro') 
ax3.set_xlim([-1.0, 11.0]) 
ax3.set_ylim([-1.0, 11.0]) 
qAnnotation = ax3.annotate('(%.2f, %.2f)' % marker_coord, xy=marker_coord, textcoords='data') 

## Add sliders ## 

# Define an axes area and draw sliders in it 
var1_slider_ax = fig.add_axes([0.25, 0.2, 0.65, 0.03], facecolor=axis_color) 
var1_slider = Slider(var1_slider_ax, 'var1', 0, 10.0, valinit=var1_init) 

# Define an action for modifying the plot1 when any slider's value changes 
def sliders_on_changed(val): 
    qMarker1.set_ydata(positionY(var1_slider.val)) 
    qMarker1.set_xdata(positionX(var1_slider.val)) 
    #qAnnotation.remove() ## <--------------------------- !! 
    marker_coord = (positionX(var1_slider.val),positionY(var1_slider.val)) 
    qAnnotation = ax3.annotate('(%.2f, %.2f)' % marker_coord, xy=marker_coord, textcoords='data') 
    fig.canvas.draw_idle() 
var1_slider.on_changed(sliders_on_changed) 

# Add a button for resetting the parameters 
reset_button_ax = fig.add_axes([0.05, 0.1, 0.1, 0.04]) 
reset_button = Button(reset_button_ax, 'Reset', color=axis_color, hovercolor='0.975') 
def reset_button_on_clicked(mouse_event): 
    var1_slider.reset() 
reset_button.on_clicked(reset_button_on_clicked) 

plt.show() 

답변

1

오류 UnboundLocalError: local variable 'qAnnotation' referenced before assignment 문제 꽤 설명이 생성한다. qAnnotation은 함수의 로컬 범위에서 재정의됩니다. 따라서 파이썬에서 로컬 및 글로벌 스코프를 이해하는 것이고 특정 matplotlib 객체와는 아무런 관련이 없습니다.

오류

또한 쉽게 발생

a = 0 
def f(): 
    a += 1 
    a=100 
f() 

, UnboundLocalError: local variable 'a' referenced before assignment 같은 경우에 재생 될 수있다.

가장 쉬운 해결 방법 : 을 global qAnnotation으로 사용하십시오. 명시 적 global 문을 피하는

def sliders_on_changed(val): 
    global qAnnotation 
    # .. 
    qAnnotation.remove() 
    qAnnotation = ax3.annotate(...) 
    fig.canvas.draw_idle() 

다른 솔루션은 주석이 목록의 일부가 될 수 있도록 로컬이 목록에 액세스하는 것입니다.

qAnnotation = [ax3.annotate(...)] 

def sliders_on_changed(val): 
    # .. 
    qAnnotation[0].remove() 
    qAnnotation[0] = ax3.annotate(...) 
    fig.canvas.draw_idle()