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实现从url中提取域名的几种方法
Sep 26 Python
go语言计算两个时间的时间差方法
Mar 13 Python
python subprocess 杀掉全部派生的子进程方法
Jan 16 Python
Linux 修改Python命令的方法示例
Dec 03 Python
python2和python3应该学哪个(python3.6与python3.7的选择)
Oct 01 Python
python 生成器和迭代器的原理解析
Oct 12 Python
python单例模式原理与创建方法实例分析
Oct 26 Python
Django 实现外键去除自动添加的后缀‘_id’
Nov 15 Python
利用django创建一个简易的博客网站的示例
Sep 29 Python
Python在线和离线安装第三方库的方法
Oct 31 Python
python如何修改文件时间属性
Feb 05 Python
对Pytorch 中的contiguous理解说明
Mar 03 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数组操作之键名比较与差集、交集赋值的方法
2014/11/10 PHP
ThinkPHP路由机制简介
2016/03/23 PHP
php实现当前页面点击下载文件的简单方法
2016/09/22 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
PHP设计模式入门之状态模式原理与实现方法分析
2020/04/26 PHP
读jQuery之十四 (触发事件核心方法)
2011/08/23 Javascript
JavaScript中的对象的extensible属性介绍
2014/12/30 Javascript
JavaScript 弹出子窗体并返回结果到父窗体的实现代码
2016/05/28 Javascript
AngularJS模块详解及示例代码
2016/08/17 Javascript
基于vue.js轮播组件vue-awesome-swiper实现轮播图
2017/03/17 Javascript
Iscrool下拉刷新功能实现方法(推荐)
2017/06/26 Javascript
webpack配置之后端渲染详解
2017/10/26 Javascript
jQuery实现动态控制页面元素的方法分析
2017/12/20 jQuery
利用vue和element-ui设置表格内容分页的实例
2018/03/02 Javascript
手把手教你用Node.js爬虫爬取网站数据的方法
2018/07/05 Javascript
webpack4.x CommonJS模块化浅析
2018/11/09 Javascript
性能优化篇之Webpack构建速度优化的建议
2019/04/03 Javascript
[54:28]EG vs OG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
在Python的Django框架中用流响应生成CSV文件的教程
2015/05/02 Python
Python实现学生成绩管理系统
2020/04/05 Python
详解Python locals()的陷阱
2019/03/26 Python
pyqt5实现绘制ui,列表窗口,滚动窗口显示图片的方法
2019/06/20 Python
Python实现获取当前目录下文件名代码详解
2020/03/10 Python
tensorflow图像裁剪进行数据增强操作
2020/06/30 Python
佛罗里达州印第安河新鲜水果:Hale Groves
2017/02/20 全球购物
软件配置管理有什么好处
2015/04/15 面试题
农村婚庆司仪主持词
2014/03/15 职场文书
2014年教师节讲话稿5篇
2014/09/10 职场文书
出国留学英文自荐信
2015/03/25 职场文书
格林童话读书笔记
2015/06/30 职场文书
关于开学的感想
2015/08/10 职场文书
谢师宴学生答谢词
2015/09/30 职场文书
大学生活委员竞选稿
2015/11/21 职场文书
2016年师德师风学习心得体会
2016/01/12 职场文书
苹果可能正在打击不进行更新的 App
2022/04/24 数码科技