Matplotlib 动画:通过子图的垂直光标线
Matplotlib animation: vertical cursor line through subplots
[解决方案已添加到此 post]
的编辑部分
2 个动画子图垂直堆叠。
我想根据鼠标位置显示一条黑色垂直线穿过它们。
到现在我只能在移动鼠标的时候完全乱图...
如何清除更新之间的旧垂直线?
(只是好奇:自从有了鼠标移动控制,我的电脑迷在执行代码时即使不移动鼠标也会发疯。鼠标是这样吗"calculation expensive"?!?)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from time import sleep
val1 = np.zeros(100)
val2 = np.zeros(100)
level1 = 0.2
level2 = 0.5
fig, ax = plt.subplots()
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
ax1.set_ylim(-0.5, 1.5)
ax2 = plt.subplot2grid((2,1),(1,0))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax2.set_ylim(-0.5, 1.5)
def onMouseMove(event):
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
def updateData():
global level1, val1
global level2, val2
clamp = lambda n, minn, maxn: max(min(maxn, n), minn)
level1 = clamp(level1 + (np.random.random()-.5)/20.0, 0.0, 1.0)
level2 = clamp(level2 + (np.random.random()-.5)/10.0, 0.0, 1.0)
# values are appended to the respective arrays which keep the last 100 readings
val1 = np.append(val1, level1)[-100:]
val2 = np.append(val2, level2)[-100:]
yield 1 # FuncAnimation expects an iterator
def visualize(i):
lineVal1.set_ydata(val1)
lineVal2.set_ydata(val2)
return lineVal1,lineVal2
fig.canvas.mpl_connect('motion_notify_event', onMouseMove)
ani = animation.FuncAnimation(fig, visualize, updateData, interval=50)
plt.show()
编辑1
由 Ophir 解决:
def onMouseMove(event):
ax1.lines = [ax1.lines[0]]
ax2.lines = [ax2.lines[0]]
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
编辑2
如果同一图中有更多数据集,例如:
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax1.set_ylim(-0.5, 1.5)
每个数据集的行存储在ax1.lines[]
:
ax1.lines[0]
是 lineVal1
ax1.lines[1]
是 lineVal2
ax1.lines[2]
如果已经画了就是竖线
这意味着 onMouseMove
必须更改为:
def onMouseMove(event):
ax1.lines = ax1.lines[:2] # keep the first two lines
ax1.axvline(x=event.xdata, color="k") # then draw the vertical line
将您的 onMouseMove
替换为以下内容:
(我用的是How to remove lines in a Matplotlib plot)
def onMouseMove(event):
ax1.lines = [ax1.lines[0]]
ax2.lines = [ax2.lines[0]]
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
无需向图中添加新的 axvline
,只需更改现有数据即可。您只需要存储 axvline
调用的 return 值以保留其句柄。数据格式为([x, x], [0, 1])
,可使用set_data
更改。
(顺便说一下,对于 axhlines,格式是 ([0, 1], [y, y])
。)
添加以下全局变量:
axvline1 = ax1.axvline(x=0., color="k")
axvline2 = ax2.axvline(x=0., color="k")
并将 conMouseMove 处理程序更改为:
def onMouseMove(event):
axvline1.set_data([event.xdata, event.xdata], [0, 1])
axvline2.set_data([event.xdata, event.xdata], [0, 1])
一个小缺点是您从一开始就从 x=0 处的 vlines 开始。
完整代码:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from time import sleep
val1 = np.zeros(100)
val2 = np.zeros(100)
level1 = 0.2
level2 = 0.5
fig, ax = plt.subplots()
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
ax1.set_ylim(-0.5, 1.5)
ax2 = plt.subplot2grid((2,1),(1,0))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax2.set_ylim(-0.5, 1.5)
axvline1 = ax1.axvline(x=0., color="k")
axvline2 = ax2.axvline(x=0., color="k")
def onMouseMove(event):
axvline1.set_data([event.xdata, event.xdata], [0, 1])
axvline2.set_data([event.xdata, event.xdata], [0, 1])
def updateData():
global level1, val1
global level2, val2
clamp = lambda n, minn, maxn: max(min(maxn, n), minn)
level1 = clamp(level1 + (np.random.random()-.5)/20.0, 0.0, 1.0)
level2 = clamp(level2 + (np.random.random()-.5)/10.0, 0.0, 1.0)
# values are appended to the respective arrays which keep the last 100 readings
val1 = np.append(val1, level1)[-100:]
val2 = np.append(val2, level2)[-100:]
yield 1 # FuncAnimation expects an iterator
def visualize(i):
lineVal1.set_ydata(val1)
lineVal2.set_ydata(val2)
return lineVal1,lineVal2
fig.canvas.mpl_connect('motion_notify_event', onMouseMove)
ani = animation.FuncAnimation(fig, visualize, updateData, interval=50)
plt.show()
[解决方案已添加到此 post]
的编辑部分2 个动画子图垂直堆叠。
我想根据鼠标位置显示一条黑色垂直线穿过它们。
到现在我只能在移动鼠标的时候完全乱图...
如何清除更新之间的旧垂直线?
(只是好奇:自从有了鼠标移动控制,我的电脑迷在执行代码时即使不移动鼠标也会发疯。鼠标是这样吗"calculation expensive"?!?)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from time import sleep
val1 = np.zeros(100)
val2 = np.zeros(100)
level1 = 0.2
level2 = 0.5
fig, ax = plt.subplots()
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
ax1.set_ylim(-0.5, 1.5)
ax2 = plt.subplot2grid((2,1),(1,0))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax2.set_ylim(-0.5, 1.5)
def onMouseMove(event):
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
def updateData():
global level1, val1
global level2, val2
clamp = lambda n, minn, maxn: max(min(maxn, n), minn)
level1 = clamp(level1 + (np.random.random()-.5)/20.0, 0.0, 1.0)
level2 = clamp(level2 + (np.random.random()-.5)/10.0, 0.0, 1.0)
# values are appended to the respective arrays which keep the last 100 readings
val1 = np.append(val1, level1)[-100:]
val2 = np.append(val2, level2)[-100:]
yield 1 # FuncAnimation expects an iterator
def visualize(i):
lineVal1.set_ydata(val1)
lineVal2.set_ydata(val2)
return lineVal1,lineVal2
fig.canvas.mpl_connect('motion_notify_event', onMouseMove)
ani = animation.FuncAnimation(fig, visualize, updateData, interval=50)
plt.show()
编辑1
由 Ophir 解决:
def onMouseMove(event):
ax1.lines = [ax1.lines[0]]
ax2.lines = [ax2.lines[0]]
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
编辑2
如果同一图中有更多数据集,例如:
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax1.set_ylim(-0.5, 1.5)
每个数据集的行存储在ax1.lines[]
:
ax1.lines[0]
是lineVal1
ax1.lines[1]
是lineVal2
ax1.lines[2]
如果已经画了就是竖线
这意味着 onMouseMove
必须更改为:
def onMouseMove(event):
ax1.lines = ax1.lines[:2] # keep the first two lines
ax1.axvline(x=event.xdata, color="k") # then draw the vertical line
将您的 onMouseMove
替换为以下内容:
(我用的是How to remove lines in a Matplotlib plot)
def onMouseMove(event):
ax1.lines = [ax1.lines[0]]
ax2.lines = [ax2.lines[0]]
ax1.axvline(x=event.xdata, color="k")
ax2.axvline(x=event.xdata, color="k")
无需向图中添加新的 axvline
,只需更改现有数据即可。您只需要存储 axvline
调用的 return 值以保留其句柄。数据格式为([x, x], [0, 1])
,可使用set_data
更改。
(顺便说一下,对于 axhlines,格式是 ([0, 1], [y, y])
。)
添加以下全局变量:
axvline1 = ax1.axvline(x=0., color="k")
axvline2 = ax2.axvline(x=0., color="k")
并将 conMouseMove 处理程序更改为:
def onMouseMove(event):
axvline1.set_data([event.xdata, event.xdata], [0, 1])
axvline2.set_data([event.xdata, event.xdata], [0, 1])
一个小缺点是您从一开始就从 x=0 处的 vlines 开始。
完整代码:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from time import sleep
val1 = np.zeros(100)
val2 = np.zeros(100)
level1 = 0.2
level2 = 0.5
fig, ax = plt.subplots()
ax1 = plt.subplot2grid((2,1),(0,0))
lineVal1, = ax1.plot(np.zeros(100))
ax1.set_ylim(-0.5, 1.5)
ax2 = plt.subplot2grid((2,1),(1,0))
lineVal2, = ax2.plot(np.zeros(100), color = "r")
ax2.set_ylim(-0.5, 1.5)
axvline1 = ax1.axvline(x=0., color="k")
axvline2 = ax2.axvline(x=0., color="k")
def onMouseMove(event):
axvline1.set_data([event.xdata, event.xdata], [0, 1])
axvline2.set_data([event.xdata, event.xdata], [0, 1])
def updateData():
global level1, val1
global level2, val2
clamp = lambda n, minn, maxn: max(min(maxn, n), minn)
level1 = clamp(level1 + (np.random.random()-.5)/20.0, 0.0, 1.0)
level2 = clamp(level2 + (np.random.random()-.5)/10.0, 0.0, 1.0)
# values are appended to the respective arrays which keep the last 100 readings
val1 = np.append(val1, level1)[-100:]
val2 = np.append(val2, level2)[-100:]
yield 1 # FuncAnimation expects an iterator
def visualize(i):
lineVal1.set_ydata(val1)
lineVal2.set_ydata(val2)
return lineVal1,lineVal2
fig.canvas.mpl_connect('motion_notify_event', onMouseMove)
ani = animation.FuncAnimation(fig, visualize, updateData, interval=50)
plt.show()