# Why do Tooltips slow down Dynamic so much? Is there a faster alternative?

I'm working on a Dynamic ListPlot with a few thousand plots, and it seems that wrapping the points with Tooltip slows the Dynamic responsiveness substantially. With the simple example below, dragging the Slider is sluggish. If you change the Show line from "plot1" to "plot2", the Slider response is smooth. Notice that the ListPlot and Tooltips are not being modified by the Control. Maybe Show is muddling things when it combines the graphics, but still, the slowdown doesn't make sense to me, since Tooltip isn't active during the drag, and isn't changing in any way.

x = Table[RandomVariate[NormalDistribution[0, .5], 2], {i, 5000}];
boxPts[x_] := {{x, x}, {-x, x}, {-x, -x}, {x, -x}};
plot1 = ListPlot[MapIndexed[Tooltip[#1, First[#2]] &, x]];
plot2 = ListPlot[x];
Control[{{z, .5}, 0, 1.5}]
overlay = Graphics[{Opacity[.2],
FilledCurve[{{Line[boxPts[1.5]]}, {Dynamic[Line[boxPts[z]]]}}]}];
Show[overlay, plot1, PlotRange -> 1.5, AspectRatio -> 1]


I'd prefer to be able to use Tooltip, if it's fixable, or at least understand why it's so slow. I'd also be interested in any alternative methods for doing mouseover-style feedback, which could show up inside or outside the plot area. Thank you!

(This is in Mma 9.0.1 on OSX 10.8.5, on a 2012 MBP.)

Update: I noticed that if I execute the Control line after the Show line with plot1, the Slider works smoothly. I then noticed that merely moving the cursor away to a new point can make the Control work normally. This only makes a difference with the plot that has Tooltips, since the other is always smooth.

-
you haven't defined boxPts so this cannot be tested. – Mike Honeychurch May 19 '14 at 4:32
Thanks, fixed it! Less thanks to whoever downvoted it. I did research it, and attempted to make it useful and clear. – Joe Fusion May 19 '14 at 4:54
I do not see it slowing down so much on my end. M 9.01, windows 7. Yes, the slider is tiny bit less smooth, but you have one plot with 5000 tooltips and another without? – Nasser May 19 '14 at 5:54
Mma 9.0.1 Mac 10.9.2 worked fine for me. I think you need to tell us what version of the operating system you are using. – Mike Honeychurch May 19 '14 at 6:00
This is on 10.8.5, on a 2012 MBP. It appears to be a frontend UI quirk, based on the Update I added above. Having the cursor (text entry focus) next to the Tooltip'd output is slow. Move the cursor, or remove the Tooltips, and it's not slow. I don't think it's merely the number of objects (as @Nasser said), since I can move the cursor and see improvement, or have many more objects with Tooltips. For anyone not seeing the problem, you might try cranking up the number of points, to account for differences in hardware speed. – Joe Fusion May 19 '14 at 16:00

This is a very common problem for people who work on data analysis. Here as a solution to the problem using LocatorPane and a few other functions and tricks.

    TooltipListPlot[data_, tipFunction_, listPlotOptions___] := DynamicModule[
{displayQ = False, yRange , xRange, pt, minX, maxX, minY, maxY, tip, threshold, tipPosition, nf, dataPoints, dataAsRulesQ = Head@data[[1]]===Rule}
,
dataPoints := If[dataAsRulesQ, #[[1]]&/@data, data];
nf = Nearest@data;
{maxY, minY} = {Max[#], Min[#]} &@dataPoints[[All, 2]];
{maxX, minX} = {Max[#], Min[#]} &@dataPoints[[All, 1]];
pt = {maxX, maxY}*2;
yRange = maxY - minY ;
xRange = maxX - minX;
tipPosition[point_] := {
Which[point[[1]] < minX + 0.1 xRange,
Left
,point[[1]] > maxX - 0.1 xRange,
Right
,True,
Center
]
,
Which[point[[2]] < minY + 0.1 yRange,
Bottom
,point[[2]] > maxY - 0.1 yRange,
Top
,True,
Top
]
};
threshold = EuclideanDistance[{minX, minY}, {maxX, maxY}]/100.;
LocatorPane[Dynamic[pt,
(
pt = #;
tip = nf[pt, {1, threshold}];
displayQ = tip =!= {};
) &
]
,
Show[
ListPlot[dataPoints, listPlotOptions]
,
Graphics[{
Dynamic@
If[displayQ,
Text[
Framed[tipFunction@tip[[1]]
, Background -> Lighter@Lighter@Lighter@Yellow
, FrameStyle -> Directive[Opacity[0], White]
, FrameMargins -> 2
]
, {pt[[1]], pt[[2]]}
, tipPosition[pt]
]
, {}
]
}]
]
, AutoAction -> True
, Appearance -> None
]
]


This is a test example for 10,000 points.

data = Table[RandomVariate[NormalDistribution[0, .5], 2], {i, 10000}];
tipsFunc =
Labeled[Column[#, Frame -> True, FrameStyle -> Red],
Rotate[": )", -Pi/2]] &;
TooltipListPlot[data, tipsFunc, ImageSize -> 400, Frame -> True,
Axes -> False]


And this is a snapshot of the result.

Note that with the latest imrpovement it is now also possible to input data as rules which in some cases may be more appropriate for creating the tooltips. Following is a simple example.

dataAsRules=Table[RandomVariate[NormalDistribution[0,.5], 2]->StringJoin["my tooltip info ",ToString[i]],{i,10000}];
tipsFunc = #&;
TooltipListPlot[dataAsRules,tipsFunc, Frame->True, Axes->False,ImageSize->400]

-
It is much more responsive if you use Nearest[data] to construct a NearestFunction and then call this within Dynamic. I am editing your otherwise-fine answer with this improvement. (and +1 of course) – Mr.Wizard Aug 1 '14 at 17:38
I had it originally implemented as you are suggesting as I had the same idea of making the search process as fast as possible. However, the Nearest function takes some precious evaluation time before rendering the plot, plus, it also adds more information to save inside the DynamicModule which also is against initial responsiveness. For these reasons I'm not sure that it is better to step back to the precomputation of Nearest. Indeed, the decision should be left to the user. For using the function inside user interfaces I would not precompute. For a single use I would. Thanks for the +1! – Ariel Sepulveda Aug 1 '14 at 17:47
I do not observe a significant delay in the display using Nearest[data] but I did notice the lag without it. In fact I doubt that there is a case where it could be significant without the lag being much more so. Nevertheless I will be glad to refrain from making such edits to your posts in the future if you wish. – Mr.Wizard Aug 1 '14 at 18:05
I just tested again with the Nearest precomputation and I agree that the speed is basically the same. I'm not sure what may have caused the delay in the past. In any case, your modifications are welcome and I appreciate them. – Ariel Sepulveda Aug 1 '14 at 18:22
Alright, and you're welcome. :-) – Mr.Wizard Aug 1 '14 at 18:25