-
Notifications
You must be signed in to change notification settings - Fork 0
/
app_server.py
156 lines (131 loc) · 5.13 KB
/
app_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from bokeh.layouts import column, row
from bokeh.models import Button, TextInput, Div, RadioButtonGroup, PreText, RadioGroup
from bokeh.models.callbacks import CustomJS
from bokeh.plotting import curdoc
from gmaps_client import init_client
from googlemaps.exceptions import ApiError, HTTPError, Timeout, TransportError
from bokeh_plots import plot_elevation_graphs, plot_gradient_graphs, plot_map, plot_gradient_histogram # noqa: E501
MAX_GRADIENT = 24
gmaps = init_client()
search_results = []
def radio_text(route):
"""Returns a short representation of a Route
Args:
route: a Route object
Returns:
str: a string containing the route summary and duration
"""
text = " ".join([
"via " + route.summary,
f"({max(1, round(route.duration / 60))} minutes)"
])
return text
def find_routes():
"""Callback for the go button. Obtains the planned routes and fills the document with plots.
Modifies nonlocal mutable variables!
"""
modes = ["bicycling", "driving", "walking"]
try:
results = gmaps.get_directions(
origin=origin_input.value,
destination=destination_input.value,
mode=modes[type_input.active],
alternatives=True
)
except (ApiError, HTTPError, Timeout, TransportError) as e:
if alert_holder.text == str(e):
alert_holder.text += " "
else:
alert_holder.text = str(e)
return
search_results.clear()
search_results.extend(results)
result_picker.labels = [radio_text(route) for route in search_results]
result_picker.active = None
try:
for result in search_results:
result.get_elevations(gmaps)
result.calculate_segment_data()
except (ApiError, HTTPError, Timeout, TransportError) as e:
if alert_holder.text == str(e):
alert_holder.text += " "
else:
alert_holder.text = str(e)
return
graph_pane.children.clear()
plot_elevation_graphs(graph_pane, elevation_graph_glyphs, search_results)
plot_gradient_graphs(graph_pane, gradient_graph_glyphs, search_results, MAX_GRADIENT)
plot_gradient_histogram(graph_pane, gradient_histogram_glyphs, search_results, MAX_GRADIENT)
if len(map_pane.children) == 2:
del map_pane.children[0]
plot_map(map_pane, map_plot_glyphs, search_results)
def display_results(attr, new, old):
"""Callback for the route picker radio buttons. Highlights the route on the plots.
Modifies nonlocal mutable variables!
"""
if result_picker.active is None:
instructions.text = ""
else:
active_result = search_results[result_picker.active]
instructions.text = "<br>".join(active_result.instructions)
if (len(search_results) == len(elevation_graph_glyphs)
== len(map_plot_glyphs) == len(gradient_histogram_glyphs)):
for i in range(len(search_results)):
if i == result_picker.active:
elevation_graph_glyphs[i].glyph.line_color = "#5cb85c"
gradient_graph_glyphs[i].glyph.line_color = "#5cb85c"
map_plot_glyphs[i].glyph.line_color = "#5cb85c"
elevation_graph_glyphs[i].glyph.line_alpha = 1
gradient_graph_glyphs[i].glyph.line_alpha = 1
map_plot_glyphs[i].glyph.line_alpha = 1
gradient_histogram_glyphs[i].visible = True
else:
elevation_graph_glyphs[i].glyph.line_color = "#8f8f8f"
gradient_graph_glyphs[i].glyph.line_color = "#8f8f8f"
map_plot_glyphs[i].glyph.line_color = "#8f8f8f"
elevation_graph_glyphs[i].glyph.line_alpha = 0.2
gradient_graph_glyphs[i].glyph.line_alpha = 0.2
map_plot_glyphs[i].glyph.line_alpha = 0.3
gradient_histogram_glyphs[i].visible = False
###############################
# Route selection pane (left) #
###############################
origin_input = TextInput(width=400, title="Origin")
destination_input = TextInput(width=400, title="Destination")
type_input = RadioButtonGroup(
labels=["Bicycle", "Driving", "Walking"],
width=400,
active=0
)
go_button = Button(width=400, label="Search", button_type="success")
go_button.on_click(find_routes)
alert_holder = PreText(text="", css_classes=['hidden'], visible=False)
alert = CustomJS(args={}, code='alert(cb_obj.text);')
alert_holder.js_on_change("text", alert)
result_picker = RadioGroup(labels=[], width=400)
result_picker.on_change("active", display_results)
route_selection_pane = column(
Div(text="<h2>Search</h2>"),
origin_input,
destination_input,
type_input,
go_button,
alert_holder,
Div(text="<h2>Results</h2>"),
result_picker
)
#####################
# Map pane (middle) #
#####################
map_plot_glyphs = []
instructions = Div(text="", width=600)
map_pane = column(instructions)
######################
# Graph pane (right) #
######################
elevation_graph_glyphs = []
gradient_graph_glyphs = []
gradient_histogram_glyphs = []
graph_pane = column()
layout = row(route_selection_pane, map_pane, graph_pane)
curdoc().add_root(layout)