#this clears all variables
#%reset
import pandas as pd
from selenium import webdriver
import os
import math
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource
from bokeh.models import HoverTool
from bokeh.models import WheelZoomTool
from bokeh.models import PanTool
from bokeh.models import ResetTool
from bokeh.models import BoxZoomTool
from bokeh.core.properties import value
from bokeh.models import LinearAxis, Range1d
import nbconvert
import nbformat
from bokeh.io import output_notebook
output_notebook()
import warnings
warnings.filterwarnings('ignore')
# this sets up notebook export to .html
import IPython.core.display as di
# This line will hide code by default when the notebook is exported as HTML
di.display_html('<script>jQuery(function() {if (jQuery("body.notebook_app").length == 0)' +
'{ jQuery(".input_area").toggle(); jQuery(".prompt").toggle();}});</script>', raw=True)
# This line will add a button to toggle visibility of code blocks, for use with the HTML export version
#di.display_html('''<button onclick="jQuery('.input_area').toggle(); jQuery('.prompt').toggle();">Toggle code</button>''', raw=True)
class crockerToolTips():
def __init__(self, line_policy, names, tooltips, point_policy, toggleable):
self.line_policy = line_policy
self.names = names
self.tooltips = tooltips
self.point_policy = point_policy
self.toggleable = toggleable
class crockerLastUpdate():
def __init__(self, last_update):
self.last_update = last_update
def scrape_tc(table_number):
try:
driver = webdriver.Chrome(r'C:\chromedriver_win32\chromedriver.exe')
browser = webdriver.Chrome()
driver.get('https://bestsnow.net/seas19.htm')
content = driver.find_element_by_xpath('/html/body/table[' + str(table_number) + ']')
tc_last_update = driver.find_element_by_xpath('/html/body/h3')
tc_last_update_to_text = tc_last_update.text
tc_last_update_string = crockerLastUpdate(last_update=tc_last_update_to_text)
except:
browser.quit()
driver.quit()
resort_dict = {}
content_list = []
for c in (content.text).splitlines()[4:]:
content_list.append(c)
content_list = [content_list[x:x+4] for x in range(0, len(content_list), 4)]
resort_dict = {}
for c in content_list:
resort_dict[c[0]] = c[1:]
resort_df = pd.DataFrame(resort_dict)
return(resort_df, tc_last_update_string)
browser.quit()
driver.quit()
def create_dfs(resort_df):
resort_season_snow_df = resort_df.iloc[:1, :]
resort_percent_normal_df = resort_df.iloc[1:2, :]
resort_percent_normal_df = resort_percent_normal_df.apply(lambda x: x.str[-4:].str.lstrip('-'))
resort_percent_open_df = resort_df.iloc[2:3, :]
resort_percent_open_df = resort_percent_open_df.apply(lambda x: x.str[-4:].str.lstrip('-'))
resort_list = resort_season_snow_df.columns
resort_season_snow_df[resort_list] = resort_season_snow_df[resort_list].apply(pd.to_numeric, errors='coerce', axis=1)
resort_season_snow_df.fillna(0)
resort_percent_normal_df = resort_percent_normal_df.apply(lambda x: x.str.replace('%', ''))
resort_percent_normal_df[resort_list] = resort_percent_normal_df[resort_list].apply(pd.to_numeric, errors='coerce', axis=1)
resort_percent_normal_df.fillna(0)
resort_percent_open_df = resort_percent_open_df.apply(lambda x: x.str.replace('%', ''))
resort_percent_open_df[resort_list] = resort_percent_open_df[resort_list].apply(pd.to_numeric, errors='coerce', axis=1)
resort_percent_open_df.fillna(0, inplace=True)
return resort_season_snow_df, resort_percent_normal_df, resort_percent_open_df, resort_list
def make_tooltip_objs(resort_list):
tooltip_season_snow_objs = [crockerToolTips(line_policy='nearest',
names=[i+'_season_snow_1'],
tooltips=[(i + ' season snow', "@{" + i + "}{0.0[0]}")],
point_policy='follow_mouse', toggleable=False) for i in resort_list]
tooltip_percent_normal_objs = [crockerToolTips(line_policy='nearest',
names=[i+'_percent_normal_1'],
tooltips=[(i + ' percent of normal', "@{" + i + "}{0.0[0]}")],
point_policy='follow_mouse', toggleable=False) for i in resort_list]
tooltip_percent_open_objs = [crockerToolTips(line_policy='nearest',
names=[i+'_percent_open_1'],
tooltips=[(i + ' percent open', "@{" + i + "}{0.0[0]}")],
point_policy='follow_mouse', toggleable=False) for i in resort_list]
return tooltip_season_snow_objs, tooltip_percent_normal_objs, tooltip_percent_open_objs
def do_bokeh_bar_chart(resort_season_snow_df, resort_percent_normal_df, resort_percent_open_df, tt_objs, tc_last_update_string):
season_snow_source = ColumnDataSource(data=resort_season_snow_df)
percent_normal_source = ColumnDataSource(data=resort_percent_normal_df)
percent_open_source = ColumnDataSource(data=resort_percent_open_df)
season_snow_hover_list = []
for i in tt_objs[0]:
i = HoverTool(
line_policy=i.line_policy,
names=i.names,
tooltips=i.tooltips,
point_policy=i.point_policy, toggleable=i.toggleable)
season_snow_hover_list.append(i)
percent_normal_hover_list = []
for i in tt_objs[1]:
i = HoverTool(
line_policy=i.line_policy,
names=i.names,
tooltips=i.tooltips,
point_policy=i.point_policy, toggleable=i.toggleable)
percent_normal_hover_list.append(i)
percent_open_hover_list = []
for i in tt_objs[2]:
i = HoverTool(
line_policy=i.line_policy,
names=i.names,
tooltips=i.tooltips,
point_policy=i.point_policy, toggleable=i.toggleable)
percent_open_hover_list.append(i)
title_dic = {'Squaw 8,000': 'California',
'Whistler': 'Pacific Northwest',
'Lake Louise': 'Canadian Rockies and Interior B.C.',
'Grand Targhee': 'U. S. Northern Rockies',
'Alta': 'Utah',
'Vail': 'Northern and Central Colorado',
'Telluride': 'Southern and Western Colorado',
'Killington': 'Northeast'}
for k, v in title_dic.items():
if k in resort_season_snow_df.columns.tolist():
title = v
v = figure(x_range=(0, len(resort_list) + 1),
y_range=(0, resort_season_snow_df.values.max() + 50),
plot_height=500,
plot_width=900,
title=title + ' Snow Data ' + tc_last_update_string.last_update,
tools=['pan', 'box_zoom',
'wheel_zoom',
'reset'] + season_snow_hover_list + percent_normal_hover_list + percent_open_hover_list)
count = 0
for i in resort_list:
if resort_season_snow_df.values[0][count] != 0:
v.vbar(x=(count + 1)-0.2, top=resort_season_snow_df.values[0][count], width=0.2, color="lightblue", legend=value("season snow"),
name=season_snow_hover_list[count].names[0], source=season_snow_source)
count += 1
v.xaxis.ticker = [x for x in range(0, len(resort_list)+1)]
xaxis_lab_override_dic = {}
xaxis_lab_override_dic[0] = ''
count = 1
for x in resort_list:
xaxis_lab_override_dic[count] = x
count += 1
v.xaxis.major_label_overrides = xaxis_lab_override_dic
v.xaxis.major_label_orientation = math.pi/3
v.xaxis.axis_label = "resort"
v.yaxis.axis_label = "season snow (inches)"
#
v.legend.click_policy = 'hide'
v.legend.location = 'top_right'
v.extra_y_ranges = {"foo": Range1d(start=0, end=200)}
v.add_layout(LinearAxis(y_range_name="foo", axis_label="percent"), 'right')
# add percent of normal bars
count = 0
for i in resort_list:
if resort_percent_normal_df.values[0][count] != 0:
v.vbar(x=(count+ 1), top= resort_percent_normal_df.values[0][count], width=0.2, color="royalblue", legend=value("percent of normal"),
name=percent_normal_hover_list[count].names[0], source=percent_normal_source, y_range_name="foo")
count += 1
count = 0
for i in resort_list:
if resort_percent_open_df.values[0][count] != 0:
v.vbar(x=(count+ 1)+0.2, top=resort_percent_open_df.values[0][count], width=0.2, color="lightgreen", legend=value("percent open"),
name=percent_open_hover_list[count].names[0], source=percent_open_source, y_range_name="foo")
count += 1
show(v)
if __name__ == "__main__":
for i in range(1, 10):
try:
resort_df, tc_last_update_string = scrape_tc(i)
resort_season_snow_df, resort_percent_normal_df, resort_percent_open_df, resort_list = create_dfs(resort_df)
tt_objs = make_tooltip_objs(resort_list)
do_bokeh_bar_chart(resort_season_snow_df, resort_percent_normal_df, resort_percent_open_df, tt_objs, tc_last_update_string)
except:
print('done')
break
os.system('jupyter nbconvert --to html bokeh_snow_tracker_181213.ipynb')