-
Notifications
You must be signed in to change notification settings - Fork 161
Add tropical cyclones basin bounds #1031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
9c9150b
a111937
f37212f
7e82b8f
030bcb8
73889b9
cadf062
5a5c128
6056e6b
6e497ac
200a4eb
a72876d
9ffa59c
53b5bd6
9ca2ce3
5695e89
1f10bbc
dc60e2f
26e02b0
734f968
795071b
f582249
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,8 @@ | |
| import re | ||
| import shutil | ||
| import warnings | ||
| from operator import itemgetter | ||
| from collections import defaultdict | ||
| from enum import Enum | ||
| from pathlib import Path | ||
| from typing import List, Optional | ||
|
|
||
|
|
@@ -50,7 +51,8 @@ | |
| from matplotlib.collections import LineCollection | ||
| from matplotlib.colors import BoundaryNorm, ListedColormap | ||
| from matplotlib.lines import Line2D | ||
| from shapely.geometry import LineString, MultiLineString, Point | ||
| from shapely.geometry import LineString, MultiLineString, Point, Polygon | ||
| from shapely.ops import unary_union | ||
| from sklearn.metrics import DistanceMetric | ||
|
|
||
| import climada.hazard.tc_tracks_synth | ||
|
|
@@ -193,7 +195,103 @@ | |
| dataset using STORM. Scientific Data 7(1): 40.""" | ||
|
|
||
|
|
||
| class Basin_bounds_storm(Enum): | ||
|
Check warning on line 198 in climada/hazard/tc_tracks.py
|
||
|
NicolasColombi marked this conversation as resolved.
Outdated
|
||
| """ | ||
| Store tropical cyclones basin geographical extent. | ||
| The boundaries of the basin are represented as a polygon (using the `shapely` Polygon object) | ||
| and follows the definition of the STORM dataset. Important note: tropical cyclone boundaries | ||
| may vary bewteen datasets. The following boundaries follows the STORM definition: | ||
| https://www.nature.com/articles/s41597-020-0381-2 | ||
|
|
||
| Attributes: | ||
| ---------- | ||
| *name : str | ||
| The name of the tropical cyclone basin (e.g., "NA" for North Atlantic). | ||
| *polygon : Polygon | ||
| A shapely Polygon object that represents the geographical boundary of the basin. | ||
|
|
||
| """ | ||
|
|
||
| NA = Polygon( | ||
| [ | ||
| (-100, 19), | ||
| (-94.21951983987083, 17.039584804350312), | ||
| (-88.75211790888072, 14.837521327451947), | ||
| (-84.96610530622198, 12.214318798718033), | ||
| (-84.89823142225451, 12.181148019885352), | ||
| (-82.59052306410497, 8.777858931465238), | ||
| (-81.09730008320902, 8.358383265470449), | ||
| (-79.50226644452471, 9.196860922133856), | ||
| (-78.58597052442947, 9.213610839871123), | ||
| (-77.02487377167459, 7.299350879751048), | ||
| (-77.02487377167459, 5), | ||
| (0.0, 5.0), | ||
| (0.0, 60.0), | ||
| (-100.0, 60.0), | ||
| (-100, 19), | ||
| ] | ||
| ) | ||
|
|
||
| EP = Polygon( | ||
| [ | ||
| (-180.0, 5.0), | ||
| (-77.02487377167459, 5), | ||
| (-77.02487377167459, 7.299350879751048), | ||
| (-78.58597052442947, 9.213610839871123), | ||
| (-79.50226644452471, 9.196860922133856), | ||
| (-81.09730008320902, 8.358383265470449), | ||
| (-82.59052306410497, 8.777858931465238), | ||
| (-84.89823142225451, 12.181148019885352), | ||
| (-84.96610530622198, 12.214318798718033), | ||
| (-88.75211790888072, 14.837521327451947), | ||
| (-94.21951983987083, 17.039584804350312), | ||
| (-100, 19), | ||
| (-100.0, 60.0), | ||
| (-180.0, 60.0), | ||
| (-180.0, 5.0), | ||
| ] | ||
| ) | ||
|
|
||
| WP = Polygon( | ||
| [(100.0, 5.0), (180.0, 5.0), (180.0, 60.0), (100.0, 60.0), (100.0, 5.0)] | ||
| ) | ||
|
|
||
| NI = Polygon([(30.0, 5.0), (100.0, 5.0), (100.0, 60.0), (30.0, 60.0), (30.0, 5.0)]) | ||
|
|
||
| SI = Polygon( | ||
| [(10.0, -60.0), (135.0, -60.0), (135.0, -5.0), (10.0, -5.0), (10.0, -60.0)] | ||
| ) | ||
|
|
||
| SP = unary_union( | ||
| [ | ||
| Polygon( # west side of antimeridian | ||
| [ | ||
| (135.0, -60.0), | ||
| (180.0, -60.0), | ||
| (180.0, -5.0), | ||
| (135.0, -5.0), | ||
| (135.0, -60.0), | ||
| ] | ||
| ), | ||
| Polygon( # east side | ||
| [ | ||
| (-180.0, -60.0), | ||
| (-120.0, -60.0), | ||
| (-120.0, -5.0), | ||
| (-180.0, -5.0), | ||
| (-180.0, -60.0), | ||
| ] | ||
| ), | ||
| ] | ||
| ) | ||
|
|
||
|
|
||
| BASINS_GDF = gpd.GeoDataFrame( | ||
| {"basin": b, "geometry": b.value} for b in Basin_bounds_storm | ||
| ) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This beats the purpose of the enum class a bit. Please do without it if possible (I know this was proposed by @emanuel-schmid , but this is just a very minor change and allows for future flexibility). This should be part of the method
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure to understand: do you want to remove this or move it under
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think the naming is not well chosen because it is only one way to define basins, but let's keep it as is for the moment. Thanks! |
||
|
|
||
|
|
||
| class TCTracks: | ||
| """Contains tropical cyclone tracks. | ||
|
|
||
| Attributes | ||
|
|
@@ -322,7 +420,60 @@ | |
|
|
||
| return out | ||
|
|
||
| def get_basins(track): | ||
|
Check warning on line 423 in climada/hazard/tc_tracks.py
|
||
|
chahank marked this conversation as resolved.
|
||
|
|
||
| track_coordinates = gpd.GeoDataFrame( | ||
| geometry=gpd.points_from_xy(track.lon, track.lat) | ||
|
Check warning on line 426 in climada/hazard/tc_tracks.py
|
||
| ) | ||
| return track_coordinates.sjoin(BASINS_GDF, how="left", predicate="within").basin | ||
|
|
||
| def subset_by_basin(self, origin: bool = False): | ||
| """Subset all tropical cyclones tracks by basin. | ||
|
|
||
| This function collects for every basin the tracks that crossed them. The resulting dictionary | ||
| maps each basin's name to a list of tropical cyclones tracks that intersected them. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| self : TCTtracks object | ||
| The object instance containing the tropical cyclone data (`self.data`). | ||
| origin : bool | ||
| Either True or False. If True, the outputs basin will contain only the tracks that originated there. | ||
| If False, every track that crossed a basin will be present in the basin. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict_tc_basins : dict | ||
| A dictionary where the keys are basin names (e.g., "NA", "EP", "WP", etc.) and the | ||
| values are instances of the `TCTracks` class: effectively all tracks that intersected or originated | ||
| in each basin, depending on the argument "origin". | ||
|
chahank marked this conversation as resolved.
|
||
| tracks_outside_basin : list | ||
| A list of all tracks that did not cross any basin. | ||
|
|
||
| """ | ||
|
|
||
| basins_dict: dict = defaultdict(list) | ||
| tracks_outside_basin: list = [] | ||
|
|
||
| for track in self.data: | ||
| # if only origin basin is of interest (origin = True) | ||
| if origin: | ||
| origin_basin = TCTracks.get_basins(track)[0] | ||
| if origin_basin: | ||
| basins_dict[origin_basin.name].append(track) | ||
| else: | ||
| tracks_outside_basin.append(track) | ||
| else: # if every basin crossed is of interest (origin = False) | ||
| touched = TCTracks.get_basins(track).dropna().drop_duplicates() | ||
| if touched.size: | ||
| for basin in touched: | ||
| basins_dict[basin.name].append(track) | ||
| else: | ||
| tracks_outside_basin.append(track) | ||
|
|
||
| return basins_dict, tracks_outside_basin | ||
|
|
||
| def subset_year( | ||
|
Check warning on line 476 in climada/hazard/tc_tracks.py
|
||
| self, | ||
| start_date: tuple = (False, False, False), | ||
| end_date: tuple = (False, False, False), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.