使用 matplotlib 从图中获取数据

2024-01-31

我在 python 中使用 matplotlib 来构建散点图。

假设我有以下 2 个数据列表。

X=[1,2,3,4,5]

Y=[6,7,8,9,10]

然后我使用X作为X轴值,Y作为Y轴值来绘制散点图。所以我会有一张上面有 5 个散射点的图片,对吧?

现在的问题是:是否可以将这 5 个点与实际数据建立联系。例如,当我点击这5个点中的一个时,它可以告诉我我用了哪些原始数据来做出这个点?

提前致谢


使用稍微修改过的版本乔·金顿的数据光标 https://stackoverflow.com/a/4674445/190597:

import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.cbook as cbook
import numpy as np

def fmt(x, y):
    return 'x: {x:0.2f}\ny: {y:0.2f}'.format(x = x, y = y)

class DataCursor(object):
    # https://stackoverflow.com/a/4674445/190597
    """A simple data cursor widget that displays the x,y location of a
    matplotlib artist when it is selected."""
    def __init__(self, artists, x = [], y = [], tolerance = 5, offsets = (-20, 20),
                 formatter = fmt, display_all = False):
        """Create the data cursor and connect it to the relevant figure.
        "artists" is the matplotlib artist or sequence of artists that will be 
            selected. 
        "tolerance" is the radius (in points) that the mouse click must be
            within to select the artist.
        "offsets" is a tuple of (x,y) offsets in points from the selected
            point to the displayed annotation box
        "formatter" is a callback function which takes 2 numeric arguments and
            returns a string
        "display_all" controls whether more than one annotation box will
            be shown if there are multiple axes.  Only one will be shown
            per-axis, regardless. 
        """
        self._points = np.column_stack((x,y))
        self.formatter = formatter
        self.offsets = offsets
        self.display_all = display_all
        if not cbook.iterable(artists):
            artists = [artists]
        self.artists = artists
        self.axes = tuple(set(art.axes for art in self.artists))
        self.figures = tuple(set(ax.figure for ax in self.axes))

        self.annotations = {}
        for ax in self.axes:
            self.annotations[ax] = self.annotate(ax)

        for artist in self.artists:
            artist.set_picker(tolerance)
        for fig in self.figures:
            fig.canvas.mpl_connect('pick_event', self)

    def annotate(self, ax):
        """Draws and hides the annotation box for the given axis "ax"."""
        annotation = ax.annotate(self.formatter, xy = (0, 0), ha = 'right',
                xytext = self.offsets, textcoords = 'offset points', va = 'bottom',
                bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
                arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')
                )
        annotation.set_visible(False)
        return annotation

    def snap(self, x, y):
        """Return the value in self._points closest to (x, y).
        """
        idx = np.nanargmin(((self._points - (x,y))**2).sum(axis = -1))
        return self._points[idx]
    def __call__(self, event):
        """Intended to be called through "mpl_connect"."""
        # Rather than trying to interpolate, just display the clicked coords
        # This will only be called if it's within "tolerance", anyway.
        x, y = event.mouseevent.xdata, event.mouseevent.ydata
        annotation = self.annotations[event.artist.axes]
        if x is not None:
            if not self.display_all:
                # Hide any other annotation boxes...
                for ann in self.annotations.values():
                    ann.set_visible(False)
            # Update the annotation in the current axis..
            x, y = self.snap(x, y)
            annotation.xy = x, y
            annotation.set_text(self.formatter(x, y))
            annotation.set_visible(True)
            event.canvas.draw()

x=[1,2,3,4,5]
y=[6,7,8,9,10]

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
scat = ax.scatter(x, y)
DataCursor(scat, x, y)
plt.show()

yields

您可以单击任何点,气球将显示基础数据值。


我对 DataCursor 的轻微修改是添加snap方法,确保显示的数据点来自原始数据集,而不是鼠标实际点击的位置。


如果您安装了 scipy,您可能更喜欢这个版本的光标,它使气球跟随鼠标(无需单击):

import datetime as DT
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
import scipy.spatial as spatial

def fmt(x, y, is_date):
    if is_date:
        x = mdates.num2date(x).strftime("%Y-%m-%d")
        return 'x: {x}\ny: {y}'.format(x=x, y=y)
    else:
        return 'x: {x:0.2f}\ny: {y:0.2f}'.format(x=x, y=y)


class FollowDotCursor(object):
    """Display the x,y location of the nearest data point."""
    def __init__(self, ax, x, y, tolerance=5, formatter=fmt, offsets=(-20, 20)):
        try:
            x = np.asarray(x, dtype='float')
            self.is_date = False
        except (TypeError, ValueError):
            x = np.asarray(mdates.date2num(x), dtype='float')
            self.is_date = True
        y = np.asarray(y, dtype='float')
        self._points = np.column_stack((x, y))
        self.offsets = offsets
        self.scale = x.ptp()
        self.scale = y.ptp() / self.scale if self.scale else 1
        self.tree = spatial.cKDTree(self.scaled(self._points))
        self.formatter = formatter
        self.tolerance = tolerance
        self.ax = ax
        self.fig = ax.figure
        self.ax.xaxis.set_label_position('top')
        self.dot = ax.scatter(
            [x.min()], [y.min()], s=130, color='green', alpha=0.7)
        self.annotation = self.setup_annotation()
        plt.connect('motion_notify_event', self)

    def scaled(self, points):
        points = np.asarray(points)
        return points * (self.scale, 1)

    def __call__(self, event):
        ax = self.ax
        # event.inaxes is always the current axis. If you use twinx, ax could be
        # a different axis.
        if event.inaxes == ax:
            x, y = event.xdata, event.ydata
        elif event.inaxes is None:
            return
        else:
            inv = ax.transData.inverted()
            x, y = inv.transform([(event.x, event.y)]).ravel()
        annotation = self.annotation
        x, y = self.snap(x, y)
        annotation.xy = x, y
        annotation.set_text(self.formatter(x, y, self.is_date))
        self.dot.set_offsets((x, y))
        bbox = ax.viewLim
        event.canvas.draw()

    def setup_annotation(self):
        """Draw and hide the annotation box."""
        annotation = self.ax.annotate(
            '', xy=(0, 0), ha = 'right',
            xytext = self.offsets, textcoords = 'offset points', va = 'bottom',
            bbox = dict(
                boxstyle='round,pad=0.5', fc='yellow', alpha=0.75),
            arrowprops = dict(
                arrowstyle='->', connectionstyle='arc3,rad=0'))
        return annotation

    def snap(self, x, y):
        """Return the value in self.tree closest to x, y."""
        dist, idx = self.tree.query(self.scaled((x, y)), k=1, p=1)
        try:
            return self._points[idx]
        except IndexError:
            # IndexError: index out of bounds
            return self._points[0]

x = [DT.date.today()+DT.timedelta(days=i) for i in [10,20,30,40,50]]
y = [6,7,8,9,10]

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x, y)
cursor = FollowDotCursor(ax, x, y)
fig.autofmt_xdate()
plt.show()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 matplotlib 从图中获取数据 的相关文章

