|
import datetime |
|
import io |
|
import os |
|
import requests |
|
|
|
import geopandas as gpd |
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
import streamlit as st |
|
import xarray as xr |
|
|
|
from geogif import gif |
|
from rasterio import features |
|
|
|
provinces = gpd.read_file("./data/prov_stat.geojson") |
|
geoms = provinces.geometry.boundary |
|
|
|
image = features.rasterize( |
|
geoms, |
|
out_shape=[381, 1081], |
|
transform=(0.10000000149011612, 0.0, -160.0, 0.0, 0.10000000149011612, 32.0), |
|
) |
|
|
|
cmap = st.selectbox("Colormap", plt.colormaps(), index=1) |
|
|
|
fps = st.slider("Frames per second", 0.01, 50.0, 16.0) |
|
|
|
show_dt = st.checkbox("Show timestamp", True) |
|
|
|
fetch_data = st.checkbox("Refresh data", False) |
|
|
|
if st.button("Create GIF"): |
|
smoke_url = "https://firesmoke.ca/forecasts/current/dispersion.nc" |
|
smoke_nc = "./data/dispersion.nc" |
|
if not os.path.isfile(smoke_nc) or fetch_data: |
|
response = requests.head(smoke_url) |
|
|
|
total_size = int(response.headers.get("Content-Length")) |
|
|
|
progress_text = "Downloading data. Please wait." |
|
progress_bar = st.progress(0, text=progress_text) |
|
|
|
size_downloaded = 0 |
|
chunk_size = 8192 |
|
|
|
with requests.get(smoke_url, stream=True) as r: |
|
r.raise_for_status() |
|
with open(smoke_nc, "wb") as f: |
|
for chunk in r.iter_content(chunk_size=chunk_size): |
|
f.write(chunk) |
|
|
|
size_downloaded += chunk_size |
|
percent_complete = min(size_downloaded / total_size, 1) |
|
progress_bar.progress(percent_complete, text=progress_text) |
|
|
|
progress_bar.empty() |
|
|
|
ds_disk = xr.open_dataset(smoke_nc) |
|
|
|
tstep = ds_disk.TFLAG |
|
|
|
dts = [] |
|
for i in tstep: |
|
data = i.data[0] |
|
dt = datetime.datetime.strptime( |
|
str(data[0]) + str(data[1]).zfill(6), "%Y%j%H%M%S" |
|
) |
|
dts.append(dt) |
|
|
|
pm25 = ds_disk.PM25 |
|
|
|
pm25["TSTEP"] = dts |
|
|
|
for idx, i in enumerate(pm25.data): |
|
pm25[idx].data[0] = np.maximum(i[0], image * 6) |
|
|
|
buffer = io.BytesIO() |
|
|
|
if show_dt: |
|
date_format = "%Y-%m-%d %H:%M:%S" |
|
else: |
|
date_format = None |
|
|
|
gif( |
|
pm25[:, :, ::-1, :], |
|
date_format=date_format, |
|
fps=fps, |
|
cmap=cmap, |
|
date_color=(255, 255, 255), |
|
to=buffer, |
|
) |
|
|
|
first_dt = dts[0] |
|
last_dt = dts[-1] |
|
|
|
st.image(buffer, caption=f"{first_dt} to {last_dt}") |
|
st.download_button( |
|
label="Download GIF", data=buffer, file_name="firesmoke.gif", mime="image/gif" |
|
) |
|
|
|
with st.expander("Data Sources"): |
|
st.markdown(f"Smoke forecast: [FireSmoke Canada](https://firesmoke.ca/)") |
|
st.markdown( |
|
f"Administrative boundaries: [Natural Earth, 1:50M Admin 1 – States, provinces](https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_1_states_provinces.zip)" |
|
) |
|
|