Search code examples
pythonjupyter-notebookdata-visualizationjupyterholoviews

Holoviews example: How to display plot in Jupyter notebook?


I am trying out Holoviews for the first time, and I'd like to reproduce this animated "Gapminder" plot as described here.

The code runs but I do not know how to handle the output so that it is displayed in a Jupyter Notebook (I assume that is possible, since Jupyter can display arbitrary HTML).

# Get HoloViews plot and attach document
doc = curdoc()
hvplot = BokehRenderer.get_plot(hvgapminder, doc)

# Make a bokeh layout and add it as the Document root
plot = layout([[hvplot.state], [slider, button]], sizing_mode='fixed')
doc.add_root(plot)

Specifically, what should I do with the resulting doc or hvplot objects?


Solution

  • That particular example combines both HoloViews and bokeh components and bokeh widgets cannot easily communicate with Python in the notebook. You can however use the holoviews 'scrubber' widget to achieve the same thing:

    import pandas as pd
    import numpy as np
    import holoviews as hv
    from bokeh.sampledata import gapminder
    
    hv.extension('bokeh')
    
    # Switch to sending data 'live' and using the scrubber widget
    %output widgets='live' holomap='scrubber'
    
    # Declare dataset
    panel = pd.Panel({'Fertility': gapminder.fertility,
                      'Population': gapminder.population,
                      'Life expectancy': gapminder.life_expectancy})
    gapminder_df = panel.to_frame().reset_index().rename(columns={'minor': 'Year'})
    gapminder_df = gapminder_df.merge(gapminder.regions.reset_index(), on='Country')
    gapminder_df['Country'] = gapminder_df['Country'].astype('str')
    gapminder_df['Group'] = gapminder_df['Group'].astype('str')
    gapminder_df.Year = gapminder_df.Year.astype('f')
    ds = hv.Dataset(gapminder_df)
    
    # Apply dimension labels and ranges
    kdims = ['Fertility', 'Life expectancy']
    vdims = ['Country', 'Population', 'Group']
    dimensions = {
        'Fertility' : dict(label='Children per woman (total fertility)', range=(0, 10)),
        'Life expectancy': dict(label='Life expectancy at birth (years)', range=(15, 100)),
        'Population': ('population', 'Population')
    }
    
    # Create Points plotting fertility vs life expectancy indexed by Year
    gapminder_ds = ds.redim(**dimensions).to(hv.Points, kdims, vdims, 'Year')
    
    # Define annotations
    text = gapminder_ds.clone({yr: hv.Text(1.2, 25, str(int(yr)), fontsize=30)
                               for yr in gapminder_ds.keys()})
    
    # Define options
    opts = {'plot': dict(width=1000, height=600,tools=['hover'], size_index='Population',
                         color_index='Group', size_fn=np.sqrt, title_format="{label}"),
           'style': dict(cmap='Set1', size=0.3, line_color='black', alpha=0.6)}
    text_opts = {'style': dict(text_font_size='52pt', text_color='lightgray')}
    
    
    # Combine Points and Text
    (gapminder_ds({'Points': opts}) * text({'Text': text_opts})).relabel('Gapminder Demo')