Skip to content

Commit

Permalink
fix: use Names and Items as class names (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
12rambau authored Dec 22, 2023
2 parents 64ca8f1 + d170d6e commit b92edfc
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 90 deletions.
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
36 changes: 18 additions & 18 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -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])
Expand All @@ -136,23 +136,23 @@ 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:

.. jupyter-execute::

import pygadm

pygadm.AdmNames(admin="FRA", content_level=2)
pygadm.Names(admin="FRA", content_level=2)

.. note::

You can also get the list of all the country names by omitting ``admin`` and ``name`` parameters. If a level is not provided the table will only show country names but other parameters remain availables.

.. code-block:: python
pygadm.AdmNames()
pygadm.Names()
Google Earth engine
Expand All @@ -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__)
Expand All @@ -197,7 +197,7 @@ Use the :code:`simplify` method from GeoPandas (more information `here <https://

ee.Initialize()

gdf = pygadm.AdmItems(name="France")
gdf = pygadm.Items(name="France")

# reduce resolution
gdf.geometry = gdf.geometry.simplify(tolerance=.001)
Expand All @@ -219,7 +219,7 @@ Duplication issue

.. warning::

The names of countries are all unique but not the smaller administrative layers. If you request a small area using name, make sure it's the one you are looking for before running your workflow. If it's not the case, use the :code:`AdmNames` method to get the administrative code associated to the requested names, they are all unique.
The names of countries are all unique but not the smaller administrative layers. If you request a small area using name, make sure it's the one you are looking for before running your workflow. If it's not the case, use the :code:`Names` method to get the administrative code associated to the requested names, they are all unique.

Let's demonstrate this behavior with the "Central" province of Singapore. First we try to load it using its name. It should return an error:

Expand All @@ -228,15 +228,15 @@ Let's demonstrate this behavior with the "Central" province of Singapore. First

import pygadm

gdf = pygadm.AdmItems(name="Central")
gdf = pygadm.Items(name="Central")

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 <https://www.iban.com/country-codes>`__. 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 <https://www.iban.com/country-codes>`__. 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

Expand All @@ -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])
Expand All @@ -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")

62 changes: 22 additions & 40 deletions pygadm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "",
Expand All @@ -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:
Expand Down Expand Up @@ -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]] = "",
Expand Down Expand Up @@ -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)
2 changes: 1 addition & 1 deletion tests/test_continent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
39 changes: 24 additions & 15 deletions tests/test_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,88 +9,97 @@
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())


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)


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)
Loading

0 comments on commit b92edfc

Please sign in to comment.