'In matplotlib, how can I create fast and rich tooltips?
I have an app that uses matplotlib to plot a large number of data points (15,000 or more). Using the commonly-recommended approach of the matplotlib feature annotate, the resulting tooltips are slow to display, often prompting the blue "waiting" circle in Windows. I would also like an easy way to display rich text in these tooltips.
Here is a example program drawing 30,000 data points, and using annotate for tooltips:
# matplotlib_tooltip_slow.py: show a tooltip for plot item using plot annotation
import numpy as np
import matplotlib.pyplot as plt
from PyQt5.QtWidgets import QToolTip
fig = None
artist = None
fig = plt.figure("circle_plots", figsize=(12, 6))
ax = fig.add_subplot(1, 1, 1)
count = 30000
x = np.random.rand(count)
y = np.random.rand(count)
area = (4 * np.random.rand(count))**2
artist = ax.scatter(x, y, s=area, color="blue", alpha=0.5, facecolors='none')
# create tooltip control (annotation)
annot = ax.annotate("", xy=(0,0), xytext=(5,5), textcoords="offset points", bbox=dict(boxstyle="round", fc="w"))
annot.set_visible(False)
def set_tooltip(text):
if text:
annot.set_text(text)
annot.set_visible(True)
else:
annot.set_visible(False)
fig.canvas.draw_idle()
def hover(event):
cont, ind = artist.contains(event)
if cont and len(ind):
indexes = list(ind["ind"])
# set position of annotation to the first plot item in our list
annot.xy = artist.get_offsets()[indexes[0]]
text = "\n".join(["Name: item{}, Area: {:.0f}".format(i, area[i]) for i in indexes])
else:
text = ""
set_tooltip(text)
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
Solution 1:[1]
I have found that the underlying GUI framework offers tooltips for the window associated with the matplotlib figure, and they are fast and support HTML for rich text. Here is a new version of the example program, where the annotate creation has been removed, and the set_tooltip() function rewritten using the underlying pyqt5 framework's tooltip. The result is faster displaying tooltips that display rich text:
# matplotlib_tooltip_fast.py: show a tooltip for plot item using pyqt5 tooltip
import numpy as np
import matplotlib.pyplot as plt
from PyQt5.QtWidgets import QToolTip
fig = None
artist = None
fig = plt.figure("circle_plots", figsize=(12, 6))
ax = fig.add_subplot(1, 1, 1)
count = 30000
x = np.random.rand(count)
y = np.random.rand(count)
area = (4 * np.random.rand(count))**2
artist = ax.scatter(x, y, s=area, color="blue", alpha=0.5, facecolors='none')
def set_tooltip(text):
win = fig.canvas.window()
if text:
win.setToolTip(text)
else:
win.setToolTip(text)
QToolTip.hideText()
def hover(event):
cont, ind = artist.contains(event)
if cont and len(ind):
indexes = list(ind["ind"])
text = "<br>".join(["<b>Name:</b> item{}, <b>Area</b>: {:.0f}".format(i, area[i]) for i in indexes])
else:
text = ""
set_tooltip(text)
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
Here is a screenshot of the resulting plot with a rich tooptip:

Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
