Skip to content

Commit 81ad79d

Browse files
cgraham-rsdotNomad
andauthored
Add top-5-income-share-bokeh (#104)
* Add top-5-income-share-bokeh * Use example category --------- Co-authored-by: Jordan Jensen <[email protected]>
1 parent c6bd794 commit 81ad79d

File tree

6 files changed

+984
-0
lines changed

6 files changed

+984
-0
lines changed

.github/workflows/extensions.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
stock-api-plumber: extensions/stock-api-plumber/**
3939
stock-api-flask: extensions/stock-api-flask/**
4040
stock-dashboard-python: extensions/stock-dashboard-python/**
41+
top-5-income-share-bokeh: extensions/top-5-income-share-bokeh/**
4142
landing-page: extensions/landing-page/**
4243
stock-api-fastapi: extensions/stock-api-fastapi/**
4344
connectwidgets-example: extensions/connectwidgets-example/**
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Top 5% income share
2+
3+
## About this example
4+
5+
A Bokeh application makes it easy to transform your analysis into an interactive dashboard using Python so users can ask and answer questions in real-time, without having to touch any code.
6+
7+
8+
## Learn more
9+
10+
* [Bokeh Documentation](https://docs.bokeh.org/)
11+
* [User Guide: Bokeh](https://docs.posit.co/connect/user/bokeh/)
12+
13+
## Requirements
14+
15+
* Python version 3.9 or higher
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import pandas as pd
2+
3+
from bokeh.plotting import figure, curdoc
4+
from bokeh.models import (
5+
ColumnDataSource,
6+
DataTable,
7+
TableColumn,
8+
NumberFormatter,
9+
MultiChoice,
10+
Div,
11+
)
12+
from bokeh.layouts import column
13+
from bokeh.palettes import viridis
14+
15+
16+
DEFAULT_COUNTRIES = [
17+
"Australia",
18+
"China",
19+
"France",
20+
"Germany",
21+
"Japan",
22+
"United States",
23+
]
24+
25+
data = pd.read_csv("./data.csv")
26+
grouped = data.groupby("Entity")
27+
countries = data["Entity"].unique().tolist()
28+
colors = dict(zip(countries, viridis(len(countries))))
29+
30+
source = ColumnDataSource(dict(countries=[], years=[], percents=[]))
31+
32+
33+
# Markup header
34+
#
35+
header = Div(
36+
text="""
37+
<h1>Top 5% Income Share</h1>
38+
<p>Share of income received by the richest 5% of the population as sourced by
39+
<a href="https://ourworldindata.org/grapher/top-5-income-share">https://ourworldindata.org/grapher/top-5-income-share</a>.
40+
</p>
41+
""" # noqa
42+
)
43+
44+
45+
# Country multi-select input
46+
#
47+
countries_selector = MultiChoice(value=DEFAULT_COUNTRIES, options=countries)
48+
49+
50+
# Line plot of selected countries
51+
#
52+
plot = figure(title="Top 5% income share", x_axis_label="Year", y_axis_label="Percent")
53+
54+
plot.multi_line(
55+
xs="years",
56+
ys="percents",
57+
legend_field="countries",
58+
line_color="color",
59+
source=source,
60+
)
61+
62+
63+
# Data table of selected countries
64+
#
65+
table = DataTable(
66+
source=source,
67+
columns=[
68+
TableColumn(field="countries", title="Country"),
69+
TableColumn(field="span", title="Years"),
70+
TableColumn(
71+
field="mean",
72+
title="Percent (mean)",
73+
formatter=NumberFormatter(format="0.00"),
74+
),
75+
],
76+
)
77+
78+
79+
def update():
80+
selected_countries = countries_selector.value
81+
countries = [name for name, _ in grouped if name in selected_countries]
82+
years = [list(df["Year"]) for name, df in grouped if name in selected_countries]
83+
percents = [
84+
list(df["Percent"]) for name, df in grouped if name in selected_countries
85+
]
86+
span = [
87+
"%s - %s" % (df["Year"].min(), df["Year"].max())
88+
for name, df in grouped
89+
if name in selected_countries
90+
]
91+
mean = [df["Percent"].mean() for name, df in grouped if name in selected_countries]
92+
color = [colors[name] for name, df in grouped if name in selected_countries]
93+
source.data = dict(
94+
countries=countries,
95+
years=years,
96+
percents=percents,
97+
span=span,
98+
mean=mean,
99+
color=color,
100+
)
101+
102+
103+
countries_selector.on_change("value", lambda attr, old, new: update())
104+
105+
update()
106+
107+
curdoc().add_root(column(header, countries_selector, plot, table))
108+
curdoc().title = "Top 5% Income Share"

0 commit comments

Comments
 (0)