How To Use Two Mplcursors Simultaneously For A Scatter Plot Of Two Sets?
Solution 1:
Instead of connecting the cursors to the ax, try connecting them only to the scatter plot they belong to. The first parameter of mplcursors.cursor
is meant for just that.
You'll notice that when you move to a point from the other set, that the annotation of the previous one is not removed. Therefore, I added some code to remove the other annotation when a new one is opened.
Note that you can directly access the index via sel.target.index
. Calling get_index(airRangeValues, ...)
with a point of the wrong set could be a cause of the error you encountered.
Here's some code to demonstrate the principles. The backgroundcolor of the annotations is set differently to better illustrate which cursor is being displayed. Also, the alpha is changed to ease reading the text.
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: Something similar can also be achieved using only one cursor and adding a test. In that case there is no need to manually remove the other cursor:
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)
Post a Comment for "How To Use Two Mplcursors Simultaneously For A Scatter Plot Of Two Sets?"