-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstreamlit_app.py
More file actions
193 lines (171 loc) · 6.71 KB
/
Copy pathstreamlit_app.py
File metadata and controls
193 lines (171 loc) · 6.71 KB
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
"""
The safest times are {margin} hours either side of low tide and between dawn and dusk
when there is less danger to wildlife, especially the
[critically endangered loggerhead turtle](https://www.biepa.online/post/critically-endangered-next-stop-extinction)
mothers and hatchlings who nest and hatch on the beach from November to March.
Take all your litter and food home with you; food scraps attract native and feral animals
that prey on turtle eggs and hatchlings.
Please send helpful feedback to the BIEPA Wildlife Team at: wildlife@biepa.online
*Tide data obtained from the [BOM](http://bom.gov.au)
via [Willy Weather](https://www.willyweather.com.au/info/api.html),
interpolation formula thanks to
[Toitū Te Whenua](https://www.linz.govt.nz/products-services/tides-and-tidal-streams/tide-predictions),
coding by Mike Howells,
concept and design by [Darren Jew](https://darrenjew.com).*
*More [news](https://biepa.online/blog) and [events](https://biepa.online/events)
on the [BIEPA website](https://biepa.online).*
"""
from types import SimpleNamespace
import streamlit as st
import altair as alt
import pandas as pd
import tide_times
import chart_layers
locations = {
6781: "Southern Access Track, Woorim Beach",
17924: "Northern Access Track, Ocean Beach",
}
days_shown = 5
safe_hours = 3
def main():
with st.sidebar:
show_sidebar()
# Main area with placeholders for tides and times.
st.image("static/tread-lightly.jpg", use_container_width=True)
tides = st.container()
st.image("static/checklist.jpg", use_container_width=True)
st.success("🔄 If using your phone, rotate to landscape mode for a better view of the chart.")
settings = show_settings()
times = st.container()
# Get forecast equal days either side of driving date and show tides and times.
forecast = tide_times.safe_periods(
where=settings.where,
when=settings.when - pd.Timedelta(days=int(days_shown / 2)),
days=days_shown,
margin=safe_hours,
)
with tides:
show_chart(forecast)
with times:
show_table(forecast)
# Use docstring at top of this module for credits etc.
st.markdown(__doc__.format(margin=safe_hours))
def show_sidebar():
st.image("static/biepa_logo_fullcolour_biepaonly.png")
st.info(
"Find the turtle-friendly times to drive on the beach."
" Be turtle-aware!"
)
st.markdown(
"<small>© 2023, Bribie Island Environmental Protection Association Inc.</small>",
unsafe_allow_html=True,
)
def show_settings():
settings = SimpleNamespace()
left, right = st.columns(2)
with left:
settings.when = st.date_input(
key="when",
help="The chart will show tides for three days around this date.",
label="When will you be driving?",
value=url_value(key="when", convert=to_date, default="today"),
format="YYYY-MM-DD",
)
with right:
settings.where = st.selectbox(
key="where",
help="The chart will show tide heights for the closest monitoring station.",
label="Where will you be driving?",
options=locations,
index=0, # Default to first location.
format_func=locations.get,
)
return settings
def url_value(key, convert=None, default=None):
value = st.session_state.get(key)
if value is not None:
return value
value = st.query_params.get(key)
if value is not None:
return convert(value[0]) if convert else value[0]
return default
def to_date(string):
return pd.Timestamp(string).date()
def show_chart(forecast):
sun = forecast['sun']
tides = forecast['tides']
if tides is None:
st.error("No tide data available for selected location")
return
# Get just the times of low and high tides.
low = tides[tides["type"] == "low"].copy()
high = tides[tides["type"] == "high"].copy()
# Create layered chart of tide heights and safer times.
# NOTE: Order is important as layers overlap.
chart = alt.layer(
chart_layers.darkness(sun),
chart_layers.days(sun),
chart_layers.heights(tides),
chart_layers.curve(tides, safe=True),
chart_layers.curve(tides, safe=False),
chart_layers.crosses(high),
chart_layers.periods(low, high),
chart_layers.hints(high, label="travel between"),
# chart_layers.icons(high), # not working yet
)
st.altair_chart(
chart.configure_view(
stroke="#aaa",
strokeWidth=1,
continuousHeight=400,
).properties(
width='container',
).interactive(bind_y=False),
use_container_width=True,
)
def show_table(forecast):
# Show location for tide times.
location = forecast['location']
maps = (
"https://www.google.com/maps/@?api=1&map_action=map&zoom=14&basemap=terrain"
f"¢er={location['lat']}%2C{location['lng']}"
)
st.markdown(
"Turtle-friendly driving times for the beach near"
f" [{location['name']}, {location['region']}, {location['state']}]({maps})"
f" where times are in {location['timeZone']} time-zone."
)
# Show safe periods in a table for small screens.
tides = forecast['tides']
if tides is None:
st.error("No tide data available for selected location")
else:
# Exclude times outside chart time window.
earliest = tides['day'].min() + pd.Timedelta(days=1)
latest = tides['day'].max() - pd.Timedelta(days=1)
tides = tides[(tides['day'] >= earliest) & (tides['day'] <= latest)]
# Get start and end of safer times around low tide.
tides = tides[(tides['type'] == "low") & tides['earliest'].notnull() & tides['latest'].notnull()]
st.dataframe(
data=tides[['day', 'earliest', 'latest']],
hide_index=True,
column_config={
'day': st.column_config.DateColumn(label="Day", width="medium", format="ddd D MMM YYYY"),
'earliest': st.column_config.DatetimeColumn(label="From", width="medium", format="h:mm a"),
'latest': st.column_config.DatetimeColumn(label="To", width="medium", format="h:mm a"),
},
)
if __name__ == "__main__":
# Streamlit preferences.
st.set_page_config(
page_title="Tread Lightly on Bribie Island",
page_icon="🛞",
layout="wide",
initial_sidebar_state="collapsed",
menu_items={
"About": "Helping visitors to Bribie Island protect endangered wildlife.",
"Get help": "https://biepa.online/contact",
"Report a bug": "https://github.com/quantoid/tides/issues",
}
)
main()