2017-10-13 1 views
0

Matplotlibのインタラクティブスライダーでプロットを実装しようとしています。私はInteractive matplotlib plot with two slidersの提案を使ってスライダを実装しました。今私は、スライダが変化する点の注釈を移動しようとしています。私が理解できないいくつかの奇妙な行動があるようです。matplotlibでのアノテーションオブジェクトの処理

以下は、動作するコードの例です。コードは3番目のサブプロット内にポイントを生成し、スライダが変更されるとポイントが移動します。ポイントで移動したポイントに注釈があります。しかし、現在の例では、古いアノテーションは削除されず、不要となります。

私はこれを解決するためにいくつかのことを試みました。例えば。コメントされたコードに「!!」とマークされていると思います。仕事をする:古いアノテーションを削除してから新しいアノテーションを追加します。ただし、コメントが解除されている場合は、スライダが変更されたときにアノテーションに何も起こりません。

私はRemove annotation while keeping plot matplotlib,Python and Remove annotation from figureおよびRemove and Re-Add Object in matplotlib | Toggle Object appearance matplotlibと読みました。そこからの提案を実装しようとしました。つまり、注釈の座標を変更したり、注釈をアーティストオブジェクトとして追加したりしようとしました。 2人のうちの何人も何もしなかった。

ここには何か根本的なものがありますか?私は、アノテーションのオブジェクト変数がどのようにPythonで処理されるのか分かりません。

もう1つのコメント:私はコードの構造をあまり変更したくない(特に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は、関数のローカルスコープで再定義されています。したがって、実際にはPythonのローカルスコープとグローバルスコープを理解することになり、特定のmatplotlibオブジェクトとは関係ありません。

誤差が容易また、UnboundLocalError: local variable 'a' referenced before assignmentをスロー

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

ような場合に再現することができます。

最も簡単な解決策:qAnnotationをグローバルスコープ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() 
関連する問題