Home > Blockchain >  How to adjust tooltip to display only column selected by slider in Bokeh
How to adjust tooltip to display only column selected by slider in Bokeh

Time:03-20

I am trying to crate visualization using Geopandas and Bokeh. Data has column region, geometry and >100 columns (week1, week2, week3,..) that have numeric value of cases.

The task is for the tooltip when hovering over a region to show only the value from column currently selected by the slider.

Things I tried:

This option displays all columns in the tooltip. Too much information

data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
figsize=(1600,600))

Not sure what to put as variable next to "Cases", or how to make it dynamic based on slider.

data.plot_bokeh(
slider=[week1,week2,week3],
slider_name="Week:",
hovertool_string="""<h1>@region_name</h1>
                    <h3>Cases: ?? </h3>""",
figsize=(1600,600))

Bokeh has to have the current value according to slider stored somewhere, as it's correctly coloring the region based on value

CodePudding user response:

  • if you inspect the code of plotly_bokeh in geoplot.py/geoplot() you will find in slider callback JavaScript an internal column Colormap is set to column corresponding to value in slider (code below)
  • you did not provide a MWE, so have used OWID COVID data and natural earth lowres polygons. (see data preparation)
  • with this it is simple to define hovertool_string argument to work the way you want

solution


import warnings

# bokeh generates a lot of shapely deprecation warnings
with warnings.catch_warnings():
    warnings.simplefilter("ignore")

    gdf.plot_bokeh(
        slider=[c for c in gdf.columns if c[0:4] == "week"],
        slider_name="week ",
        colorbar_tick_format="0.0a",
        colormap="Inferno",
        colormap_range=[
            gdf.loc[:, [c for c in gdf.columns if c[0:4] == "week"]].quantile(p).quantile(p)
            for p in [0.10, 0.90]
        ],
        hovertool_string="<h3>@name</h3><pre>@Colormap{0.0a}</pre>"
    )

output

enter image description here

plotly_bokeh callback

        # Define Callback for Slider widget:
        callback = CustomJS(
            args=dict(
                slider_widget=slider_widget,
                geo_source=geo_source,
                value2name=value2name,
            ),
            code="""

                //Change selection of field for Colormapper for choropleth plot:
                var slider_value = slider_widget.value;
                var i;
                for(i=0; i<value2name.data["Names"].length; i  )
                    {
                    if (value2name.data["Values"][i] == slider_value)
                        {
                         var name = value2name.data["Names"][i];
                         }

                    }
                geo_source.data["Colormap"] = geo_source.data[name];
                geo_source.change.emit();

                            """,
        )
        slider_widget.js_on_change("value", callback)


data preparation

import pandas as pd
import geopandas as gpd
import pandas_bokeh
pandas_bokeh.output_notebook()

df = pd.read_csv(
    "https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv"
).loc[
    lambda df: ~df["iso_code"].str.contains("_"),
    ["iso_code", "date", "total_cases_per_million"],
]
df["date"] = pd.to_datetime(df["date"])

# cases for each week as columns
df2 = (
    df.merge(
        pd.DataFrame(
            {"date": pd.date_range(df["date"].quantile(.1), df["date"].max(), freq="W-MON")}
        ).assign(week=lambda d: "week"   d.index.astype(str).str.zfill(3)),
        on="date",
        how="inner",
    )
    .drop(columns=["date"])
    .set_index(["iso_code", "week"])
    .unstack("week")
    .droplevel(0, 1)
    .reset_index()
)

# geometry and cases as columns
gdf = (
    gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
    .loc[:, ["iso_a3", "name", "geometry"]]
    .merge(df2, left_on="iso_a3", right_on="iso_code")
)
  • Related