How to link the hover text so it change automatically when switching between holomap object?

So here is a reproductible example based on [https://holoviews.org/gallery/demos/bokeh/choropleth_data_link.html#demos-bokeh-gallery-choropleth-data-link]:

import holoviews as hv
from holoviews import opts
from holoviews.plotting.links import DataLink
hv.extension('bokeh')

from bokeh.sampledata.us_counties import data as counties
from bokeh.sampledata.unemployment import data as unemployment

# Generate dummy data
data2 = {}
data3 = {}
for ind, keys in enumerate(list(unemployment.keys())):
    data2[keys] = unemployment[keys]+ind/10
    data3[keys] = unemployment[keys]-ind/10   
print(list(data2.items())[0:3])


counties = [dict(county, Unemployment=unemployment[cid], Data2=data2[cid], Data3=data3[cid])
            for cid, county in counties.items()
            if county["state"] == "tx"]

def map_and_table(counties,var='Unemployment'):
    county_data = [(county['detailed name'], county[var]) for county in counties]

    choropleth = hv.Polygons(counties, ['lons', 'lats'], [('detailed name', 'County'), var])#, label='Texas ' + var)
    table = hv.Table(county_data, [('detailed name', 'County'), var])

    
    # Link the choropleth and the table
    DataLink(choropleth, table)

    layout = choropleth + table

    layout.opts(
       opts.Table(height=428),
       opts.Polygons(width=500, height=500,  tools=['hover', 'tap'], xaxis=None, 
                     yaxis=None, color_index=var))
    
    return layout

layout=map_and_table(counties,var='Data2')

layout

statistics = ('Unemployment','Data2','Data3')

# get a map object
layout_dict = {stat: map_and_table(counties,var=stat)[0] for stat in statistics}
kdims = [hv.Dimension(('statistics', 'Statistics'))]
holomaps = hv.HoloMap(layout_dict, kdims=kdims)

# get a table object
layout_dict = {stat: map_and_table(counties,var=stat)[1] for stat in statistics}
kdims = [hv.Dimension(('statistics', 'Statistics'))]
holotables = hv.HoloMap(layout_dict, kdims=kdims)

# Link both object
DataLink(holomaps, holotables)

holomapwithtable = holomaps + holotables

holomapwithtable

This generated a figure similar to this one:

If the datalink is working properly between the map and the table, the hover text is not changing when selecting different statistics.

Do you know how I could fix that?

The notebook can be accessed here: https://nbviewer.jupyter.org/urls/dl.dropbox.com/s/amtbmtd6j6s3ts0/choropleth_data_link_holo.ipynb

Thank you!

Hi @lhoupert

I played around with it. But I am no expert. But my hypothesis is that what confuses holoviews is that the value (?) dimension is called something differently in the 3 maps. It’s called “Data2”, “Data3” and “Unemployment” respectively. And if you look at the dropdown they are sorted in that order. No matter which order you provide them with in the statistics dict.

Thus somehow I think that the holomap chooses the value dimension in the hover from the “last” plot in the holomap. Thus “Unemployment” becomes the dimension used. And since that data is available in the dataset underlying all the plots it’s displayed and used. I actually also think the Unemployment dimesion is coloring the map always as well.

I don’t know if this is by design or a bug. But it is confusing and hard to figure out.

The below code got the map working for me. I hope you can use it to construct a working example.

import holoviews as hv
from holoviews import opts
hv.extension('bokeh')
import panel as pn

from bokeh.sampledata.us_counties import data as counties
from bokeh.sampledata.unemployment import data as unemployment

# Generate dummy data
data2 = {}
data3 = {}
for ind, keys in enumerate(list(unemployment.keys())):
    data2[keys] = unemployment[keys]+ind/10
    data3[keys] = unemployment[keys]-ind/10

unemployment_datasets={
    "Unemployment": unemployment,
    "Data2": data2,
    "Data3": data3
}

def get_counties(var):
    result = []
    for cid, county in counties.items():
        if county["state"]=="tx":
            row = dict(county)
            row["Unemployment"]=unemployment_datasets[var][cid]
            result.append(row)
    return result

def map_and_table(var='Unemployment'):
    data = get_counties(var)
    choropleth = hv.Polygons(data, ['lons', 'lats'], [('detailed name', 'County'), "Unemployment"])#, label='Texas ' + var)
    choropleth.opts(
       opts.Polygons(width=500, height=500,  xaxis=None, tools=['hover', 'tap'],
                     yaxis=None, color_index="Unemployment"))
    return choropleth

statistics = ("Unemployment", 'Data2', 'Data3')

# get a map object
layout_dict = {stat: map_and_table(var=stat) for stat in statistics}
kdims = [hv.Dimension(('statistics', 'Statistics'))]
holomaps = hv.HoloMap(layout_dict, kdims=kdims)

pn.Column("#### HoloMaps", holomaps, "#### Data2", map_and_table(var="Data2")).servable()

Hi @lhoupert

If you get a working example please share it here. It would build the knowledge base of the community and I would also like to have a nice working example. Maybe something I could add to awesome-panel.org.

Thanks.

Thank you @Marc for your quick reply! I had to changed it slightly.
Interestingly my holomap example is working for me in the notebook (except the hover text) but the panel solution is not working in my jupyter notebook. However when I save the panel as static html and open it in a webbrowser it is working…

I think it may be related to my version of bokeh (Cannot get the getting started example to update the figure - #6 by lhoupert). If you want to see by yourself, you can access the last version of this test notebook (choropleth_data_link_holomaps.ipynb (9.1 MB) or available here).
You can see that the holomaps object is working fine in the notebook while layout_pn is not. However, the static html file generated from the panel example is working fine in a web browser (see example here)

What version of bokeh are you using? (mine is the 2.2.3)

I will try again downgrading my bokeh version

I’m using bokeh 2.2.3 and latest versions of hvplot, holoviews and panel as well.

Thank you @Marc. Did you try in jupyter notebook or jupyter lab?
I realise that the interactivity is working in jupyter notebook but not in jupyter lab.
My jupyter version are:

 jupyter --version                                                                   12:41:02
jupyter core     : 4.7.0
jupyter-notebook : 6.1.5
qtconsole        : 5.0.1
ipython          : 7.19.0
ipykernel        : 5.4.2
jupyter client   : 6.1.7
jupyter lab      : 2.2.9
nbconvert        : 6.0.7
ipywidgets       : 7.5.1
nbformat         : 5.0.8
traitlets        : 5.0.5
1 Like

I’m not normally using Jupyter lab. I’m a VS code user. I have a hypothesis that in Jupyter lab the js library needs to be loaded in a different way. But I don’t know for sure.

Problem solved, I didn’t have the jupyter lab extension installed properly … https://github.com/holoviz/panel/issues/1845. I will send you the final notebook of the example.

1 Like

Here is the example that should be working!


import holoviews as hv
from holoviews import opts
hv.extension('bokeh')

import panel as pn
import panel.widgets as pnw
pn.extension()

from bokeh.sampledata.us_counties import data as counties
from bokeh.sampledata.unemployment import data as unemployment


# Generate dummy data
data2 = {}
data3 = {}
for ind, keys in enumerate(list(unemployment.keys())):
    data2[keys] = unemployment[keys]+ind/10
    data3[keys] = unemployment[keys]-ind/10   

unemployment_datasets={
    "Unemployment": unemployment,
    "Data2": data2,
    "Data3": data3
}

def get_counties(var):
    result = []
    for cid, county in counties.items():
        if county["state"]=="tx":
            row = dict(county)
            row[var]=unemployment_datasets[var][cid]
            result.append(row)
    return result

def plot_map(var='Unemployment'):
    data = get_counties(var)
    choropleth = hv.Polygons(data, ['lons', 'lats'], [('detailed name', 'County'), var])#, label='Texas ' + var)
    choropleth.opts(opts.Polygons(width=400, height=400,  tools=['hover', 'tap'], xaxis=None, 
                     yaxis=None, color_index=var))
    return choropleth

def get_table(var='Unemployment'):
    data = get_counties(var)
    table = hv.Table(data, [('detailed name', 'County'), var])
    table.opts(
       opts.Table(height=328)
    )
    return table


statistics = ("Unemployment", 'Data2', 'Data3')

variable  = pnw.RadioButtonGroup(name='variable', value='Unemployment', 
                                 options=list(statistics))

@pn.depends(variable)
def reactive_map(variable):
    return plot_map(variable)

@pn.depends(variable)
def reactive_table(variable):
    return get_table(variable)

widgets   = pn.Column("<br>\n# Statistics", variable)
maps_pn = pn.Column(widgets,pn.Row(reactive_map, reactive_table))

#maps_pn.show()
maps_pn