xopr.geometry
1import geopandas as gpd 2import shapely 3import shapely.ops 4from pyproj import Transformer 5 6 7def get_antarctic_regions( 8 name=None, 9 regions=None, 10 subregions=None, 11 type=None, 12 merge_regions=True, 13 measures_boundaries_url = "https://storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson", 14 merge_in_projection="EPSG:3031", 15 simplify_tolerance=None 16): 17 """ 18 Load and filter Antarctic regional boundaries from the MEASURES dataset. 19 20 Parameters 21 ---------- 22 name : str or list, optional 23 NAME field value(s) to filter by 24 regions : str or list, optional 25 REGIONS field value(s) to filter by 26 subregions : str or list, optional 27 SUBREGION field value(s) to filter by 28 type : str or list, optional 29 TYPE field value(s) to filter by 30 merge_regions : bool, default True 31 If True, return a single merged geometry; if False, return list of geometries 32 measures_boundaries_url : str, default "https://storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson" 33 URL to the GeoJSON file containing Antarctic region boundaries 34 35 Returns 36 ------- 37 list or dict 38 If merge_regions=False: List of GeoJSON geometry dicts 39 If merge_regions=True: Single GeoJSON geometry dict of merged regions 40 41 Examples 42 -------- 43 # Get George VI ice shelf 44 >>> george_vi = get_antarctic_regions(name="George_VI", type="FL") 45 46 # Get all ice shelves, merged into one geometry 47 >>> all_shelves = get_antarctic_regions(type="FL", merge_regions=True) 48 49 # Get multiple regions by name 50 >>> regions = get_antarctic_regions(name=["George_VI", "LarsenC"]) 51 """ 52 53 54 # Load the boundaries GeoJSON from the reference URL 55 filtered = gpd.read_file(measures_boundaries_url) 56 57 # Apply filters based on provided parameters 58 if name is not None: 59 if isinstance(name, str): 60 name = [name] 61 filtered = filtered[filtered['NAME'].isin(name)] 62 63 if regions is not None: 64 if isinstance(regions, str): 65 regions = [regions] 66 filtered = filtered[filtered['Regions'].isin(regions)] 67 68 if subregions is not None: 69 if isinstance(subregions, str): 70 subregions = [subregions] 71 filtered = filtered[filtered['Subregions'].isin(subregions)] 72 73 if type is not None: 74 if isinstance(type, str): 75 type = [type] 76 filtered = filtered[filtered['TYPE'].isin(type)] 77 78 if len(filtered) == 0: 79 return [] if not merge_regions else None 80 81 if merge_regions: 82 83 if merge_in_projection: 84 filtered = filtered.to_crs(merge_in_projection) 85 86 # Check for invalid regions and attempt to fix them 87 invalid_geometries = filtered[~filtered.is_valid] 88 if len(invalid_geometries) > 0: 89 filtered = filtered.make_valid() 90 print(f"Warning: {len(invalid_geometries)} invalid geometries were fixed before merging.") 91 if merge_in_projection != "EPSG:3031": 92 print("Consider using merge_in_projection='EPSG:3031' to reproject before merging.") 93 print(f"Invalid geometry regions were: {', '.join(invalid_geometries['NAME'])}") 94 95 merged = shapely.ops.unary_union(filtered.geometry) # geopandas < 1.0 compat 96 97 if simplify_tolerance is None and (merge_in_projection == "EPSG:3031"): # Set a reasonable default based on the size 98 area_km2 = merged.area / 1e6 99 if area_km2 < 10000: 100 simplify_tolerance = 0 101 elif area_km2 < 100000: 102 print(f"Area is {area_km2:.1f} km^2, automatically applying 100m simplification tolerance") 103 print(f"To disable simplification, set simplify_tolerance=0") 104 simplify_tolerance = 100 105 else: 106 print(f"Area is {area_km2:.1f} km^2, automatically applying 1km simplification tolerance") 107 print(f"To disable simplification, set simplify_tolerance=0") 108 simplify_tolerance = 1000 109 110 if simplify_tolerance and (simplify_tolerance > 0): 111 merged = shapely.buffer(merged, simplify_tolerance).simplify(tolerance=simplify_tolerance) 112 113 if merge_in_projection: 114 merged = project_geojson(merged, source_crs=merge_in_projection, target_crs="EPSG:4326") 115 116 return merged 117 else: 118 return filtered 119 120def project_dataset(ds, target_crs): 121 """ 122 Project dataset coordinates from WGS84 to a target coordinate reference system. 123 124 Takes longitude and latitude coordinates from a dataset and projects them to 125 the specified target CRS, adding 'x' and 'y' coordinate arrays to the dataset. 126 127 Parameters 128 ---------- 129 ds : xarray.Dataset 130 Input dataset containing 'Longitude' and 'Latitude' coordinates 131 target_crs : cartopy.crs.CRS or str 132 Target coordinate reference system. Can be a cartopy CRS object or 133 a string representation (e.g., "EPSG:3031") 134 135 Returns 136 ------- 137 xarray.Dataset 138 Dataset with added 'x' and 'y' coordinate arrays in the target CRS 139 140 Examples 141 -------- 142 >>> import cartopy.crs as ccrs 143 >>> projected_ds = project_dataset(ds, ccrs.SouthPolarStereo()) 144 >>> projected_ds = project_dataset(ds, "EPSG:3031") 145 """ 146 if hasattr(target_crs, 'to_epsg') and target_crs.to_epsg(): 147 target_crs_str = f"EPSG:{target_crs.to_epsg()}" 148 elif isinstance(target_crs, str): 149 target_crs_str = target_crs 150 else: 151 target_crs_str = target_crs.to_proj4_string() 152 153 transformer = Transformer.from_crs("EPSG:4326", target_crs_str, always_xy=True) 154 projected_coords = transformer.transform(ds['Longitude'].values, ds['Latitude'].values) 155 156 ds = ds.assign_coords({ 157 'x': (('slow_time'), projected_coords[0]), 158 'y': (('slow_time'), projected_coords[1]) 159 }) 160 return ds 161 162def project_geojson(geometry, source_crs="EPSG:4326", target_crs="EPSG:3031"): 163 """ 164 Project a geometry from one coordinate reference system to another. 165 166 Uses pyproj.Transformer to reproject geometries between different 167 coordinate reference systems. Commonly used for projecting geometries 168 from WGS84 (lat/lon) to polar stereographic projections. 169 170 Parameters 171 ---------- 172 geometry : shapely.geometry.base.BaseGeometry 173 Input geometry to be projected 174 source_crs : str, default "EPSG:4326" 175 Source coordinate reference system (default is WGS84) 176 target_crs : str, default "EPSG:3031" 177 Target coordinate reference system (default is Antarctic Polar Stereographic) 178 179 Returns 180 ------- 181 shapely.geometry.base.BaseGeometry 182 Projected geometry in the target coordinate reference system 183 184 Examples 185 -------- 186 >>> from shapely.geometry import Point 187 >>> point = Point(-70, -75) # lon, lat in WGS84 188 >>> projected = project_geojson(point, "EPSG:4326", "EPSG:3031") 189 """ 190 transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True) 191 projected_geometry = shapely.ops.transform(transformer.transform, geometry) 192 return projected_geometry
def
get_antarctic_regions( name=None, regions=None, subregions=None, type=None, merge_regions=True, measures_boundaries_url='https://storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson', merge_in_projection='EPSG:3031', simplify_tolerance=None):
8def get_antarctic_regions( 9 name=None, 10 regions=None, 11 subregions=None, 12 type=None, 13 merge_regions=True, 14 measures_boundaries_url = "https://storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson", 15 merge_in_projection="EPSG:3031", 16 simplify_tolerance=None 17): 18 """ 19 Load and filter Antarctic regional boundaries from the MEASURES dataset. 20 21 Parameters 22 ---------- 23 name : str or list, optional 24 NAME field value(s) to filter by 25 regions : str or list, optional 26 REGIONS field value(s) to filter by 27 subregions : str or list, optional 28 SUBREGION field value(s) to filter by 29 type : str or list, optional 30 TYPE field value(s) to filter by 31 merge_regions : bool, default True 32 If True, return a single merged geometry; if False, return list of geometries 33 measures_boundaries_url : str, default "https://storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson" 34 URL to the GeoJSON file containing Antarctic region boundaries 35 36 Returns 37 ------- 38 list or dict 39 If merge_regions=False: List of GeoJSON geometry dicts 40 If merge_regions=True: Single GeoJSON geometry dict of merged regions 41 42 Examples 43 -------- 44 # Get George VI ice shelf 45 >>> george_vi = get_antarctic_regions(name="George_VI", type="FL") 46 47 # Get all ice shelves, merged into one geometry 48 >>> all_shelves = get_antarctic_regions(type="FL", merge_regions=True) 49 50 # Get multiple regions by name 51 >>> regions = get_antarctic_regions(name=["George_VI", "LarsenC"]) 52 """ 53 54 55 # Load the boundaries GeoJSON from the reference URL 56 filtered = gpd.read_file(measures_boundaries_url) 57 58 # Apply filters based on provided parameters 59 if name is not None: 60 if isinstance(name, str): 61 name = [name] 62 filtered = filtered[filtered['NAME'].isin(name)] 63 64 if regions is not None: 65 if isinstance(regions, str): 66 regions = [regions] 67 filtered = filtered[filtered['Regions'].isin(regions)] 68 69 if subregions is not None: 70 if isinstance(subregions, str): 71 subregions = [subregions] 72 filtered = filtered[filtered['Subregions'].isin(subregions)] 73 74 if type is not None: 75 if isinstance(type, str): 76 type = [type] 77 filtered = filtered[filtered['TYPE'].isin(type)] 78 79 if len(filtered) == 0: 80 return [] if not merge_regions else None 81 82 if merge_regions: 83 84 if merge_in_projection: 85 filtered = filtered.to_crs(merge_in_projection) 86 87 # Check for invalid regions and attempt to fix them 88 invalid_geometries = filtered[~filtered.is_valid] 89 if len(invalid_geometries) > 0: 90 filtered = filtered.make_valid() 91 print(f"Warning: {len(invalid_geometries)} invalid geometries were fixed before merging.") 92 if merge_in_projection != "EPSG:3031": 93 print("Consider using merge_in_projection='EPSG:3031' to reproject before merging.") 94 print(f"Invalid geometry regions were: {', '.join(invalid_geometries['NAME'])}") 95 96 merged = shapely.ops.unary_union(filtered.geometry) # geopandas < 1.0 compat 97 98 if simplify_tolerance is None and (merge_in_projection == "EPSG:3031"): # Set a reasonable default based on the size 99 area_km2 = merged.area / 1e6 100 if area_km2 < 10000: 101 simplify_tolerance = 0 102 elif area_km2 < 100000: 103 print(f"Area is {area_km2:.1f} km^2, automatically applying 100m simplification tolerance") 104 print(f"To disable simplification, set simplify_tolerance=0") 105 simplify_tolerance = 100 106 else: 107 print(f"Area is {area_km2:.1f} km^2, automatically applying 1km simplification tolerance") 108 print(f"To disable simplification, set simplify_tolerance=0") 109 simplify_tolerance = 1000 110 111 if simplify_tolerance and (simplify_tolerance > 0): 112 merged = shapely.buffer(merged, simplify_tolerance).simplify(tolerance=simplify_tolerance) 113 114 if merge_in_projection: 115 merged = project_geojson(merged, source_crs=merge_in_projection, target_crs="EPSG:4326") 116 117 return merged 118 else: 119 return filtered
Load and filter Antarctic regional boundaries from the MEASURES dataset.
Parameters
- name (str or list, optional): NAME field value(s) to filter by
- regions (str or list, optional): REGIONS field value(s) to filter by
- subregions (str or list, optional): SUBREGION field value(s) to filter by
- type (str or list, optional): TYPE field value(s) to filter by
- merge_regions (bool, default True): If True, return a single merged geometry; if False, return list of geometries
- measures_boundaries_url : str, default "https (//storage.googleapis.com/opr_stac/reference_geometry/measures_boundaries_4326.geojson"): URL to the GeoJSON file containing Antarctic region boundaries
Returns
- list or dict: If merge_regions=False: List of GeoJSON geometry dicts If merge_regions=True: Single GeoJSON geometry dict of merged regions
Examples
Get George VI ice shelf
>>> george_vi = get_antarctic_regions(name="George_VI", type="FL")
Get all ice shelves, merged into one geometry
>>> all_shelves = get_antarctic_regions(type="FL", merge_regions=True)
Get multiple regions by name
>>> regions = get_antarctic_regions(name=["George_VI", "LarsenC"])
def
project_dataset(ds, target_crs):
121def project_dataset(ds, target_crs): 122 """ 123 Project dataset coordinates from WGS84 to a target coordinate reference system. 124 125 Takes longitude and latitude coordinates from a dataset and projects them to 126 the specified target CRS, adding 'x' and 'y' coordinate arrays to the dataset. 127 128 Parameters 129 ---------- 130 ds : xarray.Dataset 131 Input dataset containing 'Longitude' and 'Latitude' coordinates 132 target_crs : cartopy.crs.CRS or str 133 Target coordinate reference system. Can be a cartopy CRS object or 134 a string representation (e.g., "EPSG:3031") 135 136 Returns 137 ------- 138 xarray.Dataset 139 Dataset with added 'x' and 'y' coordinate arrays in the target CRS 140 141 Examples 142 -------- 143 >>> import cartopy.crs as ccrs 144 >>> projected_ds = project_dataset(ds, ccrs.SouthPolarStereo()) 145 >>> projected_ds = project_dataset(ds, "EPSG:3031") 146 """ 147 if hasattr(target_crs, 'to_epsg') and target_crs.to_epsg(): 148 target_crs_str = f"EPSG:{target_crs.to_epsg()}" 149 elif isinstance(target_crs, str): 150 target_crs_str = target_crs 151 else: 152 target_crs_str = target_crs.to_proj4_string() 153 154 transformer = Transformer.from_crs("EPSG:4326", target_crs_str, always_xy=True) 155 projected_coords = transformer.transform(ds['Longitude'].values, ds['Latitude'].values) 156 157 ds = ds.assign_coords({ 158 'x': (('slow_time'), projected_coords[0]), 159 'y': (('slow_time'), projected_coords[1]) 160 }) 161 return ds
Project dataset coordinates from WGS84 to a target coordinate reference system.
Takes longitude and latitude coordinates from a dataset and projects them to the specified target CRS, adding 'x' and 'y' coordinate arrays to the dataset.
Parameters
- ds (xarray.Dataset): Input dataset containing 'Longitude' and 'Latitude' coordinates
- target_crs (cartopy.crs.CRS or str): Target coordinate reference system. Can be a cartopy CRS object or a string representation (e.g., "EPSG:3031")
Returns
- xarray.Dataset: Dataset with added 'x' and 'y' coordinate arrays in the target CRS
Examples
>>> import cartopy.crs as ccrs
>>> projected_ds = project_dataset(ds, ccrs.SouthPolarStereo())
>>> projected_ds = project_dataset(ds, "EPSG:3031")
def
project_geojson(geometry, source_crs='EPSG:4326', target_crs='EPSG:3031'):
163def project_geojson(geometry, source_crs="EPSG:4326", target_crs="EPSG:3031"): 164 """ 165 Project a geometry from one coordinate reference system to another. 166 167 Uses pyproj.Transformer to reproject geometries between different 168 coordinate reference systems. Commonly used for projecting geometries 169 from WGS84 (lat/lon) to polar stereographic projections. 170 171 Parameters 172 ---------- 173 geometry : shapely.geometry.base.BaseGeometry 174 Input geometry to be projected 175 source_crs : str, default "EPSG:4326" 176 Source coordinate reference system (default is WGS84) 177 target_crs : str, default "EPSG:3031" 178 Target coordinate reference system (default is Antarctic Polar Stereographic) 179 180 Returns 181 ------- 182 shapely.geometry.base.BaseGeometry 183 Projected geometry in the target coordinate reference system 184 185 Examples 186 -------- 187 >>> from shapely.geometry import Point 188 >>> point = Point(-70, -75) # lon, lat in WGS84 189 >>> projected = project_geojson(point, "EPSG:4326", "EPSG:3031") 190 """ 191 transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True) 192 projected_geometry = shapely.ops.transform(transformer.transform, geometry) 193 return projected_geometry
Project a geometry from one coordinate reference system to another.
Uses pyproj.Transformer to reproject geometries between different coordinate reference systems. Commonly used for projecting geometries from WGS84 (lat/lon) to polar stereographic projections.
Parameters
- geometry (shapely.geometry.base.BaseGeometry): Input geometry to be projected
- source_crs : str, default "EPSG (4326"): Source coordinate reference system (default is WGS84)
- target_crs : str, default "EPSG (3031"): Target coordinate reference system (default is Antarctic Polar Stereographic)
Returns
- shapely.geometry.base.BaseGeometry: Projected geometry in the target coordinate reference system
Examples
>>> from shapely.geometry import Point
>>> point = Point(-70, -75) # lon, lat in WGS84
>>> projected = project_geojson(point, "EPSG:4326", "EPSG:3031")