随机推荐

  • 从 JAVA MySQLdb 导入调用 Python 脚本

    我正在从 Java 代码调用 Python 脚本 这是代码 import java io BufferedReader import java io IOException import java io InputStreamReader
  • 有没有办法使用 lapply 生成由列表中的列表中的元素组成的数据框?

    我想在列表中的列表内索引向量 并生成一个新的数据帧 其中在每行的每个列表中包含该特定向量 我之前考虑过使用 for 循环来做到这一点 a list odds c 1 3 5 7 evens c 2 4 6 8 name name1 b li
  • 对于单元测试来说,慢到什么程度算太慢?

    迈克尔 费瑟斯有效地处理遗留代码 第 13 14 页提到 单元测试需要 1 10 第二个运行是一个缓慢的单元测试 如果 单元测试 运行得不快 他们 不是单元测试 我可以理解为什么如果有 30 000 个测试 1 10 秒就太慢了 因为运行需
  • 如何从jqgrid中的dataurl获取行id或参数以创建动态选择列表来编辑行

    我有一个 ASP NET 网站 其 C 后端使用 Jqgrid 我希望用户能够选择网格中的项目进行编辑 可编辑的字段之一将作为下拉选择列表呈现给用户 其中仅包含对该用户有效的选项 例如 假设我有一个显示人员的网格 如果编辑 person1
  • Activity 无法设置在其范围内定义的变量?

    这让我摸不着头脑 我想知道我是否理解正确 我试图在活动中定义一个可供子活动使用的变量 父级应该能够在运行时在此变量中设置一个值 这是精简的 Parent 类 public sealed class Parent NativeActivity
  • 如何将犰狳与 Eclipse 链接

    我想将犰狳与 Eclipse 一起使用 然而 链接犰狳的所有说明都是针对 Visual Studio 给出的 现在我按照自述文件中概述的说明进行操作犰狳图书馆 http arma sourceforge net download html
  • DBus如何启动服务

    我很好奇如何为 DBus 启动自己的服务 在官方网站上 我找到了很多有关从客户端角度使用 DBus 服务的信息 但如何启动和开发服务还不够 1 接口文件ServiceName xml应该位于哪里 2 服务文件ServiceName serv
  • Firefox 扩展:取消请求并发出虚假响应

    我正在尝试开发一个 Firefox 扩展 它可以丢弃对某个站点的每个 HTTP 请求并返回一个虚假响应 任何请求都不应到达原始 Web 服务器 但我希望能够创建自定义响应 我尝试拦截 http on modify request 消息 但取
  • 基于Web服务实现快速更新行标签

    我有一个包含 7 行的表视图 周一 周二 周日 我的应用程序从 Web 服务接收一个 json 其格式为 appointments numApts 1 scheduleDate 2015 11 02 numApts 2 scheduleDa
  • C# 将 int 转换为字符串并填充零?

    在 C 中 我有一个整数值需要转换为字符串 但需要在之前添加零 例如 int i 1 当我将它转换为字符串时 它需要变成 0001 我需要了解 C 中的语法 i ToString PadLeft 4 0 好的 但不适用于负数 i ToStr
  • 如何更改 UISearchBar 字体大小和颜色?

    我已经用谷歌搜索了几个小时如何更改我的 UISearchBar 字体大小和颜色 但我无法找到任何与之相关的文档 这是我到目前为止在 swift 4 上所做的 searchBar UISearchBar frame CGRect x 0 y
  • 为什么可以在同一个类中创建的另一个线程中访问局部变量?

    我真的找不到关于这个确切主题的任何内容 所以如果问题已经存在 请引导我走向正确的方向 根据我对 NET 的了解 不可能跨不同线程访问变量 如果该语句错误 请纠正我 这只是我在某处读到的内容 然而 现在在这个代码示例中 它似乎不应该工作 cl
  • 将背景颜色设置为 HighChart xAxis 标签

    如何为 HighChart xAxis 标签设置背景颜色 我尝试了以下但没有运气 x轴 类别 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 标签 旋转 90 风格 颜色 89A54E 填写 000 背景颜色 F
  • 导航到“url”,等待“load” - Python Playwright Issue

    嘿 我在 python playwright 中有用于获取页面源代码的代码 import json import sys import bs4 import urllib parse from bs4 import BeautifulSou
  • 悬停后保持下拉菜单打开(CSS)

    我创建了一个水平菜单 当您将鼠标悬停在某个项目上时 会出现一个下拉菜单 这一切都很好 但是 当您离开菜单项 使用下拉菜单 时 下拉菜单就会消失 我知道这是因为你不再悬停它 但我该如何解决这个问题 注意 我不希望下拉菜单直接位于其下方 我希望
  • 无法在 Angularjs 中使用 templateUrl 加载模板

    我刚刚学习 Angularjs 以及如何使用 templateUrl 加载模板 我有一个简单的指令 var mainApp angular module mainApp mainApp directive request function
  • 如何将文本区域的标签对齐到顶部?

    我确实有一个表格数据 如下所示 td td
  • 空字符串而不是不匹配的组错误

    我有这段代码 for n in range 1 10 new re sub r regex group regex regex r something str n r 1 old count 1 它会抛出不匹配的组错误 但如果它不匹配 我想
  • 启用 Vuforia 时 Unity 崩溃

    在 XR 设置中启用 Vuforia 增强现实支持 时 我的编辑器崩溃 以下是我遵循的步骤 重现步骤 1 创建一个新项目 2 文件 gt 构建设置 gt 播放器设置 gt 播放器 3 从 XR 设置中启用 Vuforia 增强现实 复选框
  • 使用 matplotlib 从图中获取数据

    我在 python 中使用 matplotlib 来构建散点图 假设我有以下 2 个数据列表 X 1 2 3 4 5 Y 6 7 8 9 10 然后我使用X作为X轴值 Y作为Y轴值来绘制散点图 所以我会有一张上面有 5 个散射点的图片 对吧