Skip to content Skip to sidebar Skip to footer

How To Have A Fast Crosshair Mouse Cursor For Subplots In Matplotlib?

In this video of backtrader's matplotlib implementation https://youtu.be/m6b4Ti4P2HA?t=2008 I can see that a default and very fast and CPU saving crosshair mouse cursor seems to ex

Solution 1:

You can create a crosshair cursor via mplcursors. sel.extras.append() takes care that the old cursor is removed when a new is drawn. With sel.annotation.set_text you can adapt the popup annotation shown. To leave out the annotation, use sel.annotation.set_visible(False). To find the corresponding y-value in the other subplot, np.interp with the data extracted from the curve can be used.

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

defcrosshair(sel):
    x, y2 = sel.target
    y1 = np.interp( sel.target[0],   plot1.get_xdata(), plot1.get_ydata() )
    sel.annotation.set_text(f'x: {x:.2f}\ny1: {y1:.2f}\ny2: {y2:.2f}')
    # sel.annotation.set_visible(False)
    hline1 = ax1.axhline(y1, color='k', ls=':')
    vline1 = ax1.axvline(x, color='k', ls=':')
    vline2 = ax2.axvline(x, color='k', ls=':')
    hline2 = ax2.axhline(y2, color='k', ls=':')
    sel.extras.append(hline1)
    sel.extras.append(vline1)
    sel.extras.append(hline2)
    sel.extras.append(vline2)

fig = plt.figure(figsize=(15, 10))
ax1 = plt.subplot(2, 1, 1)
ax2 = plt.subplot(2, 1, 2, sharex=ax1)

plot1, = ax1.plot(np.array(np.random.uniform(-1, 1, 100).cumsum()))
plot2, = ax2.plot(np.array(np.random.uniform(-1, 1, 100).cumsum()))

cursor = mplcursors.cursor(plot2, hover=True)
cursor.connect('add', crosshair)

plt.show()

example plot

Here is an alternative implementation that stores the data in global variables and moves the lines (instead of deleting and recreating them):

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

defcrosshair(sel):
    x = sel.target[0]
    y1 = np.interp(x, plot1x, plot1y)
    y2 = np.interp(x, plot2x, plot2y)
    sel.annotation.set_visible(False)
    hline1.set_ydata([y1])
    vline1.set_xdata([x])
    hline2.set_ydata([y2])
    vline2.set_xdata([x])
    hline1.set_visible(True)
    vline1.set_visible(True)
    hline2.set_visible(True)
    vline2.set_visible(True)

fig = plt.figure(figsize=(15, 10))
ax1 = plt.subplot(2, 1, 1)
ax2 = plt.subplot(2, 1, 2, sharex=ax1)

plot1, = ax1.plot(np.array(np.random.uniform(-1, 1, 100).cumsum()))
plot2, = ax2.plot(np.array(np.random.uniform(-1, 1, 100).cumsum()))

plot1x = plot1.get_xdata()
plot1y = plot1.get_ydata()
plot2x = plot2.get_xdata()
plot2y = plot2.get_ydata()
hline1 = ax1.axhline(plot1y[0], color='k', ls=':', visible=False)
vline1 = ax1.axvline(plot1x[0], color='k', ls=':', visible=False)
hline2 = ax2.axhline(plot2y[0], color='k', ls=':', visible=False)
vline2 = ax2.axvline(plot2x[0], color='k', ls=':', visible=False)

cursor = mplcursors.cursor([plot1, plot2], hover=True)
cursor.connect('add', crosshair)

plt.show()

Post a Comment for "How To Have A Fast Crosshair Mouse Cursor For Subplots In Matplotlib?"