# equi7grid-lite
<p align="center">
<a href="https://ipl-uv.github.io"><img src="docs/logo.jpeg" alt="header" width="50%"></a>
</p>
<p align="center">
<em>
No one will drive us from the paradise which Equi7Grid created for us
</em>
</p>
<p align="center">
<a href='https://pypi.python.org/pypi/equi7grid-lite'>
<img src='https://img.shields.io/pypi/v/equi7grid-lite.svg' alt='PyPI' />
</a>
<a href='https://colab.research.google.com/drive/1SBjl4GVgCFUpVch2Prju5oiXN8WyzZTi?usp=sharing'>
<img src='https://colab.research.google.com/assets/colab-badge.svg' alt='COLAB' />
</a>
<a href="https://opensource.org/licenses/MIT" target="_blank">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License">
</a>
<a href="https://github.com/psf/black" target="_blank">
<img src="https://img.shields.io/badge/code%20style-black-000000.svg" alt="Black">
</a>
<a href="https://pycqa.github.io/isort/" target="_blank">
<img src="https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336" alt="isort">
</a>
</p>
The `equi7grid-lite` package implements a user-friendly Python interface to interact with the [**Equi7Grid**](https://github.com/TUW-GEO/Equi7Grid) grid system.
`equi7grid-lite` is an **unofficial Python implementation of [**Equi7Grid**](https://github.com/TUW-GEO/Equi7Grid)**. With this package, users can convert geographic coordinates to Equi7Grid tiles and vice versa. This implementation differs from the official version in tree key ways:
- *Quad-Tree Grid Splitting*: Users are required to split the grid in a Quad-Tree fashion, meaning each grid level is divided into four tiles. For example, transitioning from level 1 to level 0 involves splitting each tile into four regular smaller tiles.
- *Revised Grid ID Encoding*: The grid ID is always encoded in meters, and the reference to the tile system (e.g., "T1", "T3", "T6") is removed. Instead, tiles are dynamically defined by the `min_grid_size` parameter. Here is a comparison between the original Equi7Grid and equi7grid-lite name conventions:
- 'EU500M_E036N006T6' -> 'EU2560_E4521N3011'
Where 'EU' is the Equi7Grid zone, '2560' is the `min_grid_size`, 'E4521' is the position in the *x* tile grid, and 'N3011' is the position in the *y* tile grid.
- *Upper Bound Level*: The maximum grid level is determined as the nearest lower distance to 2_500_000 meters. This threshold serves as a limit to create the Quad-Tree grid structure.
<p align="center">
<img src="docs/equi7grid_tiling.gif" alt="equi7grid-lite" width="100%"/>
</p>
Please refer to the [Equi7Grid repository](https://github.com/TUW-GEO/Equi7Grid) for **more information of the official implementation**.
## Installation
The `equi7grid-lite` package is available on PyPI and can be installed using `pip`:
```python
pip install equi7grid-lite
```
## Usage
The `equi7grid-lite` package provides a single class, `Equi7Grid`, which can be used to convert between geographic coordinates and Equi7Grid tiles.
```python
from equi7grid_lite import Equi7Grid
grid_system = Equi7Grid(min_grid_size=2560)
# Equi7Grid(min_grid_size=2560)
# ----------------
# levels: 0, 1, ... , 7, 8
# zones: AN, NA, OC, SA, AF, EU, AS
# min_grid_size: 2560 meters
# max_grid_size: 1310720 meters
```
To convert between geographic coordinates and Equi7Grid tiles, use the `lonlat2grid` method.
```python
lon, lat = -79.5, -5.49
grid_system.lonlat2grid(lon=lon, lat=lat)
# id lon lat x y zone level land geometry
#0 SA2560_E2009N2525 -79.507568 -5.485739 5144320.0 6465280.0 SA Z0 True POLYGON ((514560...
```
Use the `grid2lonlat` method to convert from Equi7Grid tile id to geographic coordinates.
```python
grid_system.grid2lonlat(grid_id="SA2560_E2009N2525")
# id lon lat x y zone level land geometry
#0 SA2560_E2009N2525 -79.507568 -5.485739 5144320.0 6465280.0 SA Z0 True POLYGON ((514560...
```
The `Equi7Grid` class also provides a method to create a grid of Equi7Grid upper-level tiles that
cover a given bounding box.
```python
import geopandas as gpd
from equi7grid_lite import Equi7Grid
# Define a POLYGON geometry
world_filepath = gpd.datasets.get_path('naturalearth_lowres')
world = gpd.read_file(world_filepath)
country = world[world.name == "Peru"].geometry
# Create a grid of Equi7Grid tiles that cover the bounding box of the POLYGON geometry
grid = grid_system.create_grid(
level=4,
zone="SA",
mask=country # Only include tiles that intersect the polygon
)
# Export the grid to a GeoDataFrame
grid.to_file("grid.shp")
```
By running `create_grid` with different levels, you can obtain its corresponding Equi7Grid Quad-Tree grid structure for any region.

Obtain the metadata of each Equi7Grid zone:
```python
from equi7grid_lite import Equi7Grid
# Zones: SA, EU, AF, AS, NA, AU
Equi7Grid.SA
```
Each zone has the following attributes:
- *id*: The zone ID code.
- *crs*: The WKT representation of the CRS.
- *geometry_geo*: The geometry of the zone in EPSG:4326.
- *geometry_equi7grid*: The geometry of the zone in the Equi7Grid CRS.
- *bbox_geo*: The bounding box of the zone in EPSG:4326.
- *bbox_equi7grid*: The bounding box of the zone in the Equi7Grid CRS.
- *landmasses_equi7grid*: The landmasses of the zone in the Equi7Grid CRS.
- *origin*: The central meridian and the latitude of origin.
## Use Equi7Grid with cubo
The `equi7grid-lite` package can be used in conjunction with the [cubo](https://github.com/ESDS-Leipzig/cubo) to retrieve Earth Observation (EO) data.
```python
import cubo
import matplotlib.pyplot as plt
import numpy as np
import rioxarray
from rasterio.enums import Resampling
from equi7grid_lite import Equi7Grid
# Initialize Equi7Grid system
grid_system = Equi7Grid(min_grid_size=2560)
# Specify the center coordinates
lon, lat = -122.4194, 37.7749
# Retrieve parameters for the CUBO request
cubo_parameters = grid_system.cubo_utm_parameters(lon=lon, lat=lat)
# Define the cube request using CUBO
da = cubo.create(
lat=cubo_parameters["lat"],
lon=cubo_parameters["lon"],
collection="sentinel-2-l2a", # Name of the STAC collection
bands=["B04", "B03", "B02"], # Bands to retrieve
start_date="2021-08-01", # Start date of the cube
end_date="2021-10-30", # End date of the cube
edge_size=cubo_parameters["distance"] // 10, # Distance in pixels
resolution=10, # Pixel size of the cube (m)
query={"eo:cloud_cover": {"lt": 50}} # Query parameters
)
# Add the CRS to the cube
da = da.rio.write_crs(f"epsg:{da.attrs['epsg']}")
da = da.drop_vars("cubo:distance_from_center")
# Convert the cube to a dataset and compute median over time
image = da.to_dataset("band").median("time", skipna=True)
# Increase the resolution of the cube with Lanczos resampling
image_reprojected = image.rio.reproject(
cubo_parameters["crs"],
resolution=2.5,
resampling=Resampling.lanczos
)
# Downsample the cube with nearest neighbor resampling
image_reprojected = image_reprojected.rio.reproject(
cubo_parameters["crs"],
resolution=10,
resampling=Resampling.nearest
)
# Clip the cube to the specified polygon
composite_e7g = image_reprojected.rio.clip([cubo_parameters["polygon"]]).to_array()
# Save the images in UTM and E7G projections
composite_e7g.rio.to_raster("composite_e7g.tif")
image.to_array().rio.to_raster("composite_utm.tif")
```
## License
This package is released under the MIT License. For more information, see the [LICENSE](LICENSE) file.
## Contributing
Contributions are welcome! For bug reports or feature requests, please open an issue on GitHub. For contributions, please submit a pull request with a detailed description of the changes.
## Citation
This is a simple adaptation of the Equi7Grid paper and code. If you use this package in your research, please consider citing the original Equi7Grid package and paper.
**Package:**
```
@software{bernhard_bm_2023_8252376,
author = {Bernhard BM and
Sebastian Hahn and
actions-user and
cnavacch and
Manuel Schmitzer and
shochsto and
Senmao Cao},
title = {TUW-GEO/Equi7Grid: v0.2.4},
month = aug,
year = 2023,
publisher = {Zenodo},
version = {v0.2.4},
doi = {10.5281/zenodo.8252376},
url = {https://doi.org/10.5281/zenodo.8252376}
}
```
**Paper:**
```
@article{BAUERMARSCHALLINGER201484,
title = {Optimisation of global grids for high-resolution remote sensing data},
journal = {Computers & Geosciences},
volume = {72},
pages = {84-93},
year = {2014},
issn = {0098-3004},
doi = {https://doi.org/10.1016/j.cageo.2014.07.005},
url = {https://www.sciencedirect.com/science/article/pii/S0098300414001629},
author = {Bernhard Bauer-Marschallinger and Daniel Sabel and Wolfgang Wagner},
keywords = {Remote sensing, High resolution, Big data, Global grid, Projection, Sampling, Equi7 Grid}
}
```
Raw data
{
"_id": null,
"home_page": "https://github.com/csaybar/equi7grid-lite",
"name": "equi7grid-lite",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Cesar Aybar",
"author_email": "cesar.aybar@uv.es",
"download_url": "https://files.pythonhosted.org/packages/d2/c5/0755b7821489da0bfd81ae81329e048d76ee60c65a1ee09efc4131642acf/equi7grid_lite-0.6.0.tar.gz",
"platform": null,
"description": "# equi7grid-lite\n\n<p align=\"center\">\n <a href=\"https://ipl-uv.github.io\"><img src=\"docs/logo.jpeg\" alt=\"header\" width=\"50%\"></a>\n</p>\n\n<p align=\"center\">\n <em>\n No one will drive us from the paradise which Equi7Grid created for us\n </em>\n</p>\n\n<p align=\"center\">\n<a href='https://pypi.python.org/pypi/equi7grid-lite'>\n<img src='https://img.shields.io/pypi/v/equi7grid-lite.svg' alt='PyPI' />\n</a>\n<a href='https://colab.research.google.com/drive/1SBjl4GVgCFUpVch2Prju5oiXN8WyzZTi?usp=sharing'>\n<img src='https://colab.research.google.com/assets/colab-badge.svg' alt='COLAB' />\n</a>\n<a href=\"https://opensource.org/licenses/MIT\" target=\"_blank\">\n<img src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License\">\n</a>\n<a href=\"https://github.com/psf/black\" target=\"_blank\">\n<img src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" alt=\"Black\">\n</a>\n<a href=\"https://pycqa.github.io/isort/\" target=\"_blank\">\n<img src=\"https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336\" alt=\"isort\">\n</a>\n</p>\n\nThe `equi7grid-lite` package implements a user-friendly Python interface to interact with the [**Equi7Grid**](https://github.com/TUW-GEO/Equi7Grid) grid system. \n\n`equi7grid-lite` is an **unofficial Python implementation of [**Equi7Grid**](https://github.com/TUW-GEO/Equi7Grid)**. With this package, users can convert geographic coordinates to Equi7Grid tiles and vice versa. This implementation differs from the official version in tree key ways:\n\n- *Quad-Tree Grid Splitting*: Users are required to split the grid in a Quad-Tree fashion, meaning each grid level is divided into four tiles. For example, transitioning from level 1 to level 0 involves splitting each tile into four regular smaller tiles.\n\n- *Revised Grid ID Encoding*: The grid ID is always encoded in meters, and the reference to the tile system (e.g., \"T1\", \"T3\", \"T6\") is removed. Instead, tiles are dynamically defined by the `min_grid_size` parameter. Here is a comparison between the original Equi7Grid and equi7grid-lite name conventions:\n\n - 'EU500M_E036N006T6' -> 'EU2560_E4521N3011'\n\n Where 'EU' is the Equi7Grid zone, '2560' is the `min_grid_size`, 'E4521' is the position in the *x* tile grid, and 'N3011' is the position in the *y* tile grid.\n\n- *Upper Bound Level*: The maximum grid level is determined as the nearest lower distance to 2_500_000 meters. This threshold serves as a limit to create the Quad-Tree grid structure.\n\n\n<p align=\"center\">\n <img src=\"docs/equi7grid_tiling.gif\" alt=\"equi7grid-lite\" width=\"100%\"/>\n</p>\n\nPlease refer to the [Equi7Grid repository](https://github.com/TUW-GEO/Equi7Grid) for **more information of the official implementation**.\n\n## Installation\n\nThe `equi7grid-lite` package is available on PyPI and can be installed using `pip`:\n\n```python\npip install equi7grid-lite\n```\n\n## Usage\n\nThe `equi7grid-lite` package provides a single class, `Equi7Grid`, which can be used to convert between geographic coordinates and Equi7Grid tiles.\n\n```python\nfrom equi7grid_lite import Equi7Grid\n\ngrid_system = Equi7Grid(min_grid_size=2560)\n# Equi7Grid(min_grid_size=2560)\n# ----------------\n# levels: 0, 1, ... , 7, 8\n# zones: AN, NA, OC, SA, AF, EU, AS\n# min_grid_size: 2560 meters\n# max_grid_size: 1310720 meters\n```\n\nTo convert between geographic coordinates and Equi7Grid tiles, use the `lonlat2grid` method.\n\n```python\n\nlon, lat = -79.5, -5.49\ngrid_system.lonlat2grid(lon=lon, lat=lat)\n# id lon lat x y zone level land geometry\n#0 SA2560_E2009N2525 -79.507568 -5.485739 5144320.0 6465280.0 SA Z0 True POLYGON ((514560...\n```\n\nUse the `grid2lonlat` method to convert from Equi7Grid tile id to geographic coordinates.\n\n\n```python\ngrid_system.grid2lonlat(grid_id=\"SA2560_E2009N2525\")\n# id lon lat x y zone level land geometry\n#0 SA2560_E2009N2525 -79.507568 -5.485739 5144320.0 6465280.0 SA Z0 True POLYGON ((514560...\n```\n\nThe `Equi7Grid` class also provides a method to create a grid of Equi7Grid upper-level tiles that\ncover a given bounding box.\n\n```python\nimport geopandas as gpd\n\nfrom equi7grid_lite import Equi7Grid\n\n# Define a POLYGON geometry\nworld_filepath = gpd.datasets.get_path('naturalearth_lowres')\nworld = gpd.read_file(world_filepath)\ncountry = world[world.name == \"Peru\"].geometry\n\n# Create a grid of Equi7Grid tiles that cover the bounding box of the POLYGON geometry\ngrid = grid_system.create_grid(\n level=4,\n zone=\"SA\",\n mask=country # Only include tiles that intersect the polygon\n)\n\n# Export the grid to a GeoDataFrame\ngrid.to_file(\"grid.shp\")\n```\n\nBy running `create_grid` with different levels, you can obtain its corresponding Equi7Grid Quad-Tree grid structure for any region.\n\n\n\nObtain the metadata of each Equi7Grid zone:\n\n```python\nfrom equi7grid_lite import Equi7Grid\n\n# Zones: SA, EU, AF, AS, NA, AU\nEqui7Grid.SA\n```\n\nEach zone has the following attributes:\n\n- *id*: The zone ID code.\n- *crs*: The WKT representation of the CRS.\n- *geometry_geo*: The geometry of the zone in EPSG:4326.\n- *geometry_equi7grid*: The geometry of the zone in the Equi7Grid CRS.\n- *bbox_geo*: The bounding box of the zone in EPSG:4326.\n- *bbox_equi7grid*: The bounding box of the zone in the Equi7Grid CRS.\n- *landmasses_equi7grid*: The landmasses of the zone in the Equi7Grid CRS.\n- *origin*: The central meridian and the latitude of origin.\n\n## Use Equi7Grid with cubo\n\nThe `equi7grid-lite` package can be used in conjunction with the [cubo](https://github.com/ESDS-Leipzig/cubo) to retrieve Earth Observation (EO) data.\n\n```python\nimport cubo\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport rioxarray\nfrom rasterio.enums import Resampling\n\nfrom equi7grid_lite import Equi7Grid\n\n# Initialize Equi7Grid system\ngrid_system = Equi7Grid(min_grid_size=2560)\n\n# Specify the center coordinates\nlon, lat = -122.4194, 37.7749\n\n# Retrieve parameters for the CUBO request\ncubo_parameters = grid_system.cubo_utm_parameters(lon=lon, lat=lat)\n\n# Define the cube request using CUBO\nda = cubo.create(\n lat=cubo_parameters[\"lat\"],\n lon=cubo_parameters[\"lon\"],\n collection=\"sentinel-2-l2a\", # Name of the STAC collection\n bands=[\"B04\", \"B03\", \"B02\"], # Bands to retrieve\n start_date=\"2021-08-01\", # Start date of the cube\n end_date=\"2021-10-30\", # End date of the cube\n edge_size=cubo_parameters[\"distance\"] // 10, # Distance in pixels\n resolution=10, # Pixel size of the cube (m)\n query={\"eo:cloud_cover\": {\"lt\": 50}} # Query parameters\n)\n\n# Add the CRS to the cube\nda = da.rio.write_crs(f\"epsg:{da.attrs['epsg']}\")\nda = da.drop_vars(\"cubo:distance_from_center\")\n\n# Convert the cube to a dataset and compute median over time\nimage = da.to_dataset(\"band\").median(\"time\", skipna=True)\n\n# Increase the resolution of the cube with Lanczos resampling\nimage_reprojected = image.rio.reproject(\n cubo_parameters[\"crs\"],\n resolution=2.5,\n resampling=Resampling.lanczos\n)\n\n# Downsample the cube with nearest neighbor resampling\nimage_reprojected = image_reprojected.rio.reproject(\n cubo_parameters[\"crs\"],\n resolution=10,\n resampling=Resampling.nearest\n)\n\n# Clip the cube to the specified polygon\ncomposite_e7g = image_reprojected.rio.clip([cubo_parameters[\"polygon\"]]).to_array()\n\n# Save the images in UTM and E7G projections\ncomposite_e7g.rio.to_raster(\"composite_e7g.tif\")\nimage.to_array().rio.to_raster(\"composite_utm.tif\")\n```\n\n## License\n\nThis package is released under the MIT License. For more information, see the [LICENSE](LICENSE) file.\n\n## Contributing\n\nContributions are welcome! For bug reports or feature requests, please open an issue on GitHub. For contributions, please submit a pull request with a detailed description of the changes.\n\n## Citation\n\nThis is a simple adaptation of the Equi7Grid paper and code. If you use this package in your research, please consider citing the original Equi7Grid package and paper.\n\n**Package:**\n\n```\n@software{bernhard_bm_2023_8252376,\n author = {Bernhard BM and\n Sebastian Hahn and\n actions-user and\n cnavacch and\n Manuel Schmitzer and\n shochsto and\n Senmao Cao},\n title = {TUW-GEO/Equi7Grid: v0.2.4},\n month = aug,\n year = 2023,\n publisher = {Zenodo},\n version = {v0.2.4},\n doi = {10.5281/zenodo.8252376},\n url = {https://doi.org/10.5281/zenodo.8252376}\n}\n```\n\n**Paper:**\n\n```\n@article{BAUERMARSCHALLINGER201484,\ntitle = {Optimisation of global grids for high-resolution remote sensing data},\njournal = {Computers & Geosciences},\nvolume = {72},\npages = {84-93},\nyear = {2014},\nissn = {0098-3004},\ndoi = {https://doi.org/10.1016/j.cageo.2014.07.005},\nurl = {https://www.sciencedirect.com/science/article/pii/S0098300414001629},\nauthor = {Bernhard Bauer-Marschallinger and Daniel Sabel and Wolfgang Wagner},\nkeywords = {Remote sensing, High resolution, Big data, Global grid, Projection, Sampling, Equi7 Grid}\n}\n```\n\n",
"bugtrack_url": null,
"license": null,
"summary": "A user-friendly Python interface to interact with the Equi7Grid grid system",
"version": "0.6.0",
"project_urls": {
"Documentation": "https://ipl-uv.github.io/equi7grid-lite/",
"Homepage": "https://github.com/csaybar/equi7grid-lite",
"Repository": "https://github.com/csaybar/equi7grid-lite"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "203713fba87d657c7db841b5e5120c7c25b061b2a8a0c318c47fd6bbc39aa7bd",
"md5": "2a06961f42ffb026a22556bbf36b7053",
"sha256": "e0a72ba6ce3f38facaf45e7be16c634d6b13e30c6ebef9891902dbcfc5905da7"
},
"downloads": -1,
"filename": "equi7grid_lite-0.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2a06961f42ffb026a22556bbf36b7053",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 6856237,
"upload_time": "2024-06-22T07:34:30",
"upload_time_iso_8601": "2024-06-22T07:34:30.218188Z",
"url": "https://files.pythonhosted.org/packages/20/37/13fba87d657c7db841b5e5120c7c25b061b2a8a0c318c47fd6bbc39aa7bd/equi7grid_lite-0.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d2c50755b7821489da0bfd81ae81329e048d76ee60c65a1ee09efc4131642acf",
"md5": "1e2374413ea535feaa5613953a54fffa",
"sha256": "6e07c326b509458b216f5d26750867caa791ccfd675abdf0c9b941ba15521c08"
},
"downloads": -1,
"filename": "equi7grid_lite-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "1e2374413ea535feaa5613953a54fffa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 6861774,
"upload_time": "2024-06-22T07:34:33",
"upload_time_iso_8601": "2024-06-22T07:34:33.300777Z",
"url": "https://files.pythonhosted.org/packages/d2/c5/0755b7821489da0bfd81ae81329e048d76ee60c65a1ee09efc4131642acf/equi7grid_lite-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-06-22 07:34:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "csaybar",
"github_project": "equi7grid-lite",
"github_not_found": true,
"lcname": "equi7grid-lite"
}