【问题标题】:Matplotlib animation: vertical cursor line through subplotsMatplotlib 动画:通过子图的垂直光标线
【发布时间】:2016-12-29 00:09:34
【问题描述】:

[解决方案已添加到本文的编辑部分]

2 个动画子图垂直堆叠。

我想根据鼠标位置显示一条穿过它们的黑色垂直线。

到现在我也只能在移动鼠标的时候完全弄乱人形……

如何清除更新之间的旧垂直线?

(只是出于好奇:由于鼠标移动控制,我的 PC 粉丝即使不移动鼠标也执行代码时会发疯。鼠标有那么“计算昂贵”吗?!?)

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

【问题讨论】:

    标签: python matplotlib animation mouse-cursor


    【解决方案1】:

    将您的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")
    

    【讨论】:

    • 谢谢奥菲尔。没有你的帮助,我永远找不到它。现在完全合乎逻辑了。
    【解决方案2】:

    您只需更改现有数据的数据,而不是向图中添加新的axvlines。您只需要存储axvline 调用的返回值以保留其句柄。数据格式为([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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      相关资源
      最近更新 更多