matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)


Posted in Python onJanuary 10, 2021

matplotlib在widgets模块提供Cursor类用于支持十字光标的生成。另外官方还提供了自定义十字光标的实例。

widgets模块Cursor类源码

class Cursor(AxesWidget):
  """
  A crosshair cursor that spans the axes and moves with mouse cursor.

  For the cursor to remain responsive you must keep a reference to it.

  Parameters
  ----------
  ax : `matplotlib.axes.Axes`
    The `~.axes.Axes` to attach the cursor to.
  horizOn : bool, default: True
    Whether to draw the horizontal line.
  vertOn : bool, default: True
    Whether to draw the vertical line.
  useblit : bool, default: False
    Use blitting for faster drawing if supported by the backend.

  Other Parameters
  ----------------
  **lineprops
    `.Line2D` properties that control the appearance of the lines.
    See also `~.Axes.axhline`.

  Examples
  --------
  See :doc:`/gallery/widgets/cursor`.
  """

  def __init__(self, ax, horizOn=True, vertOn=True, useblit=False,
         **lineprops):
    AxesWidget.__init__(self, ax)

    self.connect_event('motion_notify_event', self.onmove)
    self.connect_event('draw_event', self.clear)

    self.visible = True
    self.horizOn = horizOn
    self.vertOn = vertOn
    self.useblit = useblit and self.canvas.supports_blit

    if self.useblit:
      lineprops['animated'] = True
    self.lineh = ax.axhline(ax.get_ybound()[0], visible=False, **lineprops)
    self.linev = ax.axvline(ax.get_xbound()[0], visible=False, **lineprops)

    self.background = None
    self.needclear = False

  def clear(self, event):
    """Internal event handler to clear the cursor."""
    if self.ignore(event):
      return
    if self.useblit:
      self.background = self.canvas.copy_from_bbox(self.ax.bbox)
    self.linev.set_visible(False)
    self.lineh.set_visible(False)
    
  def onmove(self, event):
    """Internal event handler to draw the cursor when the mouse moves."""
    if self.ignore(event):
      return
    if not self.canvas.widgetlock.available(self):
      return
    if event.inaxes != self.ax:
      self.linev.set_visible(False)
      self.lineh.set_visible(False)

      if self.needclear:
        self.canvas.draw()
        self.needclear = False
      return
    self.needclear = True
    if not self.visible:
      return
    self.linev.set_xdata((event.xdata, event.xdata))

    self.lineh.set_ydata((event.ydata, event.ydata))
    self.linev.set_visible(self.visible and self.vertOn)
    self.lineh.set_visible(self.visible and self.horizOn)

    self._update()

  def _update(self):
    if self.useblit:
      if self.background is not None:
        self.canvas.restore_region(self.background)
      self.ax.draw_artist(self.linev)
      self.ax.draw_artist(self.lineh)
      self.canvas.blit(self.ax.bbox)
    else:
      self.canvas.draw_idle()
    return False

自定义十字光标实现

简易十字光标实现

首先在 Cursor类的构造方法__init__中,构造了十字光标的横线、竖线和坐标显示;然后在on_mouse_move方法中,根据事件数据更新横竖线和坐标显示,最后在调用时,通过mpl_connect方法绑定on_mouse_move方法和鼠标移动事件'motion_notify_event'。

import matplotlib.pyplot as plt
import numpy as np


class Cursor:
  """
  A cross hair cursor.
  """
  def __init__(self, ax):
    self.ax = ax
    self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
    self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
    # text location in axes coordinates
    self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)

  def set_cross_hair_visible(self, visible):
    need_redraw = self.horizontal_line.get_visible() != visible
    self.horizontal_line.set_visible(visible)
    self.vertical_line.set_visible(visible)
    self.text.set_visible(visible)
    return need_redraw

  def on_mouse_move(self, event):
    if not event.inaxes:
      need_redraw = self.set_cross_hair_visible(False)
      if need_redraw:
        self.ax.figure.canvas.draw()
    else:
      self.set_cross_hair_visible(True)
      x, y = event.xdata, event.ydata
      # update the line positions
      self.horizontal_line.set_ydata(y)
      self.vertical_line.set_xdata(x)
      self.text.set_text('x=%1.2f, y=%1.2f' % (x, y))
      self.ax.figure.canvas.draw()


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Simple cursor')
ax.plot(x, y, 'o')
cursor = Cursor(ax)
#关键部分,绑定鼠标移动事件处理
fig.canvas.mpl_connect('motion_notify_event', cursor.on_mouse_move)
plt.show()

