diff --git a/docs/index.rst b/docs/index.rst index 054b313..8926ddc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -47,5 +47,5 @@ and then request area of interest from their name or GADM code: import pygadm - gdf = pygadm.AdmItems(name="Singapore", content_level=1) + gdf = pygadm.Items(name="Singapore", content_level=1) diff --git a/docs/usage.rst b/docs/usage.rst index b16ebea..8db3b00 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -9,7 +9,7 @@ The PyGADM lib can be used to extract information from the GADM dataset as GeoPa Countries ^^^^^^^^^ -Using the :code:`AdmItems` class, you can access an administrative area using either its name or its GADM identification code. +Using the :code:`Items` class, you can access an administrative area using either its name or its GADM identification code. For example to extract the France geometry you can use the following code: @@ -18,7 +18,7 @@ For example to extract the France geometry you can use the following code: import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(name="France") + gdf = pygadm.Items(name="France") # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[46.21, 2.21]) @@ -33,7 +33,7 @@ If you know the code of the area you try to use, you can use the GADM code inste import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(admin="FRA") + gdf = pygadm.Items(admin="FRA") # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[46.21, 2.21]) @@ -51,7 +51,7 @@ One is not bind to only request a country, any level can be accessed using both import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(name="Corse-du-Sud") + gdf = pygadm.Items(name="Corse-du-Sud") # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=8, center=[41.86, 8.97]) @@ -73,7 +73,7 @@ Using the :code:`content_level` option, one can require smaller administrative l import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(admin="FRA", content_level=2) + gdf = pygadm.Items(admin="FRA", content_level=2) # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[46.21, 2.21]) @@ -95,7 +95,7 @@ To perform regional analysis that aggregate multiple boundaries, you can now req import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(name=["France", "Germany"]) + gdf = pygadm.Items(name=["France", "Germany"]) # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=5, center=[48.83, 5.17]) @@ -121,7 +121,7 @@ It's possible to request all countries from one single continent using one of th import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(name="south america") + gdf = pygadm.Items(name="south america") # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=2, center=[-20.30, -59.32]) @@ -136,7 +136,7 @@ It's possible to request all countries from one single continent using one of th Find administrative names ------------------------- -To get the available name and GADM code in a administrative layer you can use the :code:`AdmNames` class with the same parameters. Use then these names in a :code:`AdmItems` request to get the geometry. +To get the available name and GADM code in a administrative layer you can use the :code:`Names` class with the same parameters. Use then these names in a :code:`Items` request to get the geometry. For example to get the name and codes of all the departments in France you can run: @@ -144,7 +144,7 @@ For example to get the name and codes of all the departments in France you can r import pygadm - pygadm.AdmNames(admin="FRA", content_level=2) + pygadm.Names(admin="FRA", content_level=2) .. note:: @@ -152,7 +152,7 @@ For example to get the name and codes of all the departments in France you can r .. code-block:: python - pygadm.AdmNames() + pygadm.Names() Google Earth engine @@ -172,7 +172,7 @@ If you want to use this lib with GEE, install the "earthengine-api" package in y ee.Initialize() - gdf = pygadm.AdmItems(name="Corse-du-Sud") + gdf = pygadm.Items(name="Corse-du-Sud") # transform into an ee.FeatureCollection fc = ee.FeatureCollection(gdf.__geo_interface__) @@ -197,7 +197,7 @@ Use the :code:`simplify` method from GeoPandas (more information `here `__. the ISO code is always displayed in the second column of the :code:`AdmNames` output. All GADM code start with the country ISO code so you can use the provided cell for any admin level. +As I don't know the GADM code I copy/paste the suggested code from the error message and filter it by `country ISO alpha-3 code `__. the ISO code is always displayed in the second column of the :code:`Names` output. All GADM code start with the country ISO code so you can use the provided cell for any admin level. .. jupyter-execute:: import pygadm - df = pygadm.AdmNames(name="Central") + df = pygadm.Names(name="Central") df = df[df.iloc[:,1].str.startswith("SGP")] df @@ -247,7 +247,7 @@ I now know that the code is "SGP.1_1" for the Central province so I can run my i import pygadm from ipyleaflet import GeoJSON, Map, basemaps - gdf = pygadm.AdmItems(admin="SGP.1_1") + gdf = pygadm.Items(admin="SGP.1_1") # display it in a map m = Map(basemap=basemaps.Esri.WorldImagery, zoom=11, center=[1.29, 103.83]) @@ -266,5 +266,5 @@ If you make an error when writing the name of your input, the error message will import pygadm - gdf = pygadm.AdmItems(name="Franc") + gdf = pygadm.Items(name="Franc") diff --git a/pygadm/__init__.py b/pygadm/__init__.py index d661444..002c90b 100644 --- a/pygadm/__init__.py +++ b/pygadm/__init__.py @@ -40,8 +40,8 @@ def _df() -> pd.DataFrame: return pd.read_parquet(__gadm_data__) -@versionadded(version="0.4.0", reason="Add the AdmNames class.") -class AdmNames(pd.DataFrame): +@versionadded(version="0.5.2", reason="Add the Names class.") +class Names(pd.DataFrame): def __init__( self, name: str = "", @@ -59,9 +59,6 @@ def __init__( admin: The id of an administrative area in the GADM nomenclature. Cannot be set along with :code:`name`. content_level: The level to use in the final dataset. Default to -1 (use level of the selected area). complete: If True, the method will return all the names of the higher administrative areas. Default to False. - - Returns: - The list of all the available names. """ # sanitary check on parameters if name and admin: @@ -148,29 +145,8 @@ def __init__( super().__init__(final_df) -@deprecated(version="0.4.0", reason="Use the AdmNames class instead.") -def get_names( - name: str = "", admin: str = "", content_level: int = -1, complete: bool = False -) -> pd.DataFrame: - """ - Return the list of names available in a administrative layer using the name or the administrative code. - - Return a pandas DataFrame of the names ad GADM code of an administrative region. The region can be requested either by its "name" or its "admin", the lib will identify the corresponding level on the fly. The user can also request for a specific level for its content e.g. get all admin level 1 of a country. If nothing is set we will infer the level of the item and if the level is higher than the found item, it will be ignored. If Nothing is found the method will return an error. - - Args: - name: The name of a administrative area. Cannot be set along with :code:`admin`. - admin: The id of an administrative area in the GADM nomenclature. Cannot be set along with :code:`name`. - content_level: The level to use in the final dataset. Default to -1 (use level of the selected area). - complete: If True, the method will return all the names of the higher administrative areas. Default to False. - - Returns: - The list of all the available names. - """ - return AdmNames(name, admin, content_level, complete) - - -@versionadded(version="0.4.0", reason="Add the AdmItems class.") -class AdmItems(gpd.GeoDataFrame): +@versionadded(version="0.5.2", reason="Add the Items class.") +class Items(gpd.GeoDataFrame): def __init__( self, name: Union[str, List[str]] = "", @@ -265,23 +241,29 @@ def _items( return gdf +@deprecated(version="0.5.2", reason="Use the Names class instead.") +class AdmNames(Names): + pass + + +@deprecated(version="0.5.2", reason="Use the Items class instead.") +class AdmItems(Items): + pass + + @deprecated(version="0.4.0", reason="Use the AdmItems class instead.") def get_items( name: Union[str, List[str]] = "", admin: Union[str, List[str]] = "", content_level: int = -1, ) -> gpd.GeoDataFrame: - """ - Return the requested administrative boundaries using the name or the administrative code. - - Return a Geopandas GeoDataFrame representing an administrative region. The region can be requested either by its "name" or its "admin", the lib will identify the area level on the fly. The user can also request for a specific level for the GeoDataFrame features e.g. get all admin level 1 of a country. If nothing is set we will infer the level of the item and if the level is higher than the found item, it will be ignored. If Nothing is found the method will return an error. + """Return the requested administrative boundaries using the name or the administrative code.""" + return AdmItems(name, admin, content_level) - Args: - name: The name of an administrative area. Cannot be set along with :code:`admin`. it can be a list or a single name. - admin: The id of an administrative area in the GADM nomenclature. Cannot be set along with :code:`name`. It can be a list or a single admin code. - content_level: The level to use in the final dataset. Default to -1 (use level from the area). - Returns: - The GeoDataFrame of the requested area with all the GADM attributes. - """ - return AdmItems(name, admin, content_level) +@deprecated(version="0.4.0", reason="Use the AdmNames class instead.") +def get_names( + name: str = "", admin: str = "", content_level: int = -1, complete: bool = False +) -> pd.DataFrame: + """Return the list of names available in a administrative layer using the name or the administrative code.""" + return AdmNames(name, admin, content_level, complete) diff --git a/tests/test_continent.py b/tests/test_continent.py index a039f86..6bfcede 100644 --- a/tests/test_continent.py +++ b/tests/test_continent.py @@ -17,7 +17,7 @@ def test_file(): def test_continent(dataframe_regression): """Check that the continent are working on the simplest.""" - gdf = pygadm.AdmItems(name="antartica") + gdf = pygadm.Items(name="antartica") df = pd.concat([gdf.GID_0, gdf.bounds], axis=1) dataframe_regression.check(df) diff --git a/tests/test_items.py b/tests/test_items.py index 7a469e3..293d10d 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -9,42 +9,42 @@ def test_empty(): """Empty request.""" with pytest.raises(Exception): - pygadm.AdmItems() + pygadm.Items() def test_duplicate_intput(): """Request with too many parameters.""" # request with too many things with pytest.raises(Exception): - pygadm.AdmItems(name="Singapore", admin="SGP") + pygadm.Items(name="Singapore", admin="SGP") def test_non_existing(): """Request non existing area.""" with pytest.raises(Exception): - pygadm.AdmItems(name="t0t0") + pygadm.Items(name="t0t0") with pytest.raises(Exception): - pygadm.AdmItems(admin="t0t0") + pygadm.Items(admin="t0t0") def test_area(dataframe_regression): """Request a known geometry.""" - gdf = pygadm.AdmItems(name="Singapore") + gdf = pygadm.Items(name="Singapore") df = pd.concat([gdf.GID_0, gdf.bounds], axis=1) dataframe_regression.check(df) def test_sub_content(dataframe_regression): """Request a sublevel.""" - gdf = pygadm.AdmItems(name="Singapore", content_level=1) + gdf = pygadm.Items(name="Singapore", content_level=1) dataframe_regression.check(gdf[["NAME_1", "GID_0"]]) def test_too_high(data_regression): """Request a sublevel higher than available in the area.""" with pytest.warns(UserWarning): - gdf = pygadm.AdmItems(admin="SGP.1_1", content_level=0) + gdf = pygadm.Items(admin="SGP.1_1", content_level=0) data_regression.check(gdf.GID_1.tolist()) @@ -52,14 +52,14 @@ def test_too_low(data_regression): """Request a sublevel lower than available in the area.""" # request a level too low with pytest.warns(UserWarning): - gdf = pygadm.AdmItems(admin="SGP.1_1", content_level=3) + gdf = pygadm.Items(admin="SGP.1_1", content_level=3) data_regression.check(gdf.GID_1.tolist()) def test_case_insensitive(): """Request an area without respecting the case.""" - gdf1 = pygadm.AdmItems(name="Singapore") - gdf2 = pygadm.AdmItems(name="singaPORE") + gdf1 = pygadm.Items(name="Singapore") + gdf2 = pygadm.Items(name="singaPORE") assert gdf1.equals(gdf2) @@ -67,30 +67,39 @@ def test_case_insensitive(): def test_duplicate_areas(): """Test that duplicate geometries return an error.""" with pytest.raises(ValueError): - pygadm.AdmItems(name="central") + pygadm.Items(name="central") def test_multiple_input(dataframe_regression): """Test when several geometries are requested at once.""" - gdf1 = pygadm.AdmItems(name=["france", "germany"]) + gdf1 = pygadm.Items(name=["france", "germany"]) df = pd.concat([gdf1.GID_0, gdf1.bounds], axis=1) dataframe_regression.check(df) - gdf2 = pygadm.AdmItems(admin=["FRA", "DEU"]) + gdf2 = pygadm.Items(admin=["FRA", "DEU"]) assert gdf2.equals(gdf1) def test_duplication(data_regression): """Test that known duplication cases return the biggest AOI.""" # italy is also a level 4 province of Bangladesh: BGD.5.4.6.6_1 - gdf = pygadm.AdmItems(name="Italy") + gdf = pygadm.Items(name="Italy") data_regression.check(gdf.GID_0.tolist()) def test_get_items(): """Test the get_items function.""" - gdf1 = pygadm.AdmItems(name="Singapore") + gdf1 = pygadm.Items(name="Singapore") with pytest.warns(DeprecationWarning): gdf2 = pygadm.get_items(name="Singapore") assert gdf1.equals(gdf2) + + +def test_adm_items(): + """Test the AdmItems class.""" + gdf1 = pygadm.Items(name="Singapore") + + with pytest.warns(DeprecationWarning): + gdf2 = pygadm.AdmItems(name="Singapore") + assert gdf1.equals(gdf2) diff --git a/tests/test_names.py b/tests/test_names.py index f771abf..2b83399 100644 --- a/tests/test_names.py +++ b/tests/test_names.py @@ -7,58 +7,58 @@ def test_empty(dataframe_regression): """Empty request which should return the country list.""" - df = pygadm.AdmNames() + df = pygadm.Names() dataframe_regression.check(df) def test_duplicate_input(): """Request with too many parameters.""" with pytest.raises(Exception): - pygadm.AdmNames(name="Singapore", admin="SGP") + pygadm.Names(name="Singapore", admin="SGP") def test_non_existing(): """Request non existing area.""" with pytest.raises(Exception): - pygadm.AdmNames(name="t0t0") + pygadm.Names(name="t0t0") with pytest.raises(Exception): - pygadm.AdmNames(admin="t0t0") + pygadm.Names(admin="t0t0") def test_area(dataframe_regression): """Request a known geometry.""" - df = pygadm.AdmNames(name="Singapore") + df = pygadm.Names(name="Singapore") dataframe_regression.check(df) - df_admin = pygadm.AdmNames(admin="SGP") + df_admin = pygadm.Names(admin="SGP") assert df_admin.equals(df) def test_sub_content(dataframe_regression): """Request a sublevel.""" - df = pygadm.AdmNames(name="Singapore", content_level=1) + df = pygadm.Names(name="Singapore", content_level=1) dataframe_regression.check(df) def test_too_high(dataframe_regression): """Request a sublevel higher than available in the area.""" with pytest.warns(UserWarning): - df = pygadm.AdmNames(admin="SGP.1_1", content_level=0) + df = pygadm.Names(admin="SGP.1_1", content_level=0) dataframe_regression.check(df) def test_too_low(dataframe_regression): """Request a sublevel lower than available in the area.""" with pytest.warns(UserWarning): - df = pygadm.AdmNames(admin="SGP.1_1", content_level=3) + df = pygadm.Names(admin="SGP.1_1", content_level=3) dataframe_regression.check(df) def test_case_insensitive(): """Request an area without respecting the case.""" - df1 = pygadm.AdmNames(name="Singapore") - df2 = pygadm.AdmNames(name="singaPORE") + df1 = pygadm.Names(name="Singapore") + df2 = pygadm.Names(name="singaPORE") assert df1.equals(df2) @@ -66,7 +66,7 @@ def test_case_insensitive(): def test_duplication(): """Test that known duplication cases return the biggest AOI.""" # italy is also a level 4 province of Bangladesh: BGD.5.4.6.6_1 - df = pygadm.AdmNames(name="Italy") + df = pygadm.Names(name="Italy") assert df.GID_0.to_list() == ["ITA"] @@ -74,19 +74,28 @@ def test_suggestions(): """Test that when a wrong name is given 5 options are proposed in the error message.""" expected_error = 'The requested "Franc" is not part of GADM. The closest matches are: Francs, Franco, France, Franca, Francon.' with pytest.raises(ValueError, match=expected_error): - pygadm.AdmNames(name="Franc") + pygadm.Names(name="Franc") def test_complete_content(dataframe_regression): """Request the complete hierarchy of an area.""" - df = pygadm.AdmNames(name="Singapore", content_level=1, complete=True) + df = pygadm.Names(name="Singapore", content_level=1, complete=True) dataframe_regression.check(df) def test_get_names(): """Test the get_names function.""" - df1 = pygadm.AdmNames(name="Singapore") + df1 = pygadm.Names(name="Singapore") with pytest.warns(DeprecationWarning): df2 = pygadm.get_names(name="Singapore") assert df1.equals(df2) + + +def test_adm_names(): + """Test the AdmName class.""" + df1 = pygadm.Names(name="Singapore") + + with pytest.warns(DeprecationWarning): + df2 = pygadm.AdmNames(name="Singapore") + assert df1.equals(df2)