import os import cartopy cartopy.config['data_dir'] = os.path.expanduser("~/.cache") 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()