优化十字光标实现

在简易实现中,每次鼠标移动时,都会重绘整个图像,这样效率比较低。
在优化实现中,每次鼠标移动时,只重绘光标和坐标显示,背景图像不再重绘。

import matplotlib.pyplot as plt
import numpy as np


class BlittedCursor:
  """
  A cross hair cursor using blitting for faster redraw.
  """
  def __init__(self, ax):
    self.ax = ax
    self.background = None
    self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
    self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
    # text location in axes coordinates
    self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)
    self._creating_background = False
    ax.figure.canvas.mpl_connect('draw_event', self.on_draw)

  def on_draw(self, event):
    self.create_new_background()

  def set_cross_hair_visible(self, visible):
    need_redraw = self.horizontal_line.get_visible() != visible
    self.horizontal_line.set_visible(visible)
    self.vertical_line.set_visible(visible)
    self.text.set_visible(visible)
    return need_redraw

  def create_new_background(self):
    if self._creating_background:
      # discard calls triggered from within this function
      return
    self._creating_background = True
    self.set_cross_hair_visible(False)
    self.ax.figure.canvas.draw()
    self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)
    self.set_cross_hair_visible(True)
    self._creating_background = False

  def on_mouse_move(self, event):
    if self.background is None:
      self.create_new_background()
    if not event.inaxes:
      need_redraw = self.set_cross_hair_visible(False)
      if need_redraw:
        self.ax.figure.canvas.restore_region(self.background)
        self.ax.figure.canvas.blit(self.ax.bbox)
    else:
      self.set_cross_hair_visible(True)
      # update the line positions
      x, y = event.xdata, event.ydata
      self.horizontal_line.set_ydata(y)
      self.vertical_line.set_xdata(x)
      self.text.set_text('x=%1.2f, y=%1.2f' % (x, y))

      self.ax.figure.canvas.restore_region(self.background)
      self.ax.draw_artist(self.horizontal_line)
      self.ax.draw_artist(self.vertical_line)
      self.ax.draw_artist(self.text)
      self.ax.figure.canvas.blit(self.ax.bbox)


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Blitted cursor')
ax.plot(x, y, 'o')
blitted_cursor = BlittedCursor(ax)
fig.canvas.mpl_connect('motion_notify_event', blitted_cursor.on_mouse_move)
plt.show()

捕捉数据十字光标实现

在前面的两种实现中,鼠标十字光标可以随意移动。在本实现中,十字光标只会出现在离鼠标x坐标最近的数据点上。

import matplotlib.pyplot as plt
import numpy as np


class SnappingCursor:
  """
  A cross hair cursor that snaps to the data point of a line, which is
  closest to the *x* position of the cursor.

  For simplicity, this assumes that *x* values of the data are sorted.
  """
  def __init__(self, ax, line):
    self.ax = ax
    self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
    self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
    self.x, self.y = line.get_data()
    self._last_index = None
    # text location in axes coords
    self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)

  def set_cross_hair_visible(self, visible):
    need_redraw = self.horizontal_line.get_visible() != visible
    self.horizontal_line.set_visible(visible)
    self.vertical_line.set_visible(visible)
    self.text.set_visible(visible)
    return need_redraw

  def on_mouse_move(self, event):
    if not event.inaxes:
      self._last_index = None
      need_redraw = self.set_cross_hair_visible(False)
      if need_redraw:
        self.ax.figure.canvas.draw()
    else:
      self.set_cross_hair_visible(True)
      x, y = event.xdata, event.ydata
      index = min(np.searchsorted(self.x, x), len(self.x) - 1)
      if index == self._last_index:
        return # still on the same data point. Nothing to do.
      self._last_index = index
      x = self.x[index]
      y = self.y[index]
      # update the line positions
      self.horizontal_line.set_ydata(y)
      self.vertical_line.set_xdata(x)
      self.text.set_text('x=%1.2f, y=%1.2f' % (x, y))
      self.ax.figure.canvas.draw()


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Snapping cursor')
line, = ax.plot(x, y, 'o')
snap_cursor = SnappingCursor(ax, line)
fig.canvas.mpl_connect('motion_notify_event', snap_cursor.on_mouse_move)
plt.show()

