File size: 1,960 Bytes
c475b2d
 
 
 
1e333df
c475b2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd91e49
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
import matplotlib.pyplot as plt
import pandas as pd
import panel as pn
import tropycal.tracks as tracks

pn.extension("perspective")  # 1.

def update_name_options(year):
    names = sorted(basin_df.query(f"year == {year}")["name"].unique())
    name_select.options = names
    if not name_select.value or name_select.value not in names:
        name_select.value = names[0] if names else None

def update_storm_preview(name, year):
    try:
        storm_preview.loading = True
        storm_id = track_dataset.get_storm_id((name, year))
        axes = track_dataset.plot_storm(storm_id)
        plt.close(axes.figure)
        storm_preview.object = axes.figure
        storm_table.object = track_dataset.get_storm(storm_id).to_dataframe() # 4.
    finally:
        storm_preview.loading = False

@pn.cache
def initialize_data():
    track_dataset = tracks.TrackDataset(basin="both", source="hurdat")
    basin_df = pd.DataFrame.from_dict(track_dataset.data, orient="index")
    return track_dataset, basin_df

# Instantiate Widgets & Pane
year_slider = pn.widgets.IntSlider(
    name="Year", value=1950, start=1950, end=2022, step=1
)
name_select = pn.widgets.Select(name="Name")
storm_preview = pn.pane.Matplotlib(plt.figure(), sizing_mode="stretch_both")
storm_table = pn.pane.Perspective(editable=False, sizing_mode="stretch_both") # 2.

# Layout the app
sidebar = pn.Column(year_slider, name_select)
main = pn.Tabs(("Preview", storm_preview), ("Table", storm_table))  # 3.

template = pn.template.FastListTemplate(
    sidebar=sidebar,
    main=main,
    title="HURDAT Tracks Viewer"
)

# Initialize data
track_dataset, basin_df = initialize_data()

# Define Callbacks
pn.bind(update_name_options, year=year_slider.param.value_throttled, watch=True)
pn.bind(update_storm_preview, name=name_select, year=year_slider.param.value_throttled, watch=True)

# Pre-populate values
year_slider.param.trigger("value_throttled")

# Serve the app
template.servable()