Skip to content

Commit

Permalink
added track database for refactored tc and track selector
Browse files Browse the repository at this point in the history
  • Loading branch information
maartenvanormondt committed Oct 25, 2024
1 parent 2967e0a commit bd0f3fb
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 30 deletions.
2 changes: 2 additions & 0 deletions cht_cyclones/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@

from .tropical_cyclone import TropicalCyclone
from .track_database import CycloneTrackDatabase
from .track_selector import track_selector

42 changes: 42 additions & 0 deletions cht_cyclones/cyclone_track_selector.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
window:
title: Select Cyclone Track ...
width: 800
height: 500
module: cht_cyclones.track_selector
variable_group: cyclone_track_selector
modal: true
cancel: true
element:
- style: edit
variable: distance
method: edit_filter
text: Distance (km)
position:
x: 100
y: 70
width: 50
height: 20
- style: edit
variable: year0
method: edit_filter
text: Year
position:
x: 100
y: 45
width: 50
height: 20
- style: edit
variable: year1
method: edit_filter
position:
x: 160
y: 45
width: 50
height: 20
- style: mapbox
id: track_selector_map
position:
x: 20
y: 100
width: -20
height: -20
18 changes: 14 additions & 4 deletions cht_cyclones/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ class TropicalCycloneEnsemble:
def __init__(self, tropical_cyclone,
name="ensemble",
number_of_realizations=10,
compute_wind_fields=True,
dt=3,
tstart=None,
tend=None,
duration=None,
track_path=None,
spw_path=None,
mean_abs_cte24=19.0397,
Expand All @@ -44,6 +46,8 @@ def __init__(self, tropical_cyclone,
# If name is not given, use the name of the tropical cyclone
self.name = name

self.compute_wind_fields = compute_wind_fields

if track_path is None:
track_path = os.getcwd()
if spw_path is None:
Expand Down Expand Up @@ -71,7 +75,7 @@ def __init__(self, tropical_cyclone,
self.sc_ve = sc_ve # auto-regression VE = 1 = no auto-regression
self.bias_ve = bias_ve # bias per hour

self.tropical_cyclone = tropical_cyclone
self.tropical_cyclone = copy.deepcopy(tropical_cyclone)

# Set scale factor of the best track to 1.0
self.tropical_cyclone.track.gdf.loc[:,"wind_scale_factor"] = pd.Series(np.zeros(len(self.tropical_cyclone.track.gdf)) + 1.0,
Expand All @@ -85,7 +89,12 @@ def __init__(self, tropical_cyclone,
self.tstart = tstart

if tend is not None:
self.tropical_cyclone.track.shorten(tend=tend)
# Do we really want to shorten the track?
self.tropical_cyclone.track.shorten(tend=tend)
else:
if duration is not None:
tend = self.tstart + pd.Timedelta(duration, unit="h")
self.tropical_cyclone.track.shorten(tend=tend)

# Make sure the metric track is computed
self.tropical_cyclone.compute_metric_track()
Expand All @@ -111,7 +120,8 @@ def generate(self):

self.generate_tracks() # Generates the tracks and vmax values for the individual ensemble members

self.compute_wind_fields() # Computes the wind fields by scaling
if self.compute_wind_fields:
self.compute_wind_fields() # Computes the wind fields by scaling

def generate_tracks(self):

Expand Down Expand Up @@ -204,7 +214,7 @@ def to_gdf(self,
# Get the GDF
if option == "tracks":
gdf = self.tracks_to_gdf()
elif option == "outline":
elif option == "outline" or option == "cone":
gdf = self.outline_to_gdf(buffer, only_forecast)

# Write to file
Expand Down
4 changes: 4 additions & 0 deletions cht_cyclones/fileio.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from datetime import datetime
import geopandas as gpd
from shapely.geometry import Point

class TropicalCycloneTrack:
def __init__(self):
pass
Expand Down
53 changes: 27 additions & 26 deletions cht_cyclones/track_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ def get_track(self, index):
# Create a TropicalCyclone object
tc = TropicalCyclone(name=self.name[index])

gdf = gpd.GeoDataFrame()

# Add track
for it in range(self.ntimes):
# Check if track is finite
Expand Down Expand Up @@ -159,42 +161,41 @@ def get_track(self, index):
R100_NW = -999.0

# Create a geopandas dataframe
gdf = gpd.GeoDataFrame(
gdf_point = gpd.GeoDataFrame(
{
"datetime": [tc_time_string],
"geometry": [point],
"vmax": [vmax],
"pc": [pc],
"RMW": [RMW],
"R35_NE": [R35_NE],
"R35_SE": [R35_SE],
"R35_SW": [R35_SW],
"R35_NW": [R35_NW],
"R50_NE": [R50_NE],
"R50_SE": [R50_SE],
"R50_SW": [R50_SW],
"R50_NW": [R50_NW],
"R65_NE": [R65_NE],
"R65_SE": [R65_SE],
"R65_SW": [R65_SW],
"R65_NW": [R65_NW],
"R100_NE": [R100_NE],
"R100_SE": [R100_SE],
"R100_SW": [R100_SW],
"R100_NW": [R100_NW],
"rmw": [RMW],
"r35_ne": [R35_NE],
"r35_se": [R35_SE],
"r35_sw": [R35_SW],
"r35_nw": [R35_NW],
"r50_ne": [R50_NE],
"r50_se": [R50_SE],
"r50_sw": [R50_SW],
"r50_nw": [R50_NW],
"r65_ne": [R65_NE],
"r65_se": [R65_SE],
"r65_sw": [R65_SW],
"r65_nw": [R65_NW],
"r100_ne": [R100_NE],
"r100_se": [R100_SE],
"r100_sw": [R100_SW],
"r100_nw": [R100_NW],
}
)

# Set CRS coordinate system
gdf.set_crs(epsg=4326, inplace=True)

# Append self
tc.track = pd.concat([tc.track, gdf])
gdf = pd.concat([gdf, gdf_point])

# Replace -999.0 with NaN
gdf = gdf.replace(-999.0, np.nan)
gdf = gdf.reset_index(drop=True)
gdf = gdf.set_crs(crs=4326, inplace=True)

# Done with this
tc.track = tc.track.reset_index(drop=True)
tc.track = tc.track.drop([0]) # remove the dummy
tc.track = tc.track.reset_index(drop=True)
tc.track.gdf = gdf

return tc

Expand Down
89 changes: 89 additions & 0 deletions cht_cyclones/track_selector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import os

def track_selector(database, app, lon=0.0, lat=0.0, distance=1000.0, year_min=1850, year_max=2030):

app.gui.setvar("cyclone_track_selector", "lon", lon)
app.gui.setvar("cyclone_track_selector", "lat", lat)
app.gui.setvar("cyclone_track_selector", "distance", distance)
app.gui.setvar("cyclone_track_selector", "year0", year_min)
app.gui.setvar("cyclone_track_selector", "year1", year_max)
app.gui.setvar("cyclone_track_selector", "name", "")

data = {}
data["track_database"] = database

# Read GUI config file
config_file = os.path.join(os.path.dirname(__file__), "cyclone_track_selector.yml")
okay, data = app.gui.popup(config_file, id="track_selector", data=data)

track = None
if okay:
# Get the track from the database
track = database.get_track(data["database_index"])

return track, okay

def map_ready(widget):

print("Selector map is ready !")

gui = widget.element.gui

mp = gui.popup_window["track_selector"].find_element_by_id("track_selector_map").widget
mp.jump_to(0.0, 0.0, 1)
data = gui.popup_data
# Container layers
data["track_selector"]["main_layer"] = mp.add_layer("track_selector")
# Tracks layers
data["track_selector"]["track_layer"] = data["track_selector"]["main_layer"].add_layer(
"tracks",
type="line_selector",
file_name="tracks.geojson",
select=select_track,
selection_type="single",
line_color="dodgerblue",
line_width=2,
line_color_selected="red",
line_width_selected=3,
hover_param="description",
)

# Update data in tracks layer
update_tracks(gui)


def update_tracks(gui):

data = gui.popup_data

tdb = data["track_selector"]["track_database"]
tracks_layer = data["track_selector"]["track_layer"]

# Get filter data
distance = gui.getvar("cyclone_track_selector", "distance")
year_min = gui.getvar("cyclone_track_selector", "year0")
year_max = gui.getvar("cyclone_track_selector", "year1")
lon = gui.getvar("cyclone_track_selector", "lon")
lat = gui.getvar("cyclone_track_selector", "lat")

# Get indices based on filter
index = tdb.filter(
lon=lon, lat=lat, distance=distance, year_min=year_min, year_max=year_max
)

# Get GeoDataFrame of tracks
gdf = tdb.to_gdf(index=index)

tracks_layer.set_data(gdf, 0)


def map_moved(coords, widget):
pass


def select_track(feature, widget):
widget.element.gui.popup_data["track_selector"]["database_index"] = feature["properties"]["database_index"]


def edit_filter(val, widget):
update_tracks(widget.element.gui)

0 comments on commit bd0f3fb

Please sign in to comment.