将鼠标悬停在matplotlib中的某个点上时,是否可以显示标签?

jdm*_*cbr 120 python matplotlib

我使用matplotlib制作散点图.散点图上的每个点都与命名对象相关联.当我将光标悬停在与该对象关联的散点图上的点上时,我希望能够看到对象的名称.特别是,能够快速查看异常点的名称会很好.我在这里搜索时能够找到的最接近的东西是annotate命令,但这似乎在图上创建了一个固定的标签.不幸的是,根据我拥有的点数,如果我标记了每个点,散点图将是不可读的.有没有人知道创建只在光标悬停在该点附近时出现的标签的方法?

Imp*_*est 95

似乎这里的其他答案都没有实际回答这个问题.因此,这是一个使用散点图的代码,并在将鼠标悬停在散点图上时显示注释.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

x = np.random.rand(15)
y = np.random.rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)

norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn

fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)

annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):

    pos = sc.get_offsets()[ind["ind"][0]]
    annot.xy = pos
    text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))), 
                           " ".join([names[n] for n in ind["ind"]]))
    annot.set_text(text)
    annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont, ind = sc.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

因为人们突然也想要将这个解决方案用于行plot而不是分散,所以以下将是相同的解决方案plot(其工作方式略有不同).

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

x = np.sort(np.random.rand(15))
y = np.sort(np.random.rand(15))
names = np.array(list("ABCDEFGHIJKLMNO"))

norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn

fig,ax = plt.subplots()
line, = plt.plot(x,y, marker="o")

annot = ax.annotate("", xy=(0,0), xytext=(-20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def update_annot(ind):
    x,y = line.get_data()
    annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]])
    text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))), 
                           " ".join([names[n] for n in ind["ind"]]))
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(0.4)


def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont, ind = line.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()
Run Code Online (Sandbox Code Playgroud)

如果有人正在寻找条形图的解决方案,请参考例如这个答案.

  • @Konstantin 是的,当在 IPython/Jupyter 笔记本中使用 `%matplotlib notebook` 时,此解决方案将起作用。 (6认同)
  • @OriolAbril(以及其他所有人),如果您在修改此答案中的代码时遇到问题,请提出相关问题,链接到此答案并显示您尝试过的代码。如果没有实际看到,我无法知道您的每个代码有什么问题。 (2认同)

小智 65

我知道这是一个老问题,但我一直在寻找悬停(不是点击)一条线的解决方案.

import matplotlib.pyplot as plt

# Need to create as global variable so our callback(on_plot_hover) can access
fig = plt.figure()
plot = fig.add_subplot(111)

# create some curves
for i in range(4):
    # Giving unique ids to each data member
    plot.plot(
        [i*1,i*2,i*3,i*4],
        gid=i)

def on_plot_hover(event):
    # Iterating over each data member plotted
    for curve in plot.get_lines():
        # Searching which data member corresponds to current mouse position
        if curve.contains(event)[0]:
            print "over %s" % curve.get_gid()