参考资料

https://www.matplotlib.org.cn/gallery/misc/cursor_demo_sgskip.html

到此这篇关于matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)的文章就介绍到这了,更多相关matplotlib鼠标十字光标 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python操作串口的方法
Jun 17 Python
Python中functools模块的常用函数解析
Jun 30 Python
python中requests使用代理proxies方法介绍
Oct 25 Python
使用pandas中的DataFrame数据绘制柱状图的方法
Apr 10 Python
Django框架使用富文本编辑器Uedit的方法分析
Jul 31 Python
Django中自定义admin Xadmin的实现代码
Aug 09 Python
Python进程间通信 multiProcessing Queue队列实现详解
Sep 23 Python
python打开使用的方法
Sep 30 Python
pytorch实现查看当前学习率
Jun 24 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
Nov 30 Python
让文件路径提取变得更简单的Python Path库
May 27 Python
Python内置的数据类型及使用方法
Apr 13 Python
解决selenium+Headless Chrome实现不弹出浏览器自动化登录的问题
Jan 09 #Python
用Python自动清理电脑内重复文件,只要10行代码(自动脚本)
Jan 09 #Python
selenium+headless chrome爬虫的实现示例
Jan 08 #Python
plt.figure()参数使用详解及运行演示
Jan 08 #Python
matplotlib绘制多子图共享鼠标光标的方法示例
Jan 08 #Python
利用python查看数组中的所有元素是否相同
Jan 08 #Python
Python爬虫自动化获取华图和粉笔网站的错题(推荐)
Jan 08 #Python
You might like
学习php设计模式 php实现命令模式(command)
2015/12/08 PHP
YII Framework框架教程之国际化实现方法
2016/03/14 PHP
Yii框架实现多数据库配置和操作的方法
2017/05/25 PHP
PHP实现更改hosts文件的方法示例
2017/08/08 PHP
浅谈PHP进程管理
2019/03/08 PHP
jQuery代码优化 选择符篇
2011/11/01 Javascript
Java/JS获取flash高宽的具体方法
2013/12/27 Javascript
JavaScript中用于四舍五入的Math.round()方法讲解
2015/06/15 Javascript
JS使用post提交的两种方式
2015/12/03 Javascript
JS实现动态表格的添加,修改,删除功能(推荐)
2016/06/15 Javascript
微信小程序 rpx 尺寸单位详细介绍
2016/10/13 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
关于webpack2和模块打包的新手指南(小结)
2017/08/07 Javascript
Vue.js划分组件的方法
2017/10/29 Javascript
小程序视频或音频自定义可拖拽进度条的示例代码
2018/09/30 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
2019/04/11 Javascript
JS实现页面数据懒加载
2020/02/13 Javascript
ES5新增数组的实现方法
2020/05/12 Javascript
解决Vue @submit 提交后不刷新页面问题
2020/07/18 Javascript
JavaScript仿京东轮播图效果
2021/02/25 Javascript
[05:56]第十六期——新进3大C之小兔基
2014/06/24 DOTA
[01:15]《辉夜杯》北京网鱼队巡礼
2015/10/26 DOTA
分析python服务器拒绝服务攻击代码
2014/01/16 Python
Python在不同目录下导入模块的实现方法
2017/10/27 Python
如何使用python实现模拟鼠标点击
2020/01/06 Python
JSF面试题:Jsf中导航的标签是什么
2013/04/20 面试题
护理学毕业生自荐信
2013/10/02 职场文书
业务代表的岗位职责
2013/11/16 职场文书
会走路的树教学反思
2014/02/20 职场文书
集团公司党的群众路线教育实践活动工作总结
2014/03/03 职场文书
函授本科个人自我鉴定
2014/03/25 职场文书
机电一体化应届生求职信
2014/08/09 职场文书
住房公积金贷款工资证明
2015/06/12 职场文书
电影雨中的树观后感
2015/06/15 职场文书
学前教育见习总结
2015/06/23 职场文书
《司马光》教学反思
2016/02/22 职场文书