Search code examples
pythonduplicateshovertooltipbokeh

Remove duplicates in Bokeh HoverTool in Python (Ubuntu)


I have a scatter plot in bokeh-2.4.3 with a huge number of points and different metadata. I'm using HoverTool to show some of the additional data, e.g.

hover = HoverTool(tooltips=f"""
<div>
<span style='font-size: 10px'>metadata1: @meta1\tmetadata2: @meta2</span>
</div>
""", renderers=renderers)

However, many of the points in the same location will have the same metadata, and because there are so many points sometimes the tooltip data becomes huge, with many duplicates, which makes it hard to see what's going on.

I would like to aggregate this data in some way, in the simplest case just by removing duplicates (e.g. the first two lines in the example image are both 'metadata1: 21.0 metadata2: 296479', I only need one of these), but it could also be useful to have a count of each.

So the hovertip as shown in the picture, currently saying:

metadata1: 21.0 metadata2: 296479
metadata1: 21.0 metadata2: 296479
metadata1: 27.0 metadata2: 296477
metadata1: 24.0 metadata2: 296610
metadata1: 27.0 metadata2: 296477
metadata1: 21.0 metadata2: 296523
metadata1: 27.0 metadata2: 296552
metadata1: 27.0 metadata2: 296477
metadata1: 27.0 metadata2: 296477
metadata1: 20.0 metadata2: 296579

would become:

metadata1: 21.0 metadata2: 296479 count: 2
metadata1: 27.0 metadata2: 296477 count: 4
metadata1: 24.0 metadata2: 296610 count: 1
metadata1: 21.0 metadata2: 296523 count: 1
metadata1: 27.0 metadata2: 296552 count: 1
metadata1: 20.0 metadata2: 296579 count: 1

for example.

Any ideas?

Example scatter plot with duplicates in HoverTool


Solution

  • Sadly, as far as I know, there is no way to remove duplicates in the way that you want, and there is a long open issue to add a filter for tooltip display which could solve the your issue if that feature was added.

    As an alternative, you could hide all tooltips except the first one using CSS, if that was acceptable to you.

    Here is some CSS that I am using for this:

    /* For Bokeh v2 - you mentioned 2.4.3 in the question */
    
    div.bk-tooltip.bk-right > div.bk > div:not(:first-child) {
        display: none !important;
    }
    div.bk-tooltip.bk-left > div.bk > div:not(:first-child) {
        display: none !important;
    }
    
    /* For Bokeh v3 */
    
    div.bk-tooltip-content > div > div:not(:first-child) {
        display: none !important;
    }
    

    To use this CSS, the easiest way is to add to your custom tooltip HTML, as Bokeh scopes the plot in a Shadow DOM, so global site CSS doesn't apply.

    Using your example, this would look like:

    hover = HoverTool(tooltips=f"""
    <div>
        <span style='font-size: 10px'>metadata1: @meta1\tmetadata2: @meta2</span>
    </div>
    <style>
         div.bk-tooltip.bk-right > div.bk > div:not(:first-child) {
             display:none !important;
         }
         div.bk-tooltip.bk-left > div.bk > div:not(:first-child) {
             display:none !important;
         }
    </style>
    """, renderers=renderers)
    

    This certainly isn't ideal, as the tooltips are still rendered but then hidden with CSS, so with many points could be a performance issue, but it is the best solution I have found so far.