fig.canvas.mpl_connect('motion_notify_event', on_plot_hover)           
plt.show()
Run Code Online (Sandbox Code Playgroud)

  • 这会在悬停时将标签打印到控制台中.**当悬停时**使标签出现在图片上**怎么样?我明白这是个问题. (9认同)
  • 嗯 - 这对我来说不是开箱即用的(用matplotlib`做的事情很少......) - 这对`ipython` /`jupyter`笔记本有用吗?当有多个子图时它是否也有效?在条形图而不是折线图上怎么样? (5认同)
  • 非常有用+1ed。您可能需要对此进行“去抖动”,因为对于曲线区域内的运动,motion_notify_event 将重复。简单地检查曲线对象是否等于前一条曲线似乎有效。 (3认同)

cyb*_*org 35

来自http://matplotlib.sourceforge.net/examples/event_handling/pick_event_demo.html:

from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import rand


if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)

    x, y, c, s = rand(4, 100)
    def onpick3(event):
        ind = event.ind
        print 'onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind)

    fig = figure()
    ax1 = fig.add_subplot(111)
    col = ax1.scatter(x, y, 100*s, c, picker=True)
    #fig.savefig('pscoll.eps')
    fig.canvas.mpl_connect('pick_event', onpick3)

show()
Run Code Online (Sandbox Code Playgroud)


Yuc*_*ang 17

如果你使用 jupyter notebook,我的解决方案很简单:

%pylab
import matplotlib.pyplot as plt
import mplcursors
plt.plot(...)
mplcursors.cursor(hover=True)
plt.show()
Run Code Online (Sandbox Code Playgroud)

你可以得到类似的东西 在此处输入图片说明

  • 到目前为止最好的解决方案,只需几行代码就可以完全满足OP的要求 (2认同)
  • 这不限于jupyter是什么?它可以在普通的 python 中工作。 (2认同)

tex*_*ood 13

http://matplotlib.org/users/shell.html中提供的示例进行了轻微编辑:

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click on points')

line, = ax.plot(np.random.rand(100), '-', picker=5)  # 5 points tolerance

def onpick(event):
    thisline = event.artist
    xdata = thisline.get_xdata()
    ydata = thisline.get_ydata()
    ind = event.ind
    print 'onpick points:', zip(xdata[ind], ydata[ind])

fig.canvas.mpl_connect('pick_event', onpick)

plt.show()
Run Code Online (Sandbox Code Playgroud)

正如Sohaib所问,这绘制了一条直线图


Far*_*igo 10

其他答案没有满足我在最新版本的 Jupyter 内联 matplotlib 图中正确显示工具提示的需求。这个虽然有效:

import matplotlib.pyplot as plt
import numpy as np
import mplcursors
np.random.seed(42)

fig, ax = plt.subplots()
ax.scatter(*np.random.random((2, 26)))
ax.set_title("Mouse over a point")
crs = mplcursors.cursor(ax,hover=True)

crs.connect("add", lambda sel: sel.annotation.set_text(
    'Point {},{}'.format(sel.target[0], sel.target[1])))
plt.show()
Run Code Online (Sandbox Code Playgroud)

用鼠标越过一个点时,会出现如下图所示的内容: 在此处输入图片说明

  • 这个(未署名)的来源是 https://mplcursors.readthedocs.io/en/stable/examples/hover.html (6认同)
  • 我无法在 jupyter 实验室中使用它。它可能在 jupyter 笔记本中工作,但在 jupyter 实验室中不起作用吗? (2认同)

Jul*_*ian 5

mpld3为我解决。编辑(添加代码):

import matplotlib.pyplot as plt
import numpy as np
import mpld3

fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE'))
N = 100

scatter = ax.scatter(np.random.normal(size=N),
                 np.random.normal(size=N),
                 c=np.random.random(size=N),
                 s=1000 * np.random.random(size=N),
                 alpha=0.3,
                 cmap=plt.cm.jet)
ax.grid(color='white', linestyle='solid')

ax.set_title("Scatter Plot (with tooltips!)", size=20)

labels = ['point {0}'.format(i + 1) for i in range(N)]
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
mpld3.plugins.connect(fig, tooltip)

mpld3.show()
Run Code Online (Sandbox Code Playgroud)

您可以检查这个例子

  • 不幸的是,截至2017年7月,mpld3不再得到积极维护 (5认同)

Ena*_*yat 5

mplcursors 为我工作。mplcursors 为 matplotlib 提供可点击的注释。它深受 mpldatacursor ( https://github.com/joferkington/mpldatacursor ) 的启发,具有大大简化的 API

import matplotlib.pyplot as plt
import numpy as np
import mplcursors

data = np.outer(range(10), range(1, 5))

fig, ax = plt.subplots()
lines = ax.plot(data)
ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n"
             "Annotations can be dragged.")

mplcursors.cursor(lines) # or just mplcursors.cursor()

plt.show()
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

87175 次

最近记录:

6 年 前