1

I would like to implement a tooltip beside the cursor in my tkinter GUI - specifically one that would display the x value of a matplot plot in a tk.Canvas that moves with and updates dynamically as the mouse moves.

There are some good examples (here) in creating a tooltip, however everything seems to either updating a tk.Label or create a static label popup - nothing that moves with the cursor. Matplotlib has a Cursor class (docs) but that draws lines on the plot, and doesn't display values. Tkinter also has a Cursor class (docs), but that just changes the cursor symbol over the associated widget. I am happy I can get the x value from the plot via calling Canvas.canvasx or similar and send to something associated with the mouse (or worst case, a static tk.Label somewhere)

Below is code showing the matplotlib.Cursor functionality and the tkinter.Cursor. Ideally a tooltip pops up and shows x values between 0-8000 as the mouse moves.

import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg)
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
import numpy as np


root = tk.Tk()

Fs = 8000
f = 5
sample = 8000
x = np.arange(sample)
y = np.sin(2 * np.pi * f * x / Fs)

figure = Figure(figsize=(5, 4), dpi=100)
plot = figure.add_subplot(1, 1, 1)

plot.plot(x, y, color="blue")

canvas = FigureCanvasTkAgg(figure, root)
canvas.get_tk_widget().grid(column=0, row=3,columnspan=4,pady = 4, padx=4)

# add button to demonstrate tkinter cursor function
B = tk.Button(root, text ="Cursor", relief=tk.RAISED,
              cursor="coffee_mug", width = 25)
B.grid(column = 0, row = 4, columnspan = 5, padx = 4, pady = 4)

# matplotlib cursor function
cursor = Cursor(plot, useblit=True, horizOn=False, vertOn=True,
                color="green", linewidth=2.0)

root.mainloop()
Lachlan
  • 360
  • 5
  • 14

1 Answers1

2

It seems you want to create your tooltip on the plot only. So I would suggest a slightly adapted/simplified version of this answer, ie using ax.annotate:

import tkinter as tk
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg)
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
import numpy as np


root = tk.Tk()

Fs = 8000
f = 5
sample = 8000
x = np.arange(sample)
y = np.sin(2 * np.pi * f * x / Fs)

fig = Figure(figsize=(5, 4), dpi=100)
ax = fig.add_subplot(1, 1, 1)

line, = ax.plot(x, y, color="blue")

canvas = FigureCanvasTkAgg(fig, root)
canvas.get_tk_widget().grid(column=0, row=3,columnspan=4,pady = 4, padx=4)

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

def update_annot(x, y):
    annot.xy = (x, y)
    text = "x={}\ny={}".format(*annot.xy)
    annot.set_text(text)
    annot.get_bbox_patch().set_alpha(0.4)

def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        update_annot(event.xdata,event.ydata)
        annot.set_visible(True)
        fig.canvas.draw()
    else:
        if vis:
            annot.set_visible(False)
            fig.canvas.draw()

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

# add button to demonstrate tkinter cursor function
B = tk.Button(root, text ="Cursor", relief=tk.RAISED,
              cursor="coffee_mug", width = 25)
B.grid(column = 0, row = 4, columnspan = 5, padx = 4, pady = 4)

# matplotlib cursor function
cursor = Cursor(ax, useblit=True, horizOn=False, vertOn=True,
                color="green", linewidth=2.0)

root.mainloop()

Output:

enter image description here

Tranbi
  • 11,407
  • 6
  • 16
  • 33