pythonmatplotlibmplcursors

Changing type of annotation in mplcursors on matplotlib


The current format

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import ScalarFormatter
import mplcursors as mpl

class Compound():
    def accumulation(i,t):
        return (1+i)**t
    def discount(i,t):
        return (1-i)**(-t)
    
years= np.linspace(1,1000,12000)

%matplotlib widget

fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))

plt.plot(years,0.93*Compound.accumulation(0.0225,years))
plt.title('Interest')

mpl.cursor(hover=True).annotation_kwargs

I'm using a Jupiter notebook and I want to change the scientific format in the annotation that mplcursors creates when the cursor hovers above the lines


Solution

  • The mplcursors package uses the matplotlib Axes.format_coord to set the style of the formatters in the annotation box. So, you can define your own format_coord function and use that instead (see, e.g., here).

    For example,

    import matplotlib.pyplot as plt
    import numpy as np
    from matplotlib.ticker import ScalarFormatter
    import mplcursors as mpl
    
    
    class Compound():
        def accumulation(i, t):
            return (1 + i)**t
        def discount(i, t):
            return (1 - i)**(-t)
        
    years = np.linspace(1, 1000, 12000)
    
    
    def format_coord(x, y):
        # output numbers (not in scientific notation) with one decimal place
        return f"x={x:.1f}, y={y:.1f}"
    
    
    fig, ax = plt.subplots()
    ax.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
    
    ax.plot(years, 0.93 * Compound.accumulation(0.0225, years))
    ax.set_title("Interest")
    
    # switch axes format_coord function to your own 
    ax.format_coord = format_coord
    
    mpl.cursor(hover=True)
    
    plt.show()
    

    Unfortunately, this doesn't seem to work with LaTeX/MathText style strings enclosed in $ signs, e.g., using:

    def format_coord(x, y):
        yscale = int(np.log10(y))
        
        # return LaTeX style scientific notation
        return rf"x={x:1.1f}, y=${y / 10**yscale:1.1f} \times 10^{yscale}$"
    

    keeps the dollars and does not render it as an equation. Doing that may required a more in-depth hack.