matplotlib 中的注释对象处理
Annotation object handling in matplotlib
我正在尝试在 Matplotlib 中使用交互式滑块实现绘图。我使用了 Interactive matplotlib plot with two sliders 的建议来实现滑块。现在我试图在滑块改变时移动一个点的注释。似乎有一些我无法弄清楚的奇怪行为。
下面是一个有效的示例代码。该代码在第三个子图中生成一个点,当滑块改变时,该点移动。随点移动的点上有注释。然而,在当前示例中,旧注释未被删除,这是不需要的。
我尝试了一些方法来解决这个问题。例如。我本来期望标有“!!”的注释代码完成这项工作:删除旧注释,然后添加一个新注释。但是,如果取消注释,则更改滑块时注释根本不会发生任何变化。
我已阅读, Python and Remove annotation from figure and Remove and Re-Add Object in matplotlib | Toggle Object appearance matplotlib。我尝试从那里实施建议,即更改注释的坐标或将注释添加为艺术家对象。两者都没有做任何事情。
我在这里有什么基本的错误吗?感觉没看懂python.
中注解的对象变量是怎么处理的
再多说一句:我宁愿不要过多地改变代码的结构(尤其是 sympy 的使用)。我删除了很多东西来创建这个最小的例子来重现错误,但我需要其他图的结构。
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()
取消注释行 qAnnotation.remove()
会产生错误
UnboundLocalError: local variable 'qAnnotation' referenced before assignment
,这很好地解释了这个问题。 qAnnotation
在函数的局部范围内重新定义。所以它实际上是关于理解 python 中的局部和全局范围,与特定的 matplotlib 对象无关。
在
这样的情况下很容易重现错误
a = 0
def f():
a += 1
a=100
f()
这也会抛出,UnboundLocalError: local variable 'a' referenced before assignment
。
最简单的解决方案:使 qAnnotation
在全局范围内可用,global qAnnotation
。
def sliders_on_changed(val):
global qAnnotation
# ..
qAnnotation.remove()
qAnnotation = ax3.annotate(...)
fig.canvas.draw_idle()
另一种避免显式 global
语句的解决方案是使注释成为列表的一部分并在本地访问该列表。
qAnnotation = [ax3.annotate( ... )]
def sliders_on_changed(val):
# ..
qAnnotation[0].remove()
qAnnotation[0] = ax3.annotate( ... )
fig.canvas.draw_idle()
我正在尝试在 Matplotlib 中使用交互式滑块实现绘图。我使用了 Interactive matplotlib plot with two sliders 的建议来实现滑块。现在我试图在滑块改变时移动一个点的注释。似乎有一些我无法弄清楚的奇怪行为。
下面是一个有效的示例代码。该代码在第三个子图中生成一个点,当滑块改变时,该点移动。随点移动的点上有注释。然而,在当前示例中,旧注释未被删除,这是不需要的。
我尝试了一些方法来解决这个问题。例如。我本来期望标有“!!”的注释代码完成这项工作:删除旧注释,然后添加一个新注释。但是,如果取消注释,则更改滑块时注释根本不会发生任何变化。
我已阅读
我在这里有什么基本的错误吗?感觉没看懂python.
中注解的对象变量是怎么处理的再多说一句:我宁愿不要过多地改变代码的结构(尤其是 sympy 的使用)。我删除了很多东西来创建这个最小的例子来重现错误,但我需要其他图的结构。
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()
取消注释行 qAnnotation.remove()
会产生错误
UnboundLocalError: local variable 'qAnnotation' referenced before assignment
,这很好地解释了这个问题。 qAnnotation
在函数的局部范围内重新定义。所以它实际上是关于理解 python 中的局部和全局范围,与特定的 matplotlib 对象无关。
在
这样的情况下很容易重现错误a = 0
def f():
a += 1
a=100
f()
这也会抛出,UnboundLocalError: local variable 'a' referenced before assignment
。
最简单的解决方案:使 qAnnotation
在全局范围内可用,global qAnnotation
。
def sliders_on_changed(val):
global qAnnotation
# ..
qAnnotation.remove()
qAnnotation = ax3.annotate(...)
fig.canvas.draw_idle()
另一种避免显式 global
语句的解决方案是使注释成为列表的一部分并在本地访问该列表。
qAnnotation = [ax3.annotate( ... )]
def sliders_on_changed(val):
# ..
qAnnotation[0].remove()
qAnnotation[0] = ax3.annotate( ... )
fig.canvas.draw_idle()