3

我正在尝试获得 2 个不同变量的散点图,一组散点是在空气阻力影响下弹丸的高度值,一个是没有空气阻力的弹丸。我可以使用一组散点,但不能同时使用这两个散点。我正在使用mplcursors 库在将鼠标悬停在一个点上时显示注释标签。这是相关代码:

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

# ...

fig, ax = plt.subplots()
nair_scatter = ax.scatter(nairRangeValues, nairHeightValues, c="blue", label="No air resistance", s=3)
air_scatter = ax.scatter(airRangeValues, airHeightValues, c="red", label="Air resistance", s=3)
ax.legend()
plt.xlabel("Range", size=10)
plt.ylabel("Height", size=10)

crs = mplcursors.cursor(ax,hover=True)
crs.connect("add", lambda sel: sel.annotation.set_text(
        'Range {} m\nHeight {} m\nVelocity {} m/s at angle {} degrees\nDisplacement {} m\nTime of flight {} s' .format(
        (sel.target[0]), (sel.target[1]),
        (airVelocityValues[get_index(airRangeValues, sel.target[0])]),
        (airAngleValues[get_index(airRangeValues, sel.target[0])]),
        (airDisplacementValues[get_index(airRangeValues, sel.target[0])]),
        (airTimeValues[get_index(airRangeValues, sel.target[0])]) ) ) )

crs2 = mplcursors.cursor(ax,hover=True)
crs2.connect("add", lambda ok: ok.annotation.set_text(
        'Range {} m\nHeight {} m' .format(ok.target[0], ok.target[1])))
plt.show()

这有一些问题。首先,它给了我一个巨大的错误,并StopIteration在最后说。另一个是它在一组散点上显示了正确的标签,但也显示了同一散点图的 crs2 值,而不是另一个。如果有人可以帮助我欣赏它,我不知道如何让他们能够对每个散点集都是独一无二的。

4

1 回答 1

3

不要将光标连接到斧头,而是尝试仅将它们连接到它们所属的散点图。的第一个参数mplcursors.cursor就是为了这个。

您会注意到,当您从另一组移到一个点时,前一个的注释不会被删除。因此,我添加了一些代码以在打开新注释时删除另一个注释。

请注意,您可以通过 直接访问索引sel.target.index。使用错误集合点调用get_index(airRangeValues, ...)可能是您遇到错误的原因。

这是一些演示原理的代码。注释的背景颜色设置不同,以更好地说明正在显示的光标。此外,更改了 alpha 以方便阅读文本。

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

def cursor1_annotations(sel):
    sel.annotation.set_text(
        'Cursor One:\nRange {:.2f} m\nHeight {:.2f} m\nindex: {}'.format(sel.target[0], sel.target[1], sel.target.index))
    sel.annotation.get_bbox_patch().set(fc="powderblue", alpha=0.9)
    for s in crs2.selections:
        crs2.remove_selection(s)

def cursor2_annotations(sel):
    sel.annotation.set_text(
        'Cursor Two:\nRange {:.2f} m\nHeight {:.2f} m\nindex: {}'.format(sel.target[0], sel.target[1], sel.target.index))
    sel.annotation.get_bbox_patch().set(fc="lightsalmon", alpha=0.9)
    for s in crs1.selections:
        crs1.remove_selection(s)

N = 100
nairRangeValues = np.random.normal(30, 10, N)
nairHeightValues = np.random.uniform(40, 100, N)
airRangeValues = np.random.normal(40, 10, N)
airHeightValues = np.random.uniform(50, 120, N)

fig, ax = plt.subplots()

nair_scatter = ax.scatter(nairRangeValues, nairHeightValues, c="blue", label="No air resistance", s=3)
air_scatter = ax.scatter(airRangeValues, airHeightValues, c="red", label="Air resistance", s=3)
ax.legend()
plt.xlabel("Range", size=10)
plt.ylabel("Height", size=10)

crs1 = mplcursors.cursor(nair_scatter, hover=True)
crs1.connect("add", cursor1_annotations)
crs2 = mplcursors.cursor(air_scatter, hover=True)
crs2.connect("add", cursor2_annotations)

plt.show()

示例图

PS:也可以仅使用一个光标并添加测试来实现类似的效果。在这种情况下,无需手动删除另一个光标:

def cursor_annotations(sel):
    if sel.artist == nair_scatter:
        sel.annotation.set_text(
            'Cursor One:\nRange {:.2f} m\nHeight {:.2f} m\nindex: {}'.format(sel.target[0], sel.target[1], sel.target.index))
        sel.annotation.get_bbox_patch().set(fc="powderblue", alpha=0.9)
    else:
        sel.annotation.set_text(
            'Cursor Two:\nRange {:.2f} m\nHeight {:.2f} m\nindex: {}'.format(sel.target[0], sel.target[1], sel.target.index))
        sel.annotation.get_bbox_patch().set(fc="lightsalmon", alpha=0.9)

crs = mplcursors.cursor([nair_scatter, air_scatter], hover=True)
crs.connect("add", cursor_annotations)
于 2020-01-18T18:35:23.950 回答