In [1]:
import pandas as pd
from numpy import where
from bokeh.plotting import show, output_notebook
output_notebook()
In [2]:
from chart_constants import WATER_COLOR_RANGE, SANITATION_COLOR_RANGE, GRAY, ORANGE
def color_data(data):
def _get_color(value, palette):
if value < 0:
return GRAY
index = int((value-0.01) / 10)
return palette[index]
data['wat_color'] = data['wat_value'].apply(
_get_color, args=([WATER_COLOR_RANGE])
)
data['san_color'] = data['san_value'].apply(
_get_color, args=([SANITATION_COLOR_RANGE])
)
data['wat_value'] = where(data['wat_value'] < 0, '-', data['wat_value'])
data['san_value'] = where(data['san_value'] < 0, '-', data['san_value'])
return data
In [3]:
wat_df = pd.read_hdf('water_data_all_years.hdf', 'df')
san_df = pd.read_hdf('san_data_all_years.hdf', 'df')
In [4]:
data = pd.read_hdf('static_map_data.hdf', 'df') # note we have to use hdf, not csv for the xs & ys lists
data.head()
Out[4]:
In [5]:
def update_data_for_new_year(data, year):
data = data.drop(['wat_value', 'san_value', 'wat_color', 'san_color'], axis=1)
data.year = year
data = data.merge(wat_df, how='left')
data = data.merge(san_df, how='left')
data = data.fillna(-99)
colored_df = color_data(data)
return colored_df
In [6]:
data = update_data_for_new_year(data, 1991)
data.head()
Out[6]:
In [7]:
from bokeh.models import Range1d, Plot
from chart_constants import PLOT_FORMATS
def setup_map_plot():
x_start, x_end = (-20, 60)
y_start, y_end = (-40, 40)
aspect_ratio = (x_end - x_start) / (y_end - y_start)
x_range = Range1d(x_start, x_end)
y_range = Range1d(y_start, y_end)
plot_height = 400
return Plot(x_range=x_range, y_range=y_range, title="", plot_width=int(plot_height * aspect_ratio), plot_height=plot_height, **PLOT_FORMATS)
In [8]:
from bokeh.models import Patches, TapTool, HoverTool
def make_map(source, fill_color_string='wat_color', value_string='wat_value', selected_color=ORANGE):
countries = Patches(
xs='xs',
ys='ys',
fill_color=fill_color_string,
line_color="#FFFFFF",
)
selected_countries = Patches(
xs='xs',
ys='ys',
fill_color=fill_color_string,
line_color=selected_color,
line_width=5,
)
map_box = setup_map_plot()
map_box.add_glyph(source, countries, selection_glyph=selected_countries, nonselection_glyph=countries)
map_box.add_tools(TapTool())
tooltips = "@year<br />@name<br />@" + value_string + " %"
map_box.add_tools(HoverTool(tooltips=tooltips))
return map_box
In [9]:
from bokeh.models import Text, Triangle, Rect
from chart_constants import FONT_PROPS_SM, FONT_PROPS_MD, FONT_PROPS_LG, ORANGE, ORANGE_SHADOW
def construct_text_box(source, value_string, color_string, bar_color):
# Plot and axes
xdr = Range1d(0, 220)
ydr = Range1d(0, 120)
plot = Plot(
x_range=xdr,
y_range=ydr,
title="",
plot_width=250,
plot_height=120,
min_border=0,
**PLOT_FORMATS
)
# Add the writing
country = Text(x=5, y=50, text='name', **FONT_PROPS_MD)
percent = Text(x=15, y=10, text=value_string, text_color=color_string, **FONT_PROPS_LG) # nopep8
percent_sign = Text(x=69, y=10, text=['%'], text_color=color_string, **FONT_PROPS_LG) # nopep8
line_one = Text(x=90, y=28, text=['of people had'], **FONT_PROPS_SM)
line_two_p1 = Text(x=90, y=14, text=['access in'], **FONT_PROPS_SM)
line_two_p2 = Text(x=136, y=14, text='year', **FONT_PROPS_SM)
plot.add_glyph(source, Text(), selection_glyph=country)
plot.add_glyph(source, Text(), selection_glyph=percent)
plot.add_glyph(source, Text(), selection_glyph=percent_sign)
plot.add_glyph(line_one)
plot.add_glyph(line_two_p1)
plot.add_glyph(source, Text(), selection_glyph=line_two_p2)
# Add the orange box with year
shadow = Triangle(x=150, y=109, size=25, fill_color=ORANGE_SHADOW, line_color=None) # nopep8
plot.add_glyph(shadow)
# Add the blue bar
rect = Rect(x=75, y=99, width=150, height=5, fill_color=bar_color, line_color=None) # nopep8
plot.add_glyph(rect)
box = Rect(x=200, y=100, width=100, height=40, fill_color=ORANGE, line_color=None) # nopep8
plot.add_glyph(box)
year = Text(x=160, y=85, text='year', text_font_size='18pt', text_color="#FFFFF", text_font_style="bold") # nopep8
plot.add_glyph(source, Text(), selection_glyph=year)
return plot
In [10]:
from bokeh.plotting import hplot, vplot
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Tabs, Panel
from chart_constants import GREEN, BLUE, DARK_GRAY
source = ColumnDataSource(data)
source.selected = [30]
water_plot = make_map(source, 'wat_color', 'wat_value', ORANGE)
water_text = construct_text_box(source, 'wat_value', 'wat_color', BLUE)
sanitation_plot = make_map(source, 'san_color', 'san_value', DARK_GRAY)
sanitation_text = construct_text_box(source, 'san_value', 'san_color', GREEN)
tabs = Tabs(tabs=[
Panel(title="Water", child=hplot(vplot(water_plot), vplot(water_text))),
Panel(title="Sanitation", child=hplot(vplot(sanitation_plot), vplot(sanitation_text)))
])
show(vplot(tabs))
In [11]:
def update(year=1990):
data = pd.DataFrame(source.data)
new_data = update_data_for_new_year(data, year)
source.data['year'] = new_data.year
source.data['wat_value'] = new_data.wat_value
source.data['san_value'] = new_data.san_value
source.data['wat_color'] = new_data.wat_color
source.data['san_color'] = new_data.san_color
source.push_notebook()
In [12]:
from IPython.html.widgets import interact
interact(update, year=(1990,2012))
In [ ]: