WG123
WG123

Reputation: 3

Using slider to update pie chart (Bokeh) via filtering out of data

I'm new to this and appreciate any pointers/help to push me to the right direction. Basically I'm trying to come up with an interactive Bokeh pie chart with a slider that can help filter the data accordingly (year in this case). The pie chart is showing proportion of 65 & above in the labour force, the end goal is to be able to use the slider to see the proportion increase over the years. Big thanks in advance to all.

https://data.gov.sg/dataset/total-residents-aged-15-years-and-over-by-labour-force-status-and-age-group-june-annual?resource_id=6549bb00-6ae8-4608-ab6a-1613b1121266

from math import pi

from bokeh.io import output_file, show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.application.handlers import FunctionHandler
from bokeh.palettes import Category20b
from bokeh.transform import cumsum
from bokeh.application import Application

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pd.options.mode.chained_assignment = None 

output_file("pie.html")

df1 = pd.read_csv('data CA2/total-residents-aged-15-years-and-over-by-age-group.csv',na_values =["na"])

rows_to_keep = ["65 Years & Over"]
rows_to_keep2 = ["Total Residents In The Labour Force", "Total Residents Outside The Labour Force"]
df2 = df1[df1['level_2'].isin(rows_to_keep)]
df3 = df2[df2["level_1"].isin(rows_to_keep2)] 


df4 = df3.groupby(['year', 'level_1', ]).sum()

df5 = df4.reset_index(drop=False)
df6 = df5[df5["year"] == 2019]

df6['angle'] = df6['value']/df6['value'].sum() * 2*pi
df6['color'] = ["purple","blue"]


p = figure(plot_height=350, title="Pie Chart", toolbar_location=None,
            tools="hover", tooltips="@level_1: @value",x_range=(-0.5, 1.0))

p.wedge(x=0, y=1, radius=0.4,
        start_angle= cumsum("angle", include_zero=True), end_angle=cumsum("angle"),
        line_color="white", fill_color='color', source=df6)

slider = Slider(start=1990, end=2019, value=2001, step=1, title="Year")


def update(source=df6, slider=slider, window=None):
    df6 = df5[df5["year"] == slider.value]
    source.trigger('change')

Output of current pie chart:

Output of current pie chart

Upvotes: 0

Views: 1002

Answers (1)

EddyG
EddyG

Reputation: 685

If you want interactions, you either need to specify the callbacks in java using js_* callbacks, or like my example below, use the pure python callbacks, but they will not work in a regular browser without hosting them on a bokeh server as the regular html wont support python. I've been exactly where you are now, see my question (Export interactive Bokeh plots with widgets to standalone HTML) and the answer.

In order to see it working, I use Jupyter notebook to run the code and design the interactions. i found this to be the most convenient way of building bokeh apps, but you can also use bokeh serve.

To get it to work in jupyter notebook:

from bokeh.io import output_notebook
output_notebook()

You'll need to wrap your code in a single function which you then pass to the FunctionHandler and that in the Application function, which you can then show.

I've made some adjustments to get it to work nicely, see below:

df1 = pd.read_csv('total-residents-aged-15-years-and-over-by-age-group.csv',na_values =["na"])

rows_to_keep = ["65 Years & Over"]
rows_to_keep2 = ["Total Residents In The Labour Force", "Total Residents Outside The Labour Force"]
df2 = df1[df1['level_2'].isin(rows_to_keep)]
df3 = df2[df2["level_1"].isin(rows_to_keep2)] 


df4 = df3.groupby(['year', 'level_1', ]).sum()

df5 = df4.reset_index(drop=False)


def viz(doc):

    def update(attr,old,new):        
        df6 = grabData(new)
        src.data.update(ColumnDataSource(df6).data)

    def grabData(year):
        df6 = df5[df5["year"] == year]

        df6['angle'] = df6['value']/df6['value'].sum() * 2*pi
        df6['angle1'] = [0,df6['angle'].iloc[0]]
        df6['angle2'] = [df6['angle'].iloc[0],2*pi]
        df6['color'] = ["purple","blue"]
        return df6

    df6 = grabData(2001)
    src = ColumnDataSource(df6)

    p = figure(plot_height=350, title="Pie Chart", toolbar_location=None,
                tools="hover", tooltips="@level_1: @value",x_range=(-0.5, 1.0))

    p.wedge(source=src,x=0, y=1, radius=0.4,
            start_angle= 'angle1', end_angle='angle2',
            line_color="white", fill_color='color')

    slider = Slider(start=1990, end=2019, value=2001, step=1, title="Year")
    slider.on_change('value',update)
    doc.add_root(column(p,slider))




show(Application(FunctionHandler(viz)))

Upvotes: 1

Related Questions