@@ -783,12 +783,22 @@ def get_country_geometries(
783783 if country_names :
784784 if isinstance (country_names , str ):
785785 country_names = [country_names ]
786+
787+ # print warning if ISO code not recognized
788+ for country_name in country_names :
789+ if not country_name in nat_earth [["ISO_A3" , "WB_A3" , "ADM0_A3" ]].values :
790+ LOGGER .warning (f"ISO code { country_name } not recognized." )
791+
786792 country_mask = np .isin (
787793 nat_earth [["ISO_A3" , "WB_A3" , "ADM0_A3" ]].values ,
788794 country_names ,
789795 ).any (axis = 1 )
790796 out = out [country_mask ]
791797
798+ # exit with Value error if no country code was recognized
799+ if out .size == 0 :
800+ raise ValueError (f"None of the given country codes were regocnized." )
801+
792802 if extent :
793803 if extent [1 ] - extent [0 ] > 360 :
794804 raise ValueError (
@@ -1687,102 +1697,84 @@ def _ensure_utf8(val):
16871697 return admin1_info , admin1_shapes
16881698
16891699
1690- def boundsNESW_from_global ():
1700+ def global_bounding_box ():
16911701 """
1692- Return global NESW bounds in EPSG 4326
1702+ Return global bounds in EPSG 4326
16931703
16941704 Returns
16951705 -------
1696- list :
1697- The calculated bounding box as [north, east, south, west] in EPSG 4326
1706+ tuple :
1707+ The global bounding box as (min_lon, min_lat, max_lon, max_lat)
16981708 """
1699- return [ 90 , 180 , - 90 , - 180 ]
1709+ return ( - 180 , - 90 , 180 , 90 )
17001710
17011711
1702- def boundsNESW_from_country_codes ( country_codes , rel_margin = 0.2 ):
1712+ def get_country_bounding_box ( country_names , buffer = 1.0 ):
17031713 """
1704- Return NESW bounds in EPSG 4326 for the combined area defined by given country ISO codes .
1714+ Return bounding box in EPSG 4326 containing given countries .
17051715
17061716 Parameters
17071717 ----------
1708- country_codes : list
1709- A list of ISO country codes ( e.g.,['ITA'], ['ITA ', 'CHE']).
1710- rel_margin : float
1711- A relative margin to extend the bounding box in all directions . Default is 0.2 .
1718+ country_names : list or str
1719+ list with ISO 3166 alpha-3 codes of countries, e.g ['ZWE', 'GBR ', 'VNM', 'UZB']
1720+ buffer : float, optional
1721+ Buffer to add to both sides of the bounding box. Default: 1.0 .
17121722
17131723 Returns
17141724 -------
1715- list:
1716- The calculated bounding box as [north, east, south, west] in EPSG 4326
1717- """
1718- [north , east , south , west ] = [- 90 , - 180 , 90 , 180 ]
1719-
1720- # loop through ISO codes
1721- for iso in country_codes :
1722- geo = get_country_geometries (iso ).to_crs (epsg = 4326 )
1723- iso_west , iso_south , iso_east , iso_north = geo .total_bounds
1724- if np .any (np .isnan ([iso_west , iso_south , iso_east , iso_north ])):
1725- LOGGER .warning (
1726- f"ISO code '{ iso } ' not recognized. This region will not be included."
1727- )
1728- continue
1729-
1730- north = max (north , iso_north )
1731- east = max (east , iso_east )
1732- south = min (south , iso_south )
1733- west = min (west , iso_west )
1734-
1735- # no countries recognized
1736- if [north , east , south , west ] == [- 90 , - 180 , 90 , 180 ]:
1737- raise Exception ("No ISO code was recognized." )
1725+ tuple
1726+ The bounding box containing all given coutries as (min_lon, min_lat, max_lon, max_lat)
1727+ """
17381728
1739- # add relative margin
1740- lat_margin = rel_margin * ( north - south )
1741- lon_margin = rel_margin * ( east - west )
1742- north = min ( north + lat_margin , 90 )
1743- east = min ( east + lon_margin , 180 )
1744- south = max ( south - lat_margin , - 90 )
1745- west = max ( west - lon_margin , - 180 )
1729+ country_geometry = get_country_geometries ( country_names ). geometry
1730+ longitudes , latitudes = [], []
1731+ for multipolygon in country_geometry :
1732+ for polygon in multipolygon . geoms : # Loop through each polygon
1733+ for coord in polygon . exterior . coords : # Extract exterior coordinates
1734+ longitudes . append ( coord [ 0 ] )
1735+ latitudes . append ( coord [ 1 ] )
17461736
1747- return [ north , east , south , west ]
1737+ return latlon_bounds ( np . array ( latitudes ), np . array ( longitudes ), buffer = buffer )
17481738
17491739
1750- def boundsNESW_from_NESW (* , north , east , south , west , rel_margin = 0.0 ):
1740+ def bounds_from_cardinal_bounds (* , northern , eastern , western , southern ):
17511741 """
1752- Return NESW bounds in EPSG 4326 with relative margin from given NESW values in EPSG 4326 .
1742+ Return and normalize bounding box in EPSG 4326 from given cardinal bounds .
17531743
17541744 Parameters
17551745 ----------
1756- north : (float, int)
1757- Maximal latitude in EPSG 4326.
1758- east : (float, int)
1759- Maximal longitute in EPSG 4326.
1760- south : (float, int)
1761- Minimal latitude in EPSG 4326.
1762- west : (float, int)
1763- Minimal longitude in EPSG 4326.
1764- rel_margin : float
1765- A relative margin to extend the bounding box in all directions. Default is 0.2.
1746+ northern : (int, float)
1747+ Northern boundary of bounding box
1748+ eastern : (int, float)
1749+ Eastern boundary of bounding box
1750+ western : (int, float)
1751+ Western boundary of bounding box
1752+ southern : (int, float)
1753+ Southern boundary of bounding box
17661754
17671755 Returns
17681756 -------
1769- list:
1770- The calculated bounding box as [north, east, south, west] in EPSG 4326
1757+ tuple
1758+ The resulting normalized bounding box (min_lon, min_lat, max_lon, max_lat) with -180 <= min_lon < max_lon < 540
1759+
17711760 """
17721761
1773- # simple bounds check
1774- if not ((90 >= north > south >= - 90 ) and (180 >= east > west >= - 180 )):
1775- raise ValueError ("Given bounds are not in standard order or standard bounds" )
1762+ # latitude bounds check
1763+ if not ((90 >= northern > southern >= - 90 )):
1764+ raise ValueError (
1765+ "Given northern bound is below given southern bound or out of bounds"
1766+ )
17761767
1777- # add relative margin
1778- lat_margin = rel_margin * (north - south )
1779- lon_margin = rel_margin * (east - west )
1780- north = min (north + lat_margin , 90 )
1781- east = min (east + lon_margin , 180 )
1782- south = max (south - lat_margin , - 90 )
1783- west = max (west - lon_margin , - 180 )
1768+ if not (360 >= eastern >= - 180 ) or not (360 >= western >= - 180 ):
1769+ raise ValueError ("Given eastern/western bounds are out of range (-180, 360)." )
1770+ # order eastern and western coordinates
1771+ if western > eastern :
1772+ eastern += 360
1773+ if eastern > 360 and western > 180 :
1774+ eastern -= 360
1775+ western -= 360
17841776
1785- return [ north , east , south , west ]
1777+ return ( western , southern , eastern , northern )
17861778
17871779
17881780def get_admin1_geometries (countries ):
0 commit comments