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 相关文章推荐
python3使用tkinter实现ui界面简单实例
Jan 10 Python
python简单分割文件的方法
Jul 30 Python
Windows系统下使用flup搭建Nginx和Python环境的方法
Dec 25 Python
深入理解python多进程编程
Jun 12 Python
Python Sqlite3以字典形式返回查询结果的实现方法
Oct 03 Python
Python模拟三级菜单效果
Sep 11 Python
200行python代码实现2048游戏
Jul 17 Python
使用Python打造一款间谍程序的流程分析
Feb 21 Python
解析pip安装第三方库但PyCharm中却无法识别的问题及PyCharm安装第三方库的方法教程
Mar 10 Python
使用npy转image图像并保存的实例
Jul 01 Python
python中pdb模块实例用法
Jan 15 Python
详解Java中一维、二维数组在内存中的结构
Feb 11 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版 汉字转码的实现详解
2013/06/09 PHP
php数组转成json格式的方法
2015/03/09 PHP
php并发加锁示例
2016/10/17 PHP
php版微信小店API二次开发及使用示例
2016/11/12 PHP
PHP生成唯一ID之SnowFlake算法
2016/12/17 PHP
自制基于jQuery的智能提示插件一枚
2011/02/18 Javascript
兼容IE和Firefox的javascript获取iframe文档内容的函数
2011/08/15 Javascript
JavaScript高级程序设计 阅读笔记(四) ECMAScript中的类型转换
2012/02/27 Javascript
Web跨浏览器进程通信(Web跨域)
2013/04/17 Javascript
jquery form表单序列化为对象的示例代码
2014/03/05 Javascript
JavaScript利用正则表达式去除日期中的-
2014/06/09 Javascript
Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法
2016/06/23 Javascript
AngularJS表单提交实例详解
2017/02/18 Javascript
详解es6新增数组方法简便了哪些操作
2019/05/09 Javascript
node express使用HTML模板的方法示例
2019/08/22 Javascript
python解析html开发库pyquery使用方法
2014/02/07 Python
收集的几个Python小技巧分享
2014/11/22 Python
Python实现的批量下载RFC文档
2015/03/10 Python
不到20行代码用Python做一个智能聊天机器人
2019/04/19 Python
python爬虫 猫眼电影和电影天堂数据csv和mysql存储过程解析
2019/09/05 Python
python 如何停止一个死循环的线程
2020/11/24 Python
canvas实现圆形进度条动画的示例代码
2017/12/26 HTML / CSS
详解html5 canvas 微信海报分享(个人爬坑)
2018/01/12 HTML / CSS
C#的几个面试问题
2016/05/22 面试题
物业客服专员岗位职责
2013/11/30 职场文书
机械专业求职信范文
2014/07/15 职场文书
农行心得体会
2014/09/02 职场文书
违反交通法规检讨书
2014/09/10 职场文书
高中班主任评语
2014/12/30 职场文书
考试作弊检讨书
2015/01/27 职场文书
红旗渠导游词
2015/02/09 职场文书
诚信考试承诺书范文
2015/04/29 职场文书
2016年三八红旗手先进事迹材料
2016/02/26 职场文书
Golang 正则匹配效率详解
2021/04/25 Golang
Nginx 反向代理解决跨域问题多种情况分析
2022/01/18 Servers
Java实现学生管理系统(IO版)
2022/02/24 Java/Android