mpld3 / mpld3

An interactive data visualization tool which brings matplotlib graphics to the browser using D3.
http://mpld3.github.io
BSD 3-Clause "New" or "Revised" License
2.36k stars 360 forks source link

Label not showing on "some" data points (PointLabelTooltip and PointHTMLTooltip) #321

Open npetitclerc opened 9 years ago

npetitclerc commented 9 years ago

I got this strange bug where the label didn't show when hovering over a specific data point (but it did for most of them). I tried both PointLabelTooltip and PointHTMLTooltip and got the same behaviour.

I know it's not a bug with the string itself since I tried to display the same for all data points and got the same behaviour.

I also find the hover area quite small so that it's quite hard to get the labels to popup in general - that might be a side effect of the same bug?

My version of mpld3 is '0.3git'

aflaxman commented 9 years ago

Can you provide a minimal example that reproduces this issue? StackOverflow has some good advice on how to do so: http://stackoverflow.com/help/mcve

npetitclerc commented 9 years ago

Ok, I was able to produce a minimal example, see below. Doing so I figured out it's when plotting a line AND a scatter plot over the same data points - then only the section of the dot BELOW the line triggers the tooltip. I hope this is fixable, thanks!

%matplotlib inline
import pylab as plt
import mpld3
from mpld3 import plugins

fig, ax = plt.subplots()
x = [4, 10, 16, 45, 46, 78, 82, 99, 137, 163, 171, 187, 193, 198]
y = [6761., 2889., 3354., 1119., 986., 750., 664., 913., 364.,  477., 349., 596., 361., 295.]

scatter = ax.scatter(x, y, s=150)
p = ax.plot(x, y)
labels = ['test']*len(x)
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
#tooltip = mpld3.plugins.PointHTMLTooltip(scatter, labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.display(fig)
#make_html = mpld3.fig_to_html(fig, template_type = "general")
#print make_html
aflaxman commented 9 years ago

I think that the svg elements from the scatter and the plot are colliding and the plot is sometimes getting the mouse events that you want the scatter to get. As a work-around, you can achieve a figure very similar to the scatter and plot together with single plot, and tooltips work well with the for me:

#scatter = ax.scatter(x, y, s=150)
p = ax.plot(x, y, 'o-', ms=15, label='curve')
labels = ['test'+str(i) for i in range(len(x))]
tooltip = mpld3.plugins.PointLabelTooltip(p[0], labels=labels, voffset=10, hoffset=10)
aflaxman commented 9 years ago

Regarding the hover area being small, there is a d3js recipe for using voronoi cells to make tooltips easier, and I think it would be a cool contribution to mpld3 to have a voronoi variant of the tooltip plugin

npetitclerc commented 9 years ago

The work-around works for this minimal example, but for the plot I'm really interested in the line is not exactly the same as the scatter data. Imagine you want to plot a model vs experimental data points.

The hover area seemed too small, because sometimes a good portion of the scatter points was conflicting with the line.

npetitclerc commented 9 years ago

Here's a better example of the issue, where you can see that the tooltip doesn't show for the data points around 50 and 150.

%matplotlib inline
import pylab as plt
import mpld3
from mpld3 import plugins

fig, ax = plt.subplots()
x = [4, 10, 16, 45, 46, 78, 82, 99, 137, 163, 171, 187, 193, 198]
y = [6761., 2889., 3354., 1119., 986., 750., 664., 913., 364.,  477., 349., 596., 361., 295.]

scatter = ax.scatter(x, y, s=150)
x2, y2 = [1, 50, 100, 150, 200], [2000, 0, 2000, -1000, 2000]

p = ax.plot(x2, y2, label='curve')
labels = ['test']*len(x)
tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels)
#tooltip = mpld3.plugins.PointHTMLTooltip(scatter, labels)
mpld3.plugins.connect(fig, tooltip)
mpld3.display(fig)
aflaxman commented 9 years ago

I can confirm that the tooltips are not working for all points here, and I don't have any simple workaround for this case. I do still think that a voronoi tooltip plugin would be the coolest way to solve it.

npetitclerc commented 9 years ago

I found a workaround, by adding these few lines to my css file:

.mpld3-figure path {
    pointer-events: none;
}
.mpld3-figure path.mpld3-path {
    pointer-events: auto;
}

This turns on 'pointer-events' only for the scatter plot - it happens to have 'path.mpld3-path' as class name. It works for this example, but it's not an ideal solution. 1 - It would be nice if we could specify the class names. Maybe mpld3 could use the matplotlib 'label' as the class name? That way we can edit the graph further with css in a more reliable manner. 2 - It would be even better to able to set things like 'pointer-events' from the mpld3 api, avoiding messing with css files altogether.

jdoepfert commented 8 years ago

@npetitclerc thanks for the nice workaround. I had the same problem overlaying a shapefile with a scatter plot.