diff --git a/README.md b/README.md index 448972e3..c12e25b3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ +# GemGIS - Spatial data and information processing for geomodeling and subsurface data +
-> Spatial data and information processing for geomodeling and subsurface data
[![PyPI](https://img.shields.io/badge/python-3-blue.svg)](https://www.python.org/downloads/)
@@ -40,9 +41,9 @@ Furthermore, many [example models](https://gemgis.readthedocs.io/en/latest/getti
## Installation
-It is recommended to use GemGIS with **python">=3.10"** in a separated environment. The main packages and its dependencies can be installed via the conda-forge channel. GemGIS is then available through PyPi or Conda.
-1) `conda install -c conda-forge geopandas">=0.13.2" rasterio">=1.3.8"`
-2) `conda install -c conda-forge pyvista">=0.42.1"`
+It is recommended to use GemGIS with **python">=3.11"** in a separated environment. The main packages and its dependencies can be installed via the conda-forge channel. GemGIS is then available through PyPi or Conda.
+1) `conda install -c conda-forge geopandas">=1.0.1" rasterio">=1.4.3"`
+2) `conda install -c conda-forge pyvista">=0.44.2"`
3) `pip install gemgis` / `conda install -c conda-forge gemgis`
Check out the [Installation Page](https://gemgis.readthedocs.io/en/latest/getting_started/installation.html) for more detailed instructions.
@@ -55,13 +56,35 @@ The Contribution Guidelines for GemGIS can be found here: [Contribution Guidelin
We welcome issue reports, questions, ideas for new features and pull-requests to fix issues or even add new features to the software. Once a pull-request is opened, we will guide through the review process.
+
+## Citation
+
+If you use GemGIS for any published work, please cite it using the reference below:
+
+Jüstel, A., Endlein Correira, A., Pischke, M., de la Varga, M., Wellmann, F.: GemGIS - Spatial Data Processing for Geomodeling. Journal of Open Source Software, 7(73), 3709, https://doi.org/10.21105/joss.03709, 2022.
+
+```
+@article{Jüstel2022,
+doi = {10.21105/joss.03709},
+url = {https://doi.org/10.21105/joss.03709},
+year = {2022},
+publisher = {The Open Journal},
+volume = {7},
+number = {73},
+pages = {3709},
+author = {Alexander Jüstel and Arthur Endlein Correira and Marius Pischke and Miguel de la Varga and Florian Wellmann},
+title = {GemGIS - Spatial Data Processing for Geomodeling},
+journal = {Journal of Open Source Software}
+}
+```
+
## References
-* Jüstel et al., (2023). From Maps to Models - Tutorials for structural geological modeling using GemPy and GemGIS. Journal of Open Source Education, 6(66), 185, https://doi.org/10.21105/jose.00185
-* Jüstel et al., (2022). GemGIS - Spatial Data Processing for Geomodeling. Journal of Open Source Software, 7(73), 3709, https://doi.org/10.21105/joss.03709
-* Jüstel, A., Endlein Correira, A., Wellmann, F. and Pischke, M.: GemGIS – GemPy Geographic: Open-Source Spatial Data Processing for Geological Modeling. EGU General Assembly 2021, https://doi.org/10.5194/egusphere-egu21-4613, 2021
-* Jüstel, A.: 3D Probabilistic Modeling and Data Analysis of the Aachen-Weisweiler Area: Implications for Deep Geothermal Energy Exploration, unpublished Master Thesis at RWTH Aachen University, 2020
-* de la Varga, M., Schaaf, A., and Wellmann, F.: GemPy 1.0: open-source stochastic geological modeling and inversion, Geosci. Model Dev., 12, 1-32, https://doi.org/10.5194/gmd-12-1-2019, 2019
-* Powell, D.: Interpretation of Geological Structures Through Maps: An Introductory Practical Manual, Longman, pp. 192, 1992
-* Bennison, G.M.: An Introduction to Geological Structures and Maps, Hodder Education Publication, pp. 78, 1990
+* Jüstel, A. et al.: From Maps to Models - Tutorials for structural geological modeling using GemPy and GemGIS. Journal of Open Source Education, 6(66), 185, https://doi.org/10.21105/jose.00185, 2023.
+* Jüstel, A. et al.: GemGIS - Spatial Data Processing for Geomodeling. Journal of Open Source Software, 7(73), 3709, https://doi.org/10.21105/joss.03709, 2022.
+* Jüstel, A., Endlein Correira, A., Wellmann, F. and Pischke, M.: GemGIS – GemPy Geographic: Open-Source Spatial Data Processing for Geological Modeling. EGU General Assembly 2021, https://doi.org/10.5194/egusphere-egu21-4613, 2021.
+* Jüstel, A.: 3D Probabilistic Modeling and Data Analysis of the Aachen-Weisweiler Area: Implications for Deep Geothermal Energy Exploration, unpublished Master Thesis at RWTH Aachen University, 2020.
+* de la Varga, M., Schaaf, A., and Wellmann, F.: GemPy 1.0: open-source stochastic geological modeling and inversion, Geosci. Model Dev., 12, 1-32, https://doi.org/10.5194/gmd-12-1-2019, 2019.
+* Powell, D.: Interpretation of Geological Structures Through Maps: An Introductory Practical Manual, Longman, pp. 192, 1992.
+* Bennison, G.M.: An Introduction to Geological Structures and Maps, Hodder Education Publication, pp. 78, 1990.
diff --git a/docs/getting_started/api.rst b/docs/getting_started/api.rst
index 1daf72d8..d5e60a31 100644
--- a/docs/getting_started/api.rst
+++ b/docs/getting_started/api.rst
@@ -42,9 +42,9 @@ or from single Shapely Polygons or multiple Shapely Polygons.
:toctree: reference/vector_api
gemgis.vector.extract_xy_from_polygon_intersections
- gemgis.vector.intersection_polygon_polygon
- gemgis.vector.intersections_polygon_polygons
- gemgis.vector.intersections_polygons_polygons
+ gemgis.vector.intersect_polygon_polygon
+ gemgis.vector.intersect_polygon_polygons
+ gemgis.vector.intersect_polygons_polygons
Calculating and extracting coordinates from cross sections
diff --git a/environment.yml b/environment.yml
index 69f597fd..a9af2506 100644
--- a/environment.yml
+++ b/environment.yml
@@ -1,13 +1,19 @@
-# Requirements as of October 2023
+# Requirements as of December 2024
name: gemgis_env
channels:
- conda-forge
dependencies:
- - python>=3.10
- # geopandas will also install numpy, pandas, shapely, fiona, and pyproj
- - geopandas>=0.14.0
+ - python>=3.11
+ # geopandas will also install numpy, pandas, shapely, pyogrio, and pyproj
+ - geopandas>=1.0.1
+ - shapely>=2.0.6
+ - pandas>=2.2.3
+ - numpy>=2.1.3
+ - affine>=2.4.0
+ - pyproj>=3.7.0
# rasterio will also install affine
- - rasterio>=1.3.8
+ - rasterio>=1.4.3
# pyvista also install pooch and matplotlib
- - pyvista>=0.42.2
+ - pyvista>=0.44.2
+ - matplotlib>=3.9.3
- gemgis>=1.1
diff --git a/environment_dev.yml b/environment_dev.yml
index 11c6b989..a67ec7c1 100644
--- a/environment_dev.yml
+++ b/environment_dev.yml
@@ -2,13 +2,19 @@ name: gemgis_dev_env
channels:
- conda-forge
dependencies:
- - python>=3.10
- # geopandas will also install numpy, pandas, shapely, fiona, and pyproj
- - geopandas>=0.14.0
+ - python>=3.11
+ # geopandas will also install numpy, pandas, shapely, pyogrio, and pyproj
+ - geopandas>=1.0.1
+ - shapely>=2.0.6
+ - pandas>=2.2.3
+ - numpy>=2.1.3
+ - affine>=2.4.0
+ - pyproj>=3.7.0
# rasterio will also install affine
- #- rasterio>=1.3.8 will be installed through rioxarray
+ - rasterio>=1.4.3
# pyvista also install pooch and matplotlib
- #- pyvista>=0.42.2 will be installed through pvgeo
+ - pyvista>=0.44.2
+ - matplotlib>=3.9.3
- gemgis>=1.1
- rioxarray
- scipy
diff --git a/gemgis/download_gemgis_data.py b/gemgis/download_gemgis_data.py
index a96c4d98..1c327a7d 100644
--- a/gemgis/download_gemgis_data.py
+++ b/gemgis/download_gemgis_data.py
@@ -23,11 +23,8 @@
import zipfile
-def create_pooch(storage_url: str,
- files: List[str],
- target: str):
- """
- Create pooch class to fetch files from a website.
+def create_pooch(storage_url: str, files: List[str], target: str):
+ """Create pooch class to fetch files from a website.
Parameters
__________
@@ -46,58 +43,62 @@ def create_pooch(storage_url: str,
See also
________
download_tutorial_data: Download the GemGIS data for each tutorial.
+
"""
try:
import pooch
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Pooch package is not installed. Use pip install pooch to install the latest version')
+ "Pooch package is not installed. Use pip install pooch to install the latest version"
+ )
# Create new pooch
- pc = pooch.create(base_url=storage_url,
- path=target,
- registry={i: None for i in files})
+ pc = pooch.create(
+ base_url=storage_url, path=target, registry={i: None for i in files}
+ )
return pc
-def download_tutorial_data(filename: str,
- dirpath: str = '',
- storage_url: str = 'https://rwth-aachen.sciebo.de/s/AfXRsZywYDbUF34/download?path=%2F'):
- """
- Download the GemGIS data for each tutorial.
+def download_tutorial_data(
+ filename: str,
+ dirpath: str = "",
+ storage_url: str = "https://rwth-aachen.sciebo.de/s/AfXRsZywYDbUF34/download?path=%2F",
+):
+ """Download the GemGIS data for each tutorial.
Parameters
__________
filename : str
File name to be downloaded by pooch, e.g. ``filename='file.zip'``.
+
dirpath : str, default: ``''``
Path to the directory where the data is being stored, default to the directory where the notebook is
located, e.g. ``dirpath='Documents/gemgis/'``.
+
storage_url : str, default 'https://rwth-aachen.sciebo.de/s/AfXRsZywYDbUF34/download?path=%2F'
URL to the GemGIS data storage, default is the RWTH Aachen University Sciebo Cloud Storage.
See also
________
create_pooch : Create pooch class to fetch files from a website.
+
"""
try:
- import pooch
from pooch import HTTPDownloader
+
download = HTTPDownloader(progressbar=False)
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Pooch package is not installed. Use pip install pooch to install the latest version')
+ "Pooch package is not installed. Use pip install pooch to install the latest version"
+ )
# Creating pooch object
- pooch_data = create_pooch(storage_url=storage_url,
- files=[filename],
- target=dirpath)
+ pooch_data = create_pooch(storage_url=storage_url, files=[filename], target=dirpath)
# Downloading data to the defined folder
- pooch_data.fetch(fname=filename,
- downloader=download)
+ pooch_data.fetch(fname=filename, downloader=download)
# Opening zip file and unzip in specified directory
- with zipfile.ZipFile(dirpath + filename, 'r') as zip_ref:
+ with zipfile.ZipFile(dirpath + filename, "r") as zip_ref:
zip_ref.extractall(dirpath)
diff --git a/gemgis/gemgis.py b/gemgis/gemgis.py
index ebef8c08..e2e10c62 100644
--- a/gemgis/gemgis.py
+++ b/gemgis/gemgis.py
@@ -20,9 +20,9 @@
"""
import numpy as np
+
# import scooby
import pandas as pd
-from pandas.core import frame
import rasterio
import geopandas as gpd
import rasterio.transform
@@ -54,7 +54,7 @@ class GemPyData(object):
"""
This class creates an object with attributes containing i.e. the interfaces or orientations
that can directly be passed to a GemPy Model
-
+
The following attributes are available:
- model_name: string - the name of the model
- crs: string - the coordinate reference system of the model
@@ -65,8 +65,8 @@ class GemPyData(object):
- customsections: GeoDataFrame containing the Linestrings or Endpoints of custom sections
- resolution: list - List containing the x,y and z resolution of the model
- dem: Union[string, array] - String containing the path to the DEM or array containing DEM values
- - stack: dict - Dictionary containing the layer stack associated with the model
- - surface_colors: dict - Dictionary containing the surface colors for the model
+ - stack: dict - Dictionary containing the layer stack associated with the model
+ - surface_colors: dict - Dictionary containing the surface colors for the model
- is_fault: list - list of surface that are classified as faults
- geolmap: Union[GeoDataFrame,np.ndarray rasterio.io.Datasetreader] - GeoDataFrame or array containing
the geological map either as vector or raster data set
@@ -83,31 +83,33 @@ class GemPyData(object):
- contours: GeoDataFrame containing the contour lines of the model area
"""
- def __init__(self,
- model_name=None,
- crs=None,
- extent=None,
- resolution=None,
- interfaces=None,
- orientations=None,
- section_dict=None,
- customsections=None,
- dem=None,
- stack=None,
- surface_colors=None,
- is_fault=None,
- geolmap=None,
- basemap=None,
- faults=None,
- tectonics=None,
- raw_i=None,
- raw_o=None,
- raw_dem=None,
- wms=None,
- slope=None,
- hillshades=None,
- aspect=None,
- contours=None):
+ def __init__(
+ self,
+ model_name=None,
+ crs=None,
+ extent=None,
+ resolution=None,
+ interfaces=None,
+ orientations=None,
+ section_dict=None,
+ customsections=None,
+ dem=None,
+ stack=None,
+ surface_colors=None,
+ is_fault=None,
+ geolmap=None,
+ basemap=None,
+ faults=None,
+ tectonics=None,
+ raw_i=None,
+ raw_o=None,
+ raw_dem=None,
+ wms=None,
+ slope=None,
+ hillshades=None,
+ aspect=None,
+ contours=None,
+ ):
# Checking if data type are correct
@@ -130,9 +132,13 @@ def __init__(self,
if all(isinstance(n, (int, (int, float))) for n in extent):
self.extent = extent
else:
- raise TypeError('Coordinates for extent must be provided as integers or floats')
+ raise TypeError(
+ "Coordinates for extent must be provided as integers or floats"
+ )
else:
- raise ValueError('Length of extent must be 6 [minx,maxx,miny,maxy,minz,maxz]')
+ raise ValueError(
+ "Length of extent must be 6 [minx,maxx,miny,maxy,minz,maxz]"
+ )
self.extent = extent
else:
raise TypeError("Extent must be of type list")
@@ -144,9 +150,11 @@ def __init__(self,
if all(isinstance(n, int) for n in resolution):
self.resolution = resolution
else:
- raise TypeError('Values for resolution must be provided as integers')
+ raise TypeError(
+ "Values for resolution must be provided as integers"
+ )
else:
- raise ValueError('Length of resolution must be 3 [x,y,z]')
+ raise ValueError("Length of resolution must be 3 [x,y,z]")
self.resolution = resolution
else:
raise TypeError("Resolution must be of type list")
@@ -154,8 +162,11 @@ def __init__(self,
# Checking if the interfaces object is a Pandas df containing all relevant columns
if isinstance(interfaces, (type(None), pd.core.frame.DataFrame)):
if isinstance(interfaces, pd.core.frame.DataFrame):
- assert pd.Series(['X', 'Y', 'Z', 'formation']).isin(
- interfaces.columns).all(), 'Interfaces DataFrame is missing columns'
+ assert (
+ pd.Series(["X", "Y", "Z", "formation"])
+ .isin(interfaces.columns)
+ .all()
+ ), "Interfaces DataFrame is missing columns"
self.interfaces = interfaces
else:
raise TypeError("Interfaces df must be a Pandas DataFrame")
@@ -163,8 +174,13 @@ def __init__(self,
# Checking if the orientations object is Pandas df containing all relevant columns
if isinstance(orientations, (type(None), pd.core.frame.DataFrame)):
if isinstance(orientations, pd.core.frame.DataFrame):
- assert pd.Series(['X', 'Y', 'Z', 'formation', 'dip', 'azimuth', 'polarity']).isin(
- orientations.columns).all(), 'Orientations DataFrame is missing columns'
+ assert (
+ pd.Series(
+ ["X", "Y", "Z", "formation", "dip", "azimuth", "polarity"]
+ )
+ .isin(orientations.columns)
+ .all()
+ ), "Orientations DataFrame is missing columns"
self.orientations = orientations
else:
raise TypeError("Orientations df must be a Pandas DataFrame")
@@ -185,18 +201,32 @@ def __init__(self,
if isinstance(dem, (type(None), np.ndarray, rasterio.io.DatasetReader, str)):
self.dem = dem
else:
- raise TypeError("Digital Elevation Model must be a np Array, a raster loaded with rasterio or a string")
+ raise TypeError(
+ "Digital Elevation Model must be a np Array, a raster loaded with rasterio or a string"
+ )
# Checking if the provided surface colors object is of type dict
if isinstance(surface_colors, (type(None), dict)):
self.surface_colors = surface_colors
elif isinstance(surface_colors, str):
- self.surface_colors = create_surface_color_dict('../../gemgis/data/Test1/style1.qml')
+ self.surface_colors = create_surface_color_dict(
+ "../../gemgis/data/Test1/style1.qml"
+ )
else:
- raise TypeError("Surface Colors Dict must be of type dict or a path directing to a qml file")
+ raise TypeError(
+ "Surface Colors Dict must be of type dict or a path directing to a qml file"
+ )
# Checking that the provided geological map is a gdf containing polygons
- if isinstance(geolmap, (type(None), gpd.geodataframe.GeoDataFrame, rasterio.io.DatasetReader, np.ndarray)):
+ if isinstance(
+ geolmap,
+ (
+ type(None),
+ gpd.geodataframe.GeoDataFrame,
+ rasterio.io.DatasetReader,
+ np.ndarray,
+ ),
+ ):
if isinstance(geolmap, gpd.geodataframe.GeoDataFrame):
if all(geolmap.geom_type == "Polygon"):
self.geolmap = geolmap
@@ -216,7 +246,9 @@ def __init__(self,
else:
self.basemap = basemap
else:
- raise TypeError('Base Map must be a Raster loaded with rasterio or a NumPy Array')
+ raise TypeError(
+ "Base Map must be a Raster loaded with rasterio or a NumPy Array"
+ )
# Checking the the provided faults are a gdf containing LineStrings
if isinstance(faults, (type(None), gpd.geodataframe.GeoDataFrame)):
@@ -235,10 +267,10 @@ def __init__(self,
if all(isinstance(n, str) for n in is_fault):
self.is_fault = is_fault
else:
- raise TypeError('Fault Names must be provided as strings')
+ raise TypeError("Fault Names must be provided as strings")
self.is_fault = is_fault
else:
- TypeError('List of faults must be of type list')
+ TypeError("List of faults must be of type list")
# Checking that the provided raw input data objects are of type gdf
if isinstance(raw_i, (gpd.geodataframe.GeoDataFrame, type(None))):
@@ -259,7 +291,9 @@ def __init__(self,
# Setting the hillshades attribute
if isinstance(hillshades, np.ndarray):
self.hillshades = hillshades
- elif isinstance(self.raw_dem, np.ndarray) and isinstance(hillshades, type(None)):
+ elif isinstance(self.raw_dem, np.ndarray) and isinstance(
+ hillshades, type(None)
+ ):
self.hillshades = calculate_hillshades(self.raw_dem, self.extent)
else:
self.hillshades = hillshades
@@ -274,18 +308,18 @@ def __init__(self,
# Calculate model dimensions
if not isinstance(self.extent, type(None)):
- self.model_width = self.extent[1]-self.extent[0]
- self.model_length = self.extent[3]-self.extent[2]
- self.model_depth = self.extent[5]-self.extent[4]
- self.model_area = self.model_width*self.model_length
- self.model_volume = self.model_area*self.model_depth
+ self.model_width = self.extent[1] - self.extent[0]
+ self.model_length = self.extent[3] - self.extent[2]
+ self.model_depth = self.extent[5] - self.extent[4]
+ self.model_area = self.model_width * self.model_length
+ self.model_volume = self.model_area * self.model_depth
# Calculate cell dimensions
if not isinstance(self.resolution, type(None)):
if not isinstance(self.extent, type(None)):
- self.cell_width = self.model_width/self.resolution[0]
- self.cell_length = self.model_length/self.resolution[1]
- self.cell_depth = self.model_depth/self.resolution[2]
+ self.cell_width = self.model_width / self.resolution[0]
+ self.cell_length = self.model_length / self.resolution[1]
+ self.cell_depth = self.model_depth / self.resolution[2]
# Setting the wms attribute
if isinstance(wms, np.ndarray):
@@ -303,7 +337,7 @@ def __init__(self,
else:
self.customsections = customsections
else:
- raise TypeError('Custom sections must be provided as GeoDataFrame')
+ raise TypeError("Custom sections must be provided as GeoDataFrame")
# Setting the contours attribute
if isinstance(contours, (type(None), gpd.geodataframe.GeoDataFrame)):
@@ -312,13 +346,15 @@ def __init__(self,
else:
self.contours = contours
else:
- raise TypeError('Custom sections must be provided as GeoDataFrame')
+ raise TypeError("Custom sections must be provided as GeoDataFrame")
# Function tested
- def to_section_dict(self,
- gdf: gpd.geodataframe.GeoDataFrame,
- section_column: str = 'section_name',
- resolution=None):
+ def to_section_dict(
+ self,
+ gdf: gpd.geodataframe.GeoDataFrame,
+ section_column: str = "section_name",
+ resolution=None,
+ ):
"""
Converting custom sections stored in shape files to GemPy section_dicts
Args:
@@ -334,50 +370,70 @@ def to_section_dict(self,
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if the section_column is of type string
if not isinstance(section_column, str):
- raise TypeError('Name for section_column must be of type string')
+ raise TypeError("Name for section_column must be of type string")
# Checking if resolution is of type list
if not isinstance(resolution, list):
- raise TypeError('resolution must be of type list')
+ raise TypeError("resolution must be of type list")
# Checking if X and Y values are in column
- if np.logical_not(pd.Series(['X', 'Y']).isin(gdf.columns).all()):
+ if np.logical_not(pd.Series(["X", "Y"]).isin(gdf.columns).all()):
gdf = extract_xy(gdf)
# Checking the length of the resolution list
if len(resolution) != 2:
- raise ValueError('resolution list must be of length two')
+ raise ValueError("resolution list must be of length two")
# Checking that a valid section name is provided
- if not {'section_name'}.issubset(gdf.columns):
+ if not {"section_name"}.issubset(gdf.columns):
if not {section_column}.issubset(gdf.columns):
- raise ValueError('Section_column name needed to create section_dict')
+ raise ValueError("Section_column name needed to create section_dict")
# Extracting Section names
section_names = gdf[section_column].unique()
# Create section dicts for Point Shape Files
if all(gdf.geom_type == "Point"):
- section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
- [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
- resolution) for i in section_names}
+ section_dict = {
+ i: (
+ [
+ gdf[gdf[section_column] == i].X.iloc[0],
+ gdf[gdf[section_column] == i].Y.iloc[0],
+ ],
+ [
+ gdf[gdf[section_column] == i].X.iloc[1],
+ gdf[gdf[section_column] == i].Y.iloc[1],
+ ],
+ resolution,
+ )
+ for i in section_names
+ }
# Create section dicts for Line Shape Files
else:
- section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
- [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
- resolution) for i in section_names}
+ section_dict = {
+ i: (
+ [
+ gdf[gdf[section_column] == i].X.iloc[0],
+ gdf[gdf[section_column] == i].Y.iloc[0],
+ ],
+ [
+ gdf[gdf[section_column] == i].X.iloc[1],
+ gdf[gdf[section_column] == i].Y.iloc[1],
+ ],
+ resolution,
+ )
+ for i in section_names
+ }
self.section_dict = section_dict
# Function tested
- def to_gempy_df(self,
- gdf: gpd.geodataframe.GeoDataFrame,
- cat: str, **kwargs):
+ def to_gempy_df(self, gdf: gpd.geodataframe.GeoDataFrame, cat: str, **kwargs):
"""
Converting a GeoDataFrame into a Pandas DataFrame ready to be read in for GemPy
Args:
@@ -391,91 +447,110 @@ def to_gempy_df(self,
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if type is of type string
if not isinstance(cat, str):
- raise TypeError('Type must be of type string')
+ raise TypeError("Type must be of type string")
- if np.logical_not(pd.Series(['X', 'Y', 'Z']).isin(gdf.columns).all()):
- dem = kwargs.get('dem', None)
- extent = kwargs.get('extent', None)
+ if np.logical_not(pd.Series(["X", "Y", "Z"]).isin(gdf.columns).all()):
+ dem = kwargs.get("dem", None)
+ extent = kwargs.get("extent", None)
if not isinstance(dem, type(None)):
gdf = extract_xyz(gdf, dem, extent=extent)
else:
- raise FileNotFoundError('DEM not provided to obtain Z values for point data')
- if np.logical_not(pd.Series(['formation']).isin(gdf.columns).all()):
- raise ValueError('formation names not defined')
+ raise FileNotFoundError(
+ "DEM not provided to obtain Z values for point data"
+ )
+ if np.logical_not(pd.Series(["formation"]).isin(gdf.columns).all()):
+ raise ValueError("formation names not defined")
# Converting dip and azimuth columns to floats
- if pd.Series(['dip']).isin(gdf.columns).all():
- gdf['dip'] = gdf['dip'].astype(float)
+ if pd.Series(["dip"]).isin(gdf.columns).all():
+ gdf["dip"] = gdf["dip"].astype(float)
- if pd.Series(['azimuth']).isin(gdf.columns).all():
- gdf['azimuth'] = gdf['azimuth'].astype(float)
+ if pd.Series(["azimuth"]).isin(gdf.columns).all():
+ gdf["azimuth"] = gdf["azimuth"].astype(float)
# Converting formation column to string
- if pd.Series(['formation']).isin(gdf.columns).all():
- gdf['formation'] = gdf['formation'].astype(str)
+ if pd.Series(["formation"]).isin(gdf.columns).all():
+ gdf["formation"] = gdf["formation"].astype(str)
# Checking if dataframe is an orientation or interfaces df
- if pd.Series(['dip']).isin(gdf.columns).all():
- if cat == 'orientations':
- if (gdf['dip'] > 90).any():
- raise ValueError('dip values exceed 90 degrees')
- if np.logical_not(pd.Series(['azimuth']).isin(gdf.columns).all()):
- raise ValueError('azimuth values not defined')
- if (gdf['azimuth'] > 360).any():
- raise ValueError('azimuth values exceed 360 degrees')
+ if pd.Series(["dip"]).isin(gdf.columns).all():
+ if cat == "orientations":
+ if (gdf["dip"] > 90).any():
+ raise ValueError("dip values exceed 90 degrees")
+ if np.logical_not(pd.Series(["azimuth"]).isin(gdf.columns).all()):
+ raise ValueError("azimuth values not defined")
+ if (gdf["azimuth"] > 360).any():
+ raise ValueError("azimuth values exceed 360 degrees")
# Create orientations dataframe
- if np.logical_not(pd.Series(['polarity']).isin(gdf.columns).all()):
- df = pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation', 'dip', 'azimuth']].reset_index())
- df['polarity'] = 1
+ if np.logical_not(pd.Series(["polarity"]).isin(gdf.columns).all()):
+ df = pd.DataFrame(
+ gdf[
+ ["X", "Y", "Z", "formation", "dip", "azimuth"]
+ ].reset_index()
+ )
+ df["polarity"] = 1
self.orientations = df
else:
- self.orientations = \
- pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation', 'dip', 'azimuth', 'polarity']].reset_index())
+ self.orientations = pd.DataFrame(
+ gdf[
+ ["X", "Y", "Z", "formation", "dip", "azimuth", "polarity"]
+ ].reset_index()
+ )
else:
- raise ValueError('GeoDataFrame contains orientations but type is interfaces')
+ raise ValueError(
+ "GeoDataFrame contains orientations but type is interfaces"
+ )
else:
- if cat == 'interfaces':
+ if cat == "interfaces":
# Create interfaces dataframe
- self.interfaces = pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation']].reset_index())
+ self.interfaces = pd.DataFrame(
+ gdf[["X", "Y", "Z", "formation"]].reset_index()
+ )
else:
- raise ValueError('GeoDataFrame contains interfaces but type is orientations')
+ raise ValueError(
+ "GeoDataFrame contains interfaces but type is orientations"
+ )
# Function tested
- def set_extent(self, minx: Union[int, float] = 0,
- maxx: Union[int, float] = 0,
- miny: Union[int, float] = 0,
- maxy: Union[int, float] = 0,
- minz: Union[int, float] = 0,
- maxz: Union[int, float] = 0,
- **kwargs):
+ def set_extent(
+ self,
+ minx: Union[int, float] = 0,
+ maxx: Union[int, float] = 0,
+ miny: Union[int, float] = 0,
+ maxy: Union[int, float] = 0,
+ minz: Union[int, float] = 0,
+ maxz: Union[int, float] = 0,
+ **kwargs,
+ ):
+ """Setting the extent for a model.
+ Args:
+ minx - float defining the left border of the model
+ maxx - float defining the right border of the model
+ miny - float defining the upper border of the model
+ maxy - float defining the lower border of the model
+ minz - float defining the top border of the model
+ maxz - float defining the bottom border of the model
+ Kwargs:
+ gdf - GeoDataFrame from which bounds the extent will be set
+ Return:
+ extent - list with resolution values
"""
- Setting the extent for a model
- Args:
- minx - float defining the left border of the model
- maxx - float defining the right border of the model
- miny - float defining the upper border of the model
- maxy - float defining the lower border of the model
- minz - float defining the top border of the model
- maxz - float defining the bottom border of the model
- Kwargs:
- gdf - GeoDataFrame from which bounds the extent will be set
- Return:
- extent - list with resolution values
- """
- gdf = kwargs.get('gdf', None)
+ gdf = kwargs.get("gdf", None)
if not isinstance(gdf, (type(None), gpd.geodataframe.GeoDataFrame)):
- raise TypeError('gdf mus be of type GeoDataFrame')
+ raise TypeError("gdf mus be of type GeoDataFrame")
# Checking if bounds are of type int or float
- if not all(isinstance(i, (int, float)) for i in [minx, maxx, miny, maxy, minz, maxz]):
- raise TypeError('bounds must be of type int or float')
+ if not all(
+ isinstance(i, (int, float)) for i in [minx, maxx, miny, maxy, minz, maxz]
+ ):
+ raise TypeError("bounds must be of type int or float")
# Checking if the gdf is of type None
if isinstance(gdf, type(None)):
@@ -491,8 +566,14 @@ def set_extent(self, minx: Union[int, float] = 0,
# Create extent from gdf of geom_type point or linestring
else:
bounds = gdf.bounds
- extent = [round(bounds.minx.min(), 2), round(bounds.maxx.max(), 2), round(bounds.miny.min(), 2),
- round(bounds.maxy.max(), 2), minz, maxz]
+ extent = [
+ round(bounds.minx.min(), 2),
+ round(bounds.maxx.max(), 2),
+ round(bounds.miny.min(), 2),
+ round(bounds.maxy.max(), 2),
+ minz,
+ maxz,
+ ]
self.extent = extent
self.model_width = self.extent[1] - self.extent[0]
@@ -518,15 +599,15 @@ def set_resolution(self, x: int, y: int, z: int):
# Checking if x is of type int
if not isinstance(x, int):
- raise TypeError('X must be of type int')
+ raise TypeError("X must be of type int")
# Checking if y is of type int
if not isinstance(y, int):
- raise TypeError('Y must be of type int')
+ raise TypeError("Y must be of type int")
# Checking if y is of type int
if not isinstance(z, int):
- raise TypeError('Z must be of type int')
+ raise TypeError("Z must be of type int")
self.resolution = [x, y, z]
@@ -547,7 +628,7 @@ def to_surface_color_dict(self, path: str, **kwargs):
# Checking that the path is of type str
if not isinstance(path, str):
- raise TypeError('path must be provided as string')
+ raise TypeError("path must be provided as string")
# Parse qml
columns, classes = parse_categorized_qml(path)
@@ -558,14 +639,14 @@ def to_surface_color_dict(self, path: str, **kwargs):
# Create surface_colors_dict
surface_colors_dict = {k: v["color"] for k, v in styles.items() if k}
- basement = kwargs.get('basement', None)
+ basement = kwargs.get("basement", None)
# Checking if discarded formation is of type string
if not isinstance(basement, (str, type(None))):
- raise TypeError('Basement formation name must be of type string')
+ raise TypeError("Basement formation name must be of type string")
# Pop oldest lithology from dict as it does not need a color in GemPy
if isinstance(basement, str):
- surface_colors_dict['basement'] = surface_colors_dict.pop(basement)
+ surface_colors_dict["basement"] = surface_colors_dict.pop(basement)
self.surface_colors = surface_colors_dict
diff --git a/gemgis/misc.py b/gemgis/misc.py
index 16f895bb..bdb7a2cb 100644
--- a/gemgis/misc.py
+++ b/gemgis/misc.py
@@ -31,8 +31,8 @@
# Borehole logs can be requested at no charge from the Geological Survey from the database DABO:
# https://www.gd.nrw.de/gd_archive_dabo.htm
-def load_pdf(path: str,
- save_as_txt: bool = True) -> str:
+
+def load_pdf(path: str, save_as_txt: bool = True) -> str:
"""
Load PDF file containing borehole data.
@@ -73,17 +73,21 @@ def load_pdf(path: str,
try:
import pypdf
except ModuleNotFoundError:
- raise ModuleNotFoundError('PyPDF package is not installed. Use pip install pypdf to install the latest version')
+ raise ModuleNotFoundError(
+ "PyPDF package is not installed. Use pip install pypdf to install the latest version"
+ )
# Trying to import tqdm but returning error if tqdm is not installed
try:
from tqdm import tqdm
except ModuleNotFoundError:
- raise ModuleNotFoundError('tqdm package is not installed. Use pip install tqdm to install the latest version')
+ raise ModuleNotFoundError(
+ "tqdm package is not installed. Use pip install tqdm to install the latest version"
+ )
# Checking that the file path is of type string
if not isinstance(path, str):
- raise TypeError('Path/Name must be of type string')
+ raise TypeError("Path/Name must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -94,14 +98,14 @@ def load_pdf(path: str,
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Checking that save_as_bool is of type bool
if not isinstance(save_as_txt, bool):
- raise TypeError('Save_as_txt variable must be of type bool')
+ raise TypeError("Save_as_txt variable must be of type bool")
# Open the file as binary object
- data = open(path, 'rb')
+ data = open(path, "rb")
# Create new PdfFileReader object
filereader = pypdf.PdfReader(data)
@@ -110,7 +114,7 @@ def load_pdf(path: str,
number_of_pages = len(filereader.pages)
# Create empty string to store page content
- page_content = ''
+ page_content = ""
# Retrieve page content for each page
for i in tqdm(range(number_of_pages)):
@@ -121,14 +125,14 @@ def load_pdf(path: str,
# Saving a txt-file of the retrieved page content for further usage
if save_as_txt:
# Split path to get original file name
- name = path.split('.pdf')[0]
+ name = path.split(".pdf")[0]
# Open new text file
- with open(name + '.txt', "w") as text_file:
+ with open(name + ".txt", "w") as text_file:
text_file.write(page_content)
# Print out message if saving was successful
- print('%s.txt successfully saved' % name)
+ print("%s.txt successfully saved" % name)
return page_content
@@ -181,7 +185,7 @@ def load_symbols(path: str) -> list:
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -192,11 +196,11 @@ def load_symbols(path: str) -> list:
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Opening file
with open(path, "r") as text_file:
- symbols = [(i, '') for i in text_file.read().splitlines()]
+ symbols = [(i, "") for i in text_file.read().splitlines()]
return symbols
@@ -237,7 +241,7 @@ def load_formations(path: str) -> list:
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -248,13 +252,15 @@ def load_formations(path: str) -> list:
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Opening file
with open(path, "rb") as text_file:
formations = text_file.read().decode("UTF-8").split()
- formations = [(formations[i], formations[i + 1]) for i in range(0, len(formations) - 1, 2)]
+ formations = [
+ (formations[i], formations[i + 1]) for i in range(0, len(formations) - 1, 2)
+ ]
return formations
@@ -319,155 +325,181 @@ def get_meta_data(page: List[str]) -> list:
# Checking that the data is of type list
if not isinstance(page, list):
- raise TypeError('Page must be of type list')
+ raise TypeError("Page must be of type list")
# Checking that all elements are of type str
if not all(isinstance(n, str) for n in page):
- raise TypeError('All elements of the list must be of type str')
+ raise TypeError("All elements of the list must be of type str")
# Obtaining DABO Number
- well_dabo = page[page.index('Bnum:') + 1:page.index('Bnum:') + 2]
- well_dabo = ''.join(well_dabo)
- well_dabo = well_dabo.split('Object')[0]
- well_dabo = 'DABO_' + well_dabo
+ well_dabo = page[page.index("Bnum:") + 1 : page.index("Bnum:") + 2]
+ well_dabo = "".join(well_dabo)
+ well_dabo = well_dabo.split("Object")[0]
+ well_dabo = "DABO_" + well_dabo
# Obtaining Name of Well
- well_name = page[page.index('Name') + 1:page.index('Bohrungs-')]
- well_name = ''.join(well_name).replace(':', '')
+ well_name = page[page.index("Name") + 1 : page.index("Bohrungs-")]
+ well_name = "".join(well_name).replace(":", "")
# Obtaining Number of Well
- well_number = page[page.index('Aufschluß-Nr.') + 1:page.index('Aufschluß-Nr.') + 4]
- well_number = ''.join(well_number).replace(':', '')
- well_number = well_number.split('Archiv-Nr.')[0]
+ well_number = page[
+ page.index("Aufschluß-Nr.") + 1 : page.index("Aufschluß-Nr.") + 4
+ ]
+ well_number = "".join(well_number).replace(":", "")
+ well_number = well_number.split("Archiv-Nr.")[0]
# Obtaining Depth of well
- well_depth = page[page.index('Endteufe') + 3:page.index('Endteufe') + 4]
- well_depth = float(''.join(well_depth).replace(':', ''))
+ well_depth = page[page.index("Endteufe") + 3 : page.index("Endteufe") + 4]
+ well_depth = float("".join(well_depth).replace(":", ""))
# Obtaining Stratigraphie der Endteufe
- well_strat = page[page.index('Stratigraphie') + 3:page.index('Stratigraphie') + 4]
- well_strat = ''.join(well_strat).replace(':', '')
+ well_strat = page[page.index("Stratigraphie") + 3 : page.index("Stratigraphie") + 4]
+ well_strat = "".join(well_strat).replace(":", "")
# Obtaining Topographic Map Sheet Number
- well_tk = page[page.index('TK') + 2:page.index('TK') + 5]
- well_tk = ''.join(well_tk).replace(':', '')
- well_tk = ''.join(well_tk).replace('[TK', ' [TK ')
+ well_tk = page[page.index("TK") + 2 : page.index("TK") + 5]
+ well_tk = "".join(well_tk).replace(":", "")
+ well_tk = "".join(well_tk).replace("[TK", " [TK ")
# Obtaining Commune
- well_gemarkung = page[page.index('Gemarkung') + 1:page.index('Gemarkung') + 2]
- well_gemarkung = ''.join(well_gemarkung).replace(':', '')
+ well_gemarkung = page[page.index("Gemarkung") + 1 : page.index("Gemarkung") + 2]
+ well_gemarkung = "".join(well_gemarkung).replace(":", "")
# Obtaining GK Coordinates of wells
- well_coord_x_gk = page[page.index('Rechtswert/Hochwert') + 3:page.index('Rechtswert/Hochwert') + 4]
- well_coord_x_gk = ''.join(well_coord_x_gk).replace(':', '')
+ well_coord_x_gk = page[
+ page.index("Rechtswert/Hochwert") + 3 : page.index("Rechtswert/Hochwert") + 4
+ ]
+ well_coord_x_gk = "".join(well_coord_x_gk).replace(":", "")
- well_coord_y_gk = page[page.index('Rechtswert/Hochwert') + 5:page.index('Rechtswert/Hochwert') + 6]
- well_coord_y_gk = ''.join(well_coord_y_gk).replace(':', '')
+ well_coord_y_gk = page[
+ page.index("Rechtswert/Hochwert") + 5 : page.index("Rechtswert/Hochwert") + 6
+ ]
+ well_coord_y_gk = "".join(well_coord_y_gk).replace(":", "")
# Obtaining UTM Coordinates of wells
- well_coord_x = page[page.index('East/North') + 3:page.index('East/North') + 4]
- well_coord_x = ''.join(well_coord_x).replace(':', '')
+ well_coord_x = page[page.index("East/North") + 3 : page.index("East/North") + 4]
+ well_coord_x = "".join(well_coord_x).replace(":", "")
- well_coord_y = page[page.index('East/North') + 5:page.index('East/North') + 6]
- well_coord_y = ''.join(well_coord_y).replace(':', '')
+ well_coord_y = page[page.index("East/North") + 5 : page.index("East/North") + 6]
+ well_coord_y = "".join(well_coord_y).replace(":", "")
- well_coord_z = page[page.index('Ansatzpunktes') + 3:page.index('Ansatzpunktes') + 4]
- well_coord_z = ''.join(well_coord_z).replace(':', '')
+ well_coord_z = page[
+ page.index("Ansatzpunktes") + 3 : page.index("Ansatzpunktes") + 4
+ ]
+ well_coord_z = "".join(well_coord_z).replace(":", "")
# Obtaining Coordinates Precision
- well_coords = page[page.index('Koordinatenbestimmung') + 1:page.index('Koordinatenbestimmung') + 7]
- well_coords = ' '.join(well_coords).replace(':', '')
- well_coords = well_coords.split(' Hoehenbestimmung')[0]
+ well_coords = page[
+ page.index("Koordinatenbestimmung")
+ + 1 : page.index("Koordinatenbestimmung")
+ + 7
+ ]
+ well_coords = " ".join(well_coords).replace(":", "")
+ well_coords = well_coords.split(" Hoehenbestimmung")[0]
# Obtaining height precision
- well_height = page[page.index('Hoehenbestimmung') + 1:page.index('Hoehenbestimmung') + 8]
- well_height = ' '.join(well_height).replace(':', '')
- well_height = ''.join(well_height).replace(' .', '')
- well_height = well_height.split(' Hauptzweck')[0]
+ well_height = page[
+ page.index("Hoehenbestimmung") + 1 : page.index("Hoehenbestimmung") + 8
+ ]
+ well_height = " ".join(well_height).replace(":", "")
+ well_height = "".join(well_height).replace(" .", "")
+ well_height = well_height.split(" Hauptzweck")[0]
# Obtaining Purpose
- well_zweck = page[page.index('Aufschlusses') + 1:page.index('Aufschlusses') + 4]
- well_zweck = ' '.join(well_zweck).replace(':', '')
- well_zweck = well_zweck.split(' Aufschlussart')[0]
+ well_zweck = page[page.index("Aufschlusses") + 1 : page.index("Aufschlusses") + 4]
+ well_zweck = " ".join(well_zweck).replace(":", "")
+ well_zweck = well_zweck.split(" Aufschlussart")[0]
# Obtaining Kind
- well_aufschlussart = page[page.index('Aufschlussart') + 1:page.index('Aufschlussart') + 3]
- well_aufschlussart = ' '.join(well_aufschlussart).replace(':', '')
- well_aufschlussart = well_aufschlussart.split(' Aufschlussverfahren')[0]
+ well_aufschlussart = page[
+ page.index("Aufschlussart") + 1 : page.index("Aufschlussart") + 3
+ ]
+ well_aufschlussart = " ".join(well_aufschlussart).replace(":", "")
+ well_aufschlussart = well_aufschlussart.split(" Aufschlussverfahren")[0]
# Obtaining Procedure
- well_aufschlussverfahren = page[page.index('Aufschlussverfahren') + 1:page.index('Aufschlussverfahren') + 4]
- well_aufschlussverfahren = ' '.join(well_aufschlussverfahren).replace(':', '')
- well_aufschlussverfahren = well_aufschlussverfahren.split(' Vertraulichkeit')[0]
+ well_aufschlussverfahren = page[
+ page.index("Aufschlussverfahren") + 1 : page.index("Aufschlussverfahren") + 4
+ ]
+ well_aufschlussverfahren = " ".join(well_aufschlussverfahren).replace(":", "")
+ well_aufschlussverfahren = well_aufschlussverfahren.split(" Vertraulichkeit")[0]
# Obtaining Confidentiality
- well_vertraulichkeit = page[page.index('Vertraulichkeit') + 1:page.index('Vertraulichkeit') + 14]
- well_vertraulichkeit = ' '.join(well_vertraulichkeit).replace(':', '')
- well_vertraulichkeit = well_vertraulichkeit.split(' Art')[0]
+ well_vertraulichkeit = page[
+ page.index("Vertraulichkeit") + 1 : page.index("Vertraulichkeit") + 14
+ ]
+ well_vertraulichkeit = " ".join(well_vertraulichkeit).replace(":", "")
+ well_vertraulichkeit = well_vertraulichkeit.split(" Art")[0]
# Obtaining Type of Record
- well_aufnahme = page[page.index('Aufnahme') + 1:page.index('Aufnahme') + 10]
- well_aufnahme = ' '.join(well_aufnahme).replace(':', '')
- well_aufnahme = well_aufnahme.split(' . Schichtenverzeichnis')[0]
+ well_aufnahme = page[page.index("Aufnahme") + 1 : page.index("Aufnahme") + 10]
+ well_aufnahme = " ".join(well_aufnahme).replace(":", "")
+ well_aufnahme = well_aufnahme.split(" . Schichtenverzeichnis")[0]
# Obtaining Lithlog Version
- well_version = page[page.index('Version') + 1:page.index('Version') + 3]
- well_version = ' '.join(well_version).replace(':', '')
- well_version = well_version.split(' Qualität')[0]
+ well_version = page[page.index("Version") + 1 : page.index("Version") + 3]
+ well_version = " ".join(well_version).replace(":", "")
+ well_version = well_version.split(" Qualität")[0]
# Obtaining Quality
- well_quality = page[page.index('Qualität') + 1:page.index('Qualität') + 9]
- well_quality = ' '.join(well_quality).replace(':', '')
- well_quality = well_quality.split(' erster')[0]
+ well_quality = page[page.index("Qualität") + 1 : page.index("Qualität") + 9]
+ well_quality = " ".join(well_quality).replace(":", "")
+ well_quality = well_quality.split(" erster")[0]
# Obtaining Drilling Period
- well_date = page[page.index('Bohrtag') + 1:page.index('Bohrtag') + 6]
- well_date = ' '.join(well_date).replace(':', '')
- well_date = well_date.split(' . Grundwasserstand')[0]
+ well_date = page[page.index("Bohrtag") + 1 : page.index("Bohrtag") + 6]
+ well_date = " ".join(well_date).replace(":", "")
+ well_date = well_date.split(" . Grundwasserstand")[0]
# Obtaining Remarks
- well_remarks = page[page.index('Bemerkung') + 1:page.index('Bemerkung') + 14]
- well_remarks = ' '.join(well_remarks).replace(':', '')
- well_remarks = well_remarks.split(' . Originalschichtenverzeichnis')[0]
+ well_remarks = page[page.index("Bemerkung") + 1 : page.index("Bemerkung") + 14]
+ well_remarks = " ".join(well_remarks).replace(":", "")
+ well_remarks = well_remarks.split(" . Originalschichtenverzeichnis")[0]
# Obtaining Availability of Lithlog
- well_lithlog = page[page.index('Originalschichtenverzeichnis') + 1:page.index('Originalschichtenverzeichnis') + 7]
- well_lithlog = ' '.join(well_lithlog).replace(':', '')
- well_lithlog = well_lithlog.split(' .Schichtdaten')[0]
- well_lithlog = well_lithlog.split(' .Geologischer Dienst NRW')[0]
+ well_lithlog = page[
+ page.index("Originalschichtenverzeichnis")
+ + 1 : page.index("Originalschichtenverzeichnis")
+ + 7
+ ]
+ well_lithlog = " ".join(well_lithlog).replace(":", "")
+ well_lithlog = well_lithlog.split(" .Schichtdaten")[0]
+ well_lithlog = well_lithlog.split(" .Geologischer Dienst NRW")[0]
# Create list with data
- data = [well_dabo,
- well_name,
- well_number,
- float(well_depth),
- float(well_coord_x),
- float(well_coord_y),
- float(well_coord_z),
- float(well_coord_x_gk),
- float(well_coord_y_gk),
- well_strat,
- well_tk,
- well_gemarkung,
- well_coords,
- well_height,
- well_zweck,
- well_aufschlussart,
- well_aufschlussverfahren,
- well_vertraulichkeit,
- well_aufnahme,
- well_version,
- well_quality,
- well_date,
- well_remarks,
- well_lithlog]
+ data = [
+ well_dabo,
+ well_name,
+ well_number,
+ float(well_depth),
+ float(well_coord_x),
+ float(well_coord_y),
+ float(well_coord_z),
+ float(well_coord_x_gk),
+ float(well_coord_y_gk),
+ well_strat,
+ well_tk,
+ well_gemarkung,
+ well_coords,
+ well_height,
+ well_zweck,
+ well_aufschlussart,
+ well_aufschlussverfahren,
+ well_vertraulichkeit,
+ well_aufnahme,
+ well_version,
+ well_quality,
+ well_date,
+ well_remarks,
+ well_lithlog,
+ ]
return data
-def get_meta_data_df(data: str,
- name: str = 'GD',
- return_gdf: bool = True) -> Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame]:
+def get_meta_data_df(
+ data: str, name: str = "GD", return_gdf: bool = True
+) -> Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame]:
"""Function to create a dataframe with coordinates and meta data of the different boreholes
Parameters
@@ -524,110 +556,124 @@ def get_meta_data_df(data: str,
# Checking that the data is of type list
if not isinstance(data, str):
- raise TypeError('Data must be provided as list of strings')
+ raise TypeError("Data must be provided as list of strings")
# Checking that the name is of type string
if not isinstance(name, str):
- raise TypeError('Path/Name must be of type string')
+ raise TypeError("Path/Name must be of type string")
# Checking that the return_gdf variable is of type bool
if not isinstance(return_gdf, bool):
- raise TypeError('Return_gdf variable must be of type bool')
+ raise TypeError("Return_gdf variable must be of type bool")
# Split Data
data = data.split()
- data = '#'.join(data)
- data = data.split('-#Stammdaten')
- data = [item.split('|')[0] for item in data]
- data = [item.split('#') for item in data]
+ data = "#".join(data)
+ data = data.split("-#Stammdaten")
+ data = [item.split("|")[0] for item in data]
+ data = [item.split("#") for item in data]
# Filter out wells without Stratigraphic Column
- data = [item for item in data if 'Beschreibung' in item]
+ data = [item for item in data if "Beschreibung" in item]
# Get Coordinates of data
coordinates = [get_meta_data(page=item) for item in data]
# Create dataframe from coordinates
- coordinates_dataframe = pd.DataFrame(data=coordinates, columns=['DABO No.',
- 'Name',
- 'Number',
- 'Depth',
- 'X',
- 'Y',
- 'Z',
- 'X_GK',
- 'Y_GK',
- 'Last Stratigraphic Unit',
- 'Map Sheet',
- 'Commune',
- 'Coordinates Precision',
- 'Height Precision',
- 'Purpose',
- 'Kind',
- 'Procedure',
- 'Confidentiality',
- 'Record Type',
- 'Lithlog Version',
- 'Quality',
- 'Drilling Period',
- 'Remarks',
- 'Availability Lithlog'])
+ coordinates_dataframe = pd.DataFrame(
+ data=coordinates,
+ columns=[
+ "DABO No.",
+ "Name",
+ "Number",
+ "Depth",
+ "X",
+ "Y",
+ "Z",
+ "X_GK",
+ "Y_GK",
+ "Last Stratigraphic Unit",
+ "Map Sheet",
+ "Commune",
+ "Coordinates Precision",
+ "Height Precision",
+ "Purpose",
+ "Kind",
+ "Procedure",
+ "Confidentiality",
+ "Record Type",
+ "Lithlog Version",
+ "Quality",
+ "Drilling Period",
+ "Remarks",
+ "Availability Lithlog",
+ ],
+ )
# Creating an empty list for indices
index = []
# Filling index list with indices
for i in range(len(coordinates_dataframe)):
- index = np.append(index, [name + '{0:04}'.format(i + 1)])
- index = pd.DataFrame(data=index, columns=['Index'])
+ index = np.append(index, [name + "{0:04}".format(i + 1)])
+ index = pd.DataFrame(data=index, columns=["Index"])
# Creating DataFrame
coordinates_dataframe = pd.concat([coordinates_dataframe, index], axis=1)
# Selecting columns
- coordinates_dataframe = coordinates_dataframe[['Index',
- 'DABO No.',
- 'Name',
- 'Number',
- 'Depth',
- 'X',
- 'Y',
- 'Z',
- 'X_GK',
- 'Y_GK',
- 'Last Stratigraphic Unit',
- 'Map Sheet',
- 'Commune',
- 'Coordinates Precision',
- 'Height Precision',
- 'Purpose',
- 'Kind',
- 'Procedure',
- 'Confidentiality',
- 'Record Type',
- 'Lithlog Version',
- 'Quality',
- 'Drilling Period',
- 'Remarks',
- 'Availability Lithlog'
- ]]
+ coordinates_dataframe = coordinates_dataframe[
+ [
+ "Index",
+ "DABO No.",
+ "Name",
+ "Number",
+ "Depth",
+ "X",
+ "Y",
+ "Z",
+ "X_GK",
+ "Y_GK",
+ "Last Stratigraphic Unit",
+ "Map Sheet",
+ "Commune",
+ "Coordinates Precision",
+ "Height Precision",
+ "Purpose",
+ "Kind",
+ "Procedure",
+ "Confidentiality",
+ "Record Type",
+ "Lithlog Version",
+ "Quality",
+ "Drilling Period",
+ "Remarks",
+ "Availability Lithlog",
+ ]
+ ]
# Remove duplicates containing identical X, Y and Z coordinates
- coordinates_dataframe = coordinates_dataframe[~coordinates_dataframe.duplicated(subset=['X', 'Y', 'Z'])]
+ coordinates_dataframe = coordinates_dataframe[
+ ~coordinates_dataframe.duplicated(subset=["X", "Y", "Z"])
+ ]
# Convert df to gdf
if return_gdf:
- coordinates_dataframe = gpd.GeoDataFrame(data=coordinates_dataframe,
- geometry=gpd.points_from_xy(x=coordinates_dataframe.X,
- y=coordinates_dataframe.Y,
- crs='EPSG:4647'))
+ coordinates_dataframe = gpd.GeoDataFrame(
+ data=coordinates_dataframe,
+ geometry=gpd.points_from_xy(
+ x=coordinates_dataframe.X, y=coordinates_dataframe.Y, crs="EPSG:4647"
+ ),
+ )
return coordinates_dataframe
-def get_stratigraphic_data(text: list,
- symbols: List[Tuple[str, str]],
- formations: List[Tuple[str, str]], ) -> list:
+def get_stratigraphic_data(
+ text: list,
+ symbols: List[Tuple[str, str]],
+ formations: List[Tuple[str, str]],
+) -> list:
"""Function to retrieve the stratigraphic data from borehole logs
Parameters
@@ -672,15 +718,15 @@ def get_stratigraphic_data(text: list,
# Checking if the provided text is of type list
if not isinstance(text, list):
- raise TypeError('The provided data must be of type list')
+ raise TypeError("The provided data must be of type list")
# Checking if the provided symbols are of type list
if not isinstance(symbols, list):
- raise TypeError('The provided symbols must be of type list')
+ raise TypeError("The provided symbols must be of type list")
# Checking if the provided formations are of type list
if not isinstance(formations, list):
- raise TypeError('The provided formations must be of type list')
+ raise TypeError("The provided formations must be of type list")
# Creating empty lists
depth = []
@@ -691,52 +737,120 @@ def get_stratigraphic_data(text: list,
txt = text
# Join elements of list
- txt = ''.join(txt)
+ txt = "".join(txt)
# Obtaining Name of Well
- well_name = text[text.index('Name') + 1:text.index('Bohrungs-')]
- well_name = ''.join(well_name).replace(':', '')
+ well_name = text[text.index("Name") + 1 : text.index("Bohrungs-")]
+ well_name = "".join(well_name).replace(":", "")
# Obtaining Depth of well
- well_depth = text[text.index('Endteufe') + 3:text.index('Endteufe') + 4]
- well_depth = float(''.join(well_depth).replace(':', ''))
+ well_depth = text[text.index("Endteufe") + 3 : text.index("Endteufe") + 4]
+ well_depth = float("".join(well_depth).replace(":", ""))
# Obtaining UTM Coordinates of wells
- well_coord_x = text[text.index('East/North') + 3:text.index('East/North') + 4]
- well_coord_x = ''.join(well_coord_x).replace(':', '')
+ well_coord_x = text[text.index("East/North") + 3 : text.index("East/North") + 4]
+ well_coord_x = "".join(well_coord_x).replace(":", "")
- well_coord_y = text[text.index('East/North') + 5:text.index('East/North') + 6]
- well_coord_y = ''.join(well_coord_y).replace(':', '')
+ well_coord_y = text[text.index("East/North") + 5 : text.index("East/North") + 6]
+ well_coord_y = "".join(well_coord_y).replace(":", "")
- well_coord_z = text[text.index('Ansatzpunktes') + 3:text.index('Ansatzpunktes') + 4]
- well_coord_z = ''.join(well_coord_z).replace(':', '')
+ well_coord_z = text[
+ text.index("Ansatzpunktes") + 3 : text.index("Ansatzpunktes") + 4
+ ]
+ well_coord_z = "".join(well_coord_z).replace(":", "")
# Defining Phrases
- phrases = ['Fachaufsicht:GeologischerDienstNRW', 'Auftraggeber:GeologischerDienstNRW',
- 'Bohrunternehmer:GeologischerDienstNRW', 'aufgestelltvon:GeologischerDienstNRW',
- 'geol./stratgr.bearbeitetvon:GeologischerDienstNRW', 'NachRh.W.B.-G.', 'Vol.-', 'Mst.-Bänke', 'Cen.-',
- 'Tst.-Stücke', 'mit Mst. - Stücken', 'Flaserstruktur(O.-', 'FlaserstrukturO.-', 'Kalkst.-',
- 'gca.-Mächtigkeit', 'ca.-', 'Karbonsst.-Gerölle',
- 'Mst.-Stücken', 'Mst.-Bank17,1-17,2m', 'Tst.-Stücke', 'Mst.-Bank', 'Mst. - Stücken', 'hum.-torfig',
- 'rötl.-ocker', 'Pfl.-Reste', 'Utbk.-Flözg', 'Glauk.-', 'Toneisensteinlagenu.-', 'Ostrac.-', 'Stromat.-',
- 'u.-knötchen', 'U.-Camp.', 'Kalkmergelst.-Gerölle', 'Pfl.-Laden', 'Pfl.-Häcksel', 'ca.-Angabe,', 'Z.-',
- 'Hgd.-Schiefer', 'Sdst.-Fame', 'Orig.-Schi', 'Mergels.-', 'Kst.-', 'Steink.-G', 'Steink.-', 'Sst.-',
- 'bzw.-anfang', 'nd.-er', 'u.-knäuel', 'u.-konk', 'u.-knoten', 'ng.-Bür', 'Ton.-', 'org.-', 'FS.-',
- 'dkl.-', 'Schluff.-', 'Erw.-', 'Abl.-', 'abl.-', 'Sch.-', 'alsU.-', 'Plänerkst.-', 'Süßw.-', 'KV.-',
- 'duchläss.-', 'Verwitt.-', 'durchlass.-', 'San.-', 'Unterkr.-', 'grünl.-', 'Stringocephal.-', 'Zinkbl.-',
- 'Amphip.-', 'Tonst.-', 'Öffn.-', 'Trennflä.-', 'Randkalku.-dolomit',
- 'keineAngaben,Bemerkung:nachOrig.-SV:"Lehm",']
+ phrases = [
+ "Fachaufsicht:GeologischerDienstNRW",
+ "Auftraggeber:GeologischerDienstNRW",
+ "Bohrunternehmer:GeologischerDienstNRW",
+ "aufgestelltvon:GeologischerDienstNRW",
+ "geol./stratgr.bearbeitetvon:GeologischerDienstNRW",
+ "NachRh.W.B.-G.",
+ "Vol.-",
+ "Mst.-Bänke",
+ "Cen.-",
+ "Tst.-Stücke",
+ "mit Mst. - Stücken",
+ "Flaserstruktur(O.-",
+ "FlaserstrukturO.-",
+ "Kalkst.-",
+ "gca.-Mächtigkeit",
+ "ca.-",
+ "Karbonsst.-Gerölle",
+ "Mst.-Stücken",
+ "Mst.-Bank17,1-17,2m",
+ "Tst.-Stücke",
+ "Mst.-Bank",
+ "Mst. - Stücken",
+ "hum.-torfig",
+ "rötl.-ocker",
+ "Pfl.-Reste",
+ "Utbk.-Flözg",
+ "Glauk.-",
+ "Toneisensteinlagenu.-",
+ "Ostrac.-",
+ "Stromat.-",
+ "u.-knötchen",
+ "U.-Camp.",
+ "Kalkmergelst.-Gerölle",
+ "Pfl.-Laden",
+ "Pfl.-Häcksel",
+ "ca.-Angabe,",
+ "Z.-",
+ "Hgd.-Schiefer",
+ "Sdst.-Fame",
+ "Orig.-Schi",
+ "Mergels.-",
+ "Kst.-",
+ "Steink.-G",
+ "Steink.-",
+ "Sst.-",
+ "bzw.-anfang",
+ "nd.-er",
+ "u.-knäuel",
+ "u.-konk",
+ "u.-knoten",
+ "ng.-Bür",
+ "Ton.-",
+ "org.-",
+ "FS.-",
+ "dkl.-",
+ "Schluff.-",
+ "Erw.-",
+ "Abl.-",
+ "abl.-",
+ "Sch.-",
+ "alsU.-",
+ "Plänerkst.-",
+ "Süßw.-",
+ "KV.-",
+ "duchläss.-",
+ "Verwitt.-",
+ "durchlass.-",
+ "San.-",
+ "Unterkr.-",
+ "grünl.-",
+ "Stringocephal.-",
+ "Zinkbl.-",
+ "Amphip.-",
+ "Tonst.-",
+ "Öffn.-",
+ "Trennflä.-",
+ "Randkalku.-dolomit",
+ 'keineAngaben,Bemerkung:nachOrig.-SV:"Lehm",',
+ ]
# Replace phrases
for i in phrases:
- txt = txt.replace(i, '')
+ txt = txt.replace(i, "")
# Replace Symbols
for a, b in symbols:
if a in txt:
txt = txt.replace(a, b)
- if 'TiefeBeschreibungStratigraphie' in txt:
+ if "TiefeBeschreibungStratigraphie" in txt:
# Every line ends with a '.' and every new line starts with '-',
# the string will be separated there, the result is that every line of stratigraphy will be one string now
@@ -752,27 +866,29 @@ def get_stratigraphic_data(text: list,
# else:
# txt = txt.split('TiefeBeschreibungStratigraphie..-')[1]
- txt = txt.split('TiefeBeschreibungStratigraphie..-')[1]
+ txt = txt.split("TiefeBeschreibungStratigraphie..-")[1]
except IndexError:
# Create data
- data = [well_name,
- float(well_depth),
- float(well_coord_x),
- float(well_coord_y),
- float(well_coord_z),
- depth,
- strings,
- subs,
- form]
+ data = [
+ well_name,
+ float(well_depth),
+ float(well_coord_x),
+ float(well_coord_y),
+ float(well_coord_z),
+ depth,
+ strings,
+ subs,
+ form,
+ ]
return data
# Join txt
- txt = ''.join(txt)
+ txt = "".join(txt)
# Split text at .-
- txt = txt.split('.-')
+ txt = txt.split(".-")
# For loop over every string that contains layer information
for a in range(len(txt)):
@@ -781,35 +897,35 @@ def get_stratigraphic_data(text: list,
break
else:
# Every string is combined to a sequence of characters
- string = ''.join(txt[a])
- if string not in (None, ''):
+ string = "".join(txt[a])
+ if string not in (None, ""):
try:
# The depth information is extracted from the string
- depth.append(float(string.split('m', 1)[0]))
+ depth.append(float(string.split("m", 1)[0]))
# The depth information is cut off from the string and
# only the lithologies and stratigraphy is kept
- string = string.split('m', 1)[1]
+ string = string.split("m", 1)[1]
# Remove all numbers from string (e.g. von 10m bis 20m)
- string = ''.join(f for f in string if not f.isdigit())
+ string = "".join(f for f in string if not f.isdigit())
except ValueError:
pass
else:
pass
# Removing symbols from string
- string = string.replace(':', '')
- string = string.replace('-', '')
- string = string.replace('.', '')
- string = string.replace(',', '')
- string = string.replace('?', '')
- string = string.replace('/', '')
+ string = string.replace(":", "")
+ string = string.replace("-", "")
+ string = string.replace(".", "")
+ string = string.replace(",", "")
+ string = string.replace("?", "")
+ string = string.replace("/", "")
# Replace PDF-formation with formation name
forms = string
for q, r in formations:
if "..---.m" not in forms:
- if 'keineAngaben' in forms:
- formation = 'NichtEingestuft'
+ if "keineAngaben" in forms:
+ formation = "NichtEingestuft"
elif q in forms:
new_string = forms.split(q, 1)
forma = forms.split(new_string[0], 1)[1]
@@ -822,25 +938,29 @@ def get_stratigraphic_data(text: list,
form.append(formation)
# Create Data
- data = [well_name,
- float(well_depth),
- float(well_coord_x),
- float(well_coord_y),
- float(well_coord_z),
- depth,
- strings,
- subs,
- form]
+ data = [
+ well_name,
+ float(well_depth),
+ float(well_coord_x),
+ float(well_coord_y),
+ float(well_coord_z),
+ depth,
+ strings,
+ subs,
+ form,
+ ]
return data
-def get_stratigraphic_data_df(data: str,
- name: str,
- symbols: List[Tuple[str, str]],
- formations: List[Tuple[str, str]],
- remove_last: bool = False,
- return_gdf: bool = True) -> Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame]:
+def get_stratigraphic_data_df(
+ data: str,
+ name: str,
+ symbols: List[Tuple[str, str]],
+ formations: List[Tuple[str, str]],
+ remove_last: bool = False,
+ return_gdf: bool = True,
+) -> Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame]:
"""Function to create a dataframe with coordinates and the stratigraphy of the different boreholes
Parameters
@@ -848,7 +968,7 @@ def get_stratigraphic_data_df(data: str,
data : list
List containing the strings of the borehole log
-
+
name : str
Name for index reference, e.g. ``name='GD'``
@@ -909,36 +1029,36 @@ def get_stratigraphic_data_df(data: str,
# Checking that the data is provided as string
if not isinstance(data, str):
- raise TypeError('Data must be provided as string')
+ raise TypeError("Data must be provided as string")
# Checking that the name of the index is provided as string
if not isinstance(name, str):
- raise TypeError('Index name must be provided as string')
+ raise TypeError("Index name must be provided as string")
# Checking that the symbols are provided as list
if not isinstance(symbols, list):
- raise TypeError('Symbols must be provided as list of tuples of strings')
+ raise TypeError("Symbols must be provided as list of tuples of strings")
# Checking that the formations are provided as list
if not isinstance(formations, list):
- raise TypeError('Formations must be provided as list of tuples of strings')
+ raise TypeError("Formations must be provided as list of tuples of strings")
# Checking that the remove_last variable is of type bool
if not isinstance(remove_last, bool):
- raise TypeError('Remove_last variable must be of type bool')
+ raise TypeError("Remove_last variable must be of type bool")
# Checking that the return_gdf variable is of type bool
if not isinstance(return_gdf, bool):
- raise TypeError('Return_gdf variable must be of type bool')
+ raise TypeError("Return_gdf variable must be of type bool")
# Splitting the entire string into a list
data = data.split()
# Join all elements of list/all pages of the borehole logs and separate with #
- data = '#'.join(data)
+ data = "#".join(data)
# Split entire string at each new page into separate elements of a list
- data = data.split('-#Stammdaten')
+ data = data.split("-#Stammdaten")
# Cut off the last part of each element, this is not done for each page
# Segment to filter out stratigraphic tables that have multiple versions and are on multiple pages
@@ -951,137 +1071,217 @@ def get_stratigraphic_data_df(data: str,
# else:
# data = [item.split('|Geologischer#Dienst#NRW#')[0] for item in data]
- data = [item.split('|Geologischer#Dienst#NRW#')[0] for item in data]
+ data = [item.split("|Geologischer#Dienst#NRW#")[0] for item in data]
# Remove last part of each page if log stretches over multiple pages
- data = [re.sub(r'Geologischer#Dienst#NRW#\d\d.\d\d.\d\d\d\d-#\d+#-#', '#', item) for item in data]
- data = [re.sub(r'Geologischer#Dienst#NRW#\d\d.\d\d.\d\d\d\d-#\d+#-', '#', item) for item in data]
+ data = [
+ re.sub(r"Geologischer#Dienst#NRW#\d\d.\d\d.\d\d\d\d-#\d+#-#", "#", item)
+ for item in data
+ ]
+ data = [
+ re.sub(r"Geologischer#Dienst#NRW#\d\d.\d\d.\d\d\d\d-#\d+#-", "#", item)
+ for item in data
+ ]
# Connect different parts of each element
- data = [''.join(item) for item in data]
+ data = ["".join(item) for item in data]
# Split each element at #
- data = [item.split('#') for item in data]
+ data = [item.split("#") for item in data]
# Filter out wells without Stratigraphic Column
- data = [item for item in data if 'Beschreibung' in item]
+ data = [item for item in data if "Beschreibung" in item]
# Create empty list for indices
index = []
# Get stratigraphic data for each well
- stratigraphy = [get_stratigraphic_data(text=item,
- symbols=symbols,
- formations=formations) for item in data]
+ stratigraphy = [
+ get_stratigraphic_data(text=item, symbols=symbols, formations=formations)
+ for item in data
+ ]
# Create DataFrame from list of stratigraphic data
stratigraphy = pd.DataFrame(data=stratigraphy)
# Create DataFrame for index
for i in range(len(stratigraphy)):
- index = np.append(index, [str(name + '{0:04}'.format(i + 1))])
+ index = np.append(index, [str(name + "{0:04}".format(i + 1))])
index = pd.DataFrame(index)
# Concatenate DataFrames
stratigraphy_dataframe_new = pd.concat([stratigraphy, index], axis=1)
# Label DataFrame Columns
- stratigraphy_dataframe_new.columns = ['Name', 'Depth', 'X', 'Y', 'Altitude', 'Z', 'PDF-Formation', 'Subformation',
- 'formation', 'Index']
+ stratigraphy_dataframe_new.columns = [
+ "Name",
+ "Depth",
+ "X",
+ "Y",
+ "Altitude",
+ "Z",
+ "PDF-Formation",
+ "Subformation",
+ "formation",
+ "Index",
+ ]
# Select Columns
stratigraphy_dataframe_new = stratigraphy_dataframe_new[
- ['Index', 'Name', 'X', 'Y', 'Z', 'Depth', 'Altitude', 'PDF-Formation', 'Subformation', 'formation']]
+ [
+ "Index",
+ "Name",
+ "X",
+ "Y",
+ "Z",
+ "Depth",
+ "Altitude",
+ "PDF-Formation",
+ "Subformation",
+ "formation",
+ ]
+ ]
# Adjust data
- strati_depth = stratigraphy_dataframe_new[['Index', 'Z']]
- lst_col1 = 'Z'
- depth = pd.DataFrame({
- col: np.repeat(strati_depth['Index'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_depth = stratigraphy_dataframe_new[['Name', 'Z']]
- lst_col1 = 'Z'
- names = pd.DataFrame({
- col: np.repeat(strati_depth['Name'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_depth = stratigraphy_dataframe_new[['X', 'Z']]
- lst_col1 = 'Z'
- x_coord = pd.DataFrame({
- col: np.repeat(strati_depth['X'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_depth = stratigraphy_dataframe_new[['Y', 'Z']]
- lst_col1 = 'Z'
- y_coord = pd.DataFrame({
- col: np.repeat(strati_depth['Y'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_depth = stratigraphy_dataframe_new[['Altitude', 'Z']]
- lst_col1 = 'Z'
- altitude = pd.DataFrame({
- col: np.repeat(strati_depth['Altitude'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_depth = stratigraphy_dataframe_new[['Depth', 'Z']]
- lst_col1 = 'Z'
- welldepth = pd.DataFrame({
- col: np.repeat(strati_depth['Depth'].values, strati_depth[lst_col1].str.len())
- for col in strati_depth.columns.drop(lst_col1)}
- ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[strati_depth.columns]
-
- strati_formation = stratigraphy_dataframe_new[['Index', 'formation']]
- lst_col4 = 'formation'
- formation = pd.DataFrame({
- col: np.repeat(strati_formation['Index'].values, strati_formation[lst_col4].str.len())
- for col in strati_formation.columns.drop(lst_col4)}
- ).assign(**{lst_col4: np.concatenate(strati_formation[lst_col4].values)})[strati_formation.columns]
+ strati_depth = stratigraphy_dataframe_new[["Index", "Z"]]
+ lst_col1 = "Z"
+ depth = pd.DataFrame(
+ {
+ col: np.repeat(
+ strati_depth["Index"].values, strati_depth[lst_col1].str.len()
+ )
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_depth = stratigraphy_dataframe_new[["Name", "Z"]]
+ lst_col1 = "Z"
+ names = pd.DataFrame(
+ {
+ col: np.repeat(
+ strati_depth["Name"].values, strati_depth[lst_col1].str.len()
+ )
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_depth = stratigraphy_dataframe_new[["X", "Z"]]
+ lst_col1 = "Z"
+ x_coord = pd.DataFrame(
+ {
+ col: np.repeat(strati_depth["X"].values, strati_depth[lst_col1].str.len())
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_depth = stratigraphy_dataframe_new[["Y", "Z"]]
+ lst_col1 = "Z"
+ y_coord = pd.DataFrame(
+ {
+ col: np.repeat(strati_depth["Y"].values, strati_depth[lst_col1].str.len())
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_depth = stratigraphy_dataframe_new[["Altitude", "Z"]]
+ lst_col1 = "Z"
+ altitude = pd.DataFrame(
+ {
+ col: np.repeat(
+ strati_depth["Altitude"].values, strati_depth[lst_col1].str.len()
+ )
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_depth = stratigraphy_dataframe_new[["Depth", "Z"]]
+ lst_col1 = "Z"
+ welldepth = pd.DataFrame(
+ {
+ col: np.repeat(
+ strati_depth["Depth"].values, strati_depth[lst_col1].str.len()
+ )
+ for col in strati_depth.columns.drop(lst_col1)
+ }
+ ).assign(**{lst_col1: np.concatenate(strati_depth[lst_col1].values)})[
+ strati_depth.columns
+ ]
+
+ strati_formation = stratigraphy_dataframe_new[["Index", "formation"]]
+ lst_col4 = "formation"
+ formation = pd.DataFrame(
+ {
+ col: np.repeat(
+ strati_formation["Index"].values, strati_formation[lst_col4].str.len()
+ )
+ for col in strati_formation.columns.drop(lst_col4)
+ }
+ ).assign(**{lst_col4: np.concatenate(strati_formation[lst_col4].values)})[
+ strati_formation.columns
+ ]
# Create DataFrame
- strat = pd.concat([names, x_coord, y_coord, depth, altitude, welldepth, formation],
- axis=1)
+ strat = pd.concat(
+ [names, x_coord, y_coord, depth, altitude, welldepth, formation], axis=1
+ )
# Name Columns of DataFrame
- strat = strat[['Index', 'Name', 'X', 'Y', 'Z', 'Altitude', 'Depth', 'formation']]
+ strat = strat[["Index", "Name", "X", "Y", "Z", "Altitude", "Depth", "formation"]]
# Delete Duplicated columns (Index)
strat = strat.loc[:, ~strat.columns.duplicated()]
# Rename columns of Data Frame
- strat.columns = ['Index', 'Name', 'X', 'Y', 'DepthLayer', 'Altitude', 'Depth',
- 'formation']
+ strat.columns = [
+ "Index",
+ "Name",
+ "X",
+ "Y",
+ "DepthLayer",
+ "Altitude",
+ "Depth",
+ "formation",
+ ]
# Create Depth Column Usable for GemPy
- strat['Z'] = strat['Altitude'] - strat['DepthLayer']
+ strat["Z"] = strat["Altitude"] - strat["DepthLayer"]
# Reorder Columns of DataFrame
- strat = strat[['Index', 'Name', 'X', 'Y', 'Z', 'Altitude', 'Depth', 'formation']]
+ strat = strat[["Index", "Name", "X", "Y", "Z", "Altitude", "Depth", "formation"]]
# Delete Last
- strat = strat.groupby(['Index', 'formation']).last().sort_values(by=['Index', 'Z'],
- ascending=[True, False]).reset_index()
+ strat = (
+ strat.groupby(["Index", "formation"])
+ .last()
+ .sort_values(by=["Index", "Z"], ascending=[True, False])
+ .reset_index()
+ )
# Selecting Data
- strat = strat[['Index', 'Name', 'X', 'Y', 'Z', 'Altitude', 'Depth', 'formation']]
+ strat = strat[["Index", "Name", "X", "Y", "Z", "Altitude", "Depth", "formation"]]
# Remove unusable entries
- strat = strat[strat['formation'] != 'NichtEingestuft']
+ strat = strat[strat["formation"] != "NichtEingestuft"]
# Removing the last interfaces of each well since it does not represent a true interfaces
if remove_last:
- strat = strat[strat.groupby('Index').cumcount(ascending=False) > 0]
+ strat = strat[strat.groupby("Index").cumcount(ascending=False) > 0]
# Convert df to gdf
if return_gdf:
- strat = gpd.GeoDataFrame(data=strat,
- geometry=gpd.points_from_xy(x=strat.X,
- y=strat.Y,
- crs='EPSG:4647'))
+ strat = gpd.GeoDataFrame(
+ data=strat,
+ geometry=gpd.points_from_xy(x=strat.X, y=strat.Y, crs="EPSG:4647"),
+ )
return strat
diff --git a/gemgis/postprocessing.py b/gemgis/postprocessing.py
index 28bc19d2..cdfe72e1 100644
--- a/gemgis/postprocessing.py
+++ b/gemgis/postprocessing.py
@@ -30,9 +30,9 @@
import xml
-def extract_lithologies(geo_model,
- extent: list,
- crs: Union[str, pyproj.crs.crs.CRS]) -> gpd.geodataframe.GeoDataFrame:
+def extract_lithologies(
+ geo_model, extent: list, crs: Union[str, pyproj.crs.crs.CRS]
+) -> gpd.geodataframe.GeoDataFrame:
"""Extracting the geological map as GeoDataFrame
Parameters
@@ -61,14 +61,15 @@ def extract_lithologies(geo_model,
import matplotlib.pyplot as plt
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Matplotlib package is not installed. Use pip install matplotlib to install the latest version')
+ "Matplotlib package is not installed. Use pip install matplotlib to install the latest version"
+ )
- # Trying to import gempy but returning error if gempy is not installed
- try:
- import gempy as gp
- except ModuleNotFoundError:
- raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ ## Trying to import gempy but returning error if gempy is not installed
+ # try:
+ # import gempy as gp
+ # except ModuleNotFoundError:
+ # raise ModuleNotFoundError(
+ # 'GemPy package is not installed. Use pip install gempy to install the latest version')
shape = geo_model._grid.topography.values_2d[:, :, 2].shape
@@ -92,8 +93,9 @@ def extract_lithologies(geo_model,
fm = []
geo = []
for col, fm_name in zip(
- contours.collections,
- geo_model.surfaces.df.sort_values(by="order_surfaces", ascending=False).surface):
+ contours.collections,
+ geo_model.surfaces.df.sort_values(by="order_surfaces", ascending=False).surface,
+ ):
# Loop through all polygons that have the same intensity level
for contour_path in col.get_paths():
@@ -114,17 +116,17 @@ def extract_lithologies(geo_model,
fm.append(fm_name)
geo.append(poly)
- lith = gpd.GeoDataFrame({"formation": fm},
- geometry=geo,
- crs=crs)
+ lith = gpd.GeoDataFrame({"formation": fm}, geometry=geo, crs=crs)
return lith
-def extract_borehole(geo_model, #: gp.core.model.Project,
- geo_data: gemgis.GemPyData,
- loc: List[Union[int, float]],
- **kwargs):
+def extract_borehole(
+ geo_model, #: gp.core.model.Project,
+ geo_data: gemgis.GemPyData,
+ loc: List[Union[int, float]],
+ **kwargs,
+):
"""Extracting a borehole at a provided location from a recalculated GemPy Model
Parameters
@@ -166,55 +168,62 @@ def extract_borehole(geo_model, #: gp.core.model.Project,
from matplotlib.colors import ListedColormap
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Matplotlib package is not installed. Use pip install matplotlib to install the latest version')
+ "Matplotlib package is not installed. Use pip install matplotlib to install the latest version"
+ )
try:
import gempy as gp
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ "GemPy package is not installed. Use pip install gempy to install the latest version"
+ )
# Checking if geo_model is a GemPy geo_model
if not isinstance(geo_model, gp.core.model.Project):
- raise TypeError('geo_model must be a GemPy geo_model')
+ raise TypeError("geo_model must be a GemPy geo_model")
# Checking if geo_data is a GemGIS GemPy Data Class
if not isinstance(geo_data, gemgis.GemPyData):
- raise TypeError('geo_data must be a GemPy Data object')
+ raise TypeError("geo_data must be a GemPy Data object")
# Checking if loc is of type list
if not isinstance(loc, list):
- raise TypeError('Borehole location must be provided as a list of a x- and y- coordinate')
+ raise TypeError(
+ "Borehole location must be provided as a list of a x- and y- coordinate"
+ )
# Checking if elements of loc are of type int or float
if not all(isinstance(n, (int, float)) for n in loc):
- raise TypeError('Location values must be provided as integers or floats')
+ raise TypeError("Location values must be provided as integers or floats")
# Selecting DataFrame columns and create deep copy of DataFrame
- orientations_df = geo_model.orientations.df[['X', 'Y', 'Z', 'surface', 'dip', 'azimuth', 'polarity']].copy(
- deep=True)
+ orientations_df = geo_model.orientations.df[
+ ["X", "Y", "Z", "surface", "dip", "azimuth", "polarity"]
+ ].copy(deep=True)
- interfaces_df = geo_model.surface_points.df[['X', 'Y', 'Z', 'surface']].copy(deep=True)
+ interfaces_df = geo_model.surface_points.df[["X", "Y", "Z", "surface"]].copy(
+ deep=True
+ )
# Creating formation column
- orientations_df['formation'] = orientations_df['surface']
- interfaces_df['formation'] = interfaces_df['surface']
+ orientations_df["formation"] = orientations_df["surface"]
+ interfaces_df["formation"] = interfaces_df["surface"]
# Deleting surface column
- del orientations_df['surface']
- del interfaces_df['surface']
+ del orientations_df["surface"]
+ del interfaces_df["surface"]
# Getting maximum depth and resolution
- zmax = kwargs.get('zmax', geo_model.grid.regular_grid.extent[5])
- res = kwargs.get('res', geo_model.grid.regular_grid.resolution[2])
+ zmax = kwargs.get("zmax", geo_model.grid.regular_grid.extent[5])
+ res = kwargs.get("res", geo_model.grid.regular_grid.resolution[2])
# Checking if zmax is of type int or float
if not isinstance(zmax, (int, float)):
- raise TypeError('Maximum depth must be of type int or float')
+ raise TypeError("Maximum depth must be of type int or float")
# Checking if res is of type int
if not isinstance(res, (int, float, np.int32)):
- raise TypeError('Resolution must be of type int')
+ raise TypeError("Resolution must be of type int")
# Creating variable for maximum depth
z = geo_model.grid.regular_grid.extent[5] - zmax
@@ -223,118 +232,189 @@ def extract_borehole(geo_model, #: gp.core.model.Project,
# sys.stdout = open(os.devnull, 'w')
# Create GemPy Model
- well_model = gp.create_model('Well_Model')
+ well_model = gp.create_model("Well_Model")
# Initiate Data for GemPy Model
- gp.init_data(well_model,
- extent=[loc[0] - 5, loc[0] + 5, loc[1] - 5, loc[1] + 5, geo_model.grid.regular_grid.extent[4],
- geo_model.grid.regular_grid.extent[5] - z],
- resolution=[5, 5, res],
- orientations_df=orientations_df.dropna(),
- surface_points_df=interfaces_df.dropna(),
- default_values=False)
+ gp.init_data(
+ well_model,
+ extent=[
+ loc[0] - 5,
+ loc[0] + 5,
+ loc[1] - 5,
+ loc[1] + 5,
+ geo_model.grid.regular_grid.extent[4],
+ geo_model.grid.regular_grid.extent[5] - z,
+ ],
+ resolution=[5, 5, res],
+ orientations_df=orientations_df.dropna(),
+ surface_points_df=interfaces_df.dropna(),
+ default_values=False,
+ )
# Map Stack to surfaces
- gp.map_stack_to_surfaces(well_model,
- geo_data.stack,
- remove_unused_series=True)
+ gp.map_stack_to_surfaces(well_model, geo_data.stack, remove_unused_series=True)
# Add Basement surface
- well_model.add_surfaces('basement')
+ well_model.add_surfaces("basement")
# Change colors of surfaces
well_model.surfaces.colors.change_colors(geo_data.surface_colors)
# Set Interpolator
- gp.set_interpolator(well_model,
- compile_theano=True,
- theano_optimizer='fast_run', dtype='float64',
- update_kriging=False,
- verbose=[])
+ gp.set_interpolator(
+ well_model,
+ compile_theano=True,
+ theano_optimizer="fast_run",
+ dtype="float64",
+ update_kriging=False,
+ verbose=[],
+ )
# Set faults active
- for i in geo_model.surfaces.df[geo_model.surfaces.df['isFault'] == True]['surface'].values.tolist():
+ for i in geo_model.surfaces.df[geo_model.surfaces.df["isFault"] == True][
+ "surface"
+ ].values.tolist():
well_model.set_is_fault([i])
# Compute Model
sol = gp.compute_model(well_model, compute_mesh=False)
# Reshape lith_block
- well = sol.lith_block.reshape(well_model.grid.regular_grid.resolution[0],
- well_model.grid.regular_grid.resolution[1],
- well_model.grid.regular_grid.resolution[2])
+ well = sol.lith_block.reshape(
+ well_model.grid.regular_grid.resolution[0],
+ well_model.grid.regular_grid.resolution[1],
+ well_model.grid.regular_grid.resolution[2],
+ )
# Select colors for plotting
color_dict = well_model.surfaces.colors.colordict
surface = well_model.surfaces.df.copy(deep=True)
- surfaces = surface[~surface['id'].isin(np.unique(np.round(sol.lith_block)))]
- for key in surfaces['surface'].values.tolist():
+ surfaces = surface[~surface["id"].isin(np.unique(np.round(sol.lith_block)))]
+ for key in surfaces["surface"].values.tolist():
color_dict.pop(key)
cols = list(color_dict.values())
# Calculate boundaries
boundaries = np.where(np.round(well.T[:, 1])[:-1] != np.round(well.T[:, 1])[1:])[0][
- ::well_model.grid.regular_grid.resolution[0]]
+ :: well_model.grid.regular_grid.resolution[0]
+ ]
# Create Plot
plt.figure(figsize=(3, 10))
- plt.imshow(np.rot90(np.round(well.T[:, 1]), 2),
- cmap=ListedColormap(cols),
- extent=(0,
- (well_model.grid.regular_grid.extent[5] - well_model.grid.regular_grid.extent[4]) / 8,
- well_model.grid.regular_grid.extent[4],
- well_model.grid.regular_grid.extent[5]),
- )
+ plt.imshow(
+ np.rot90(np.round(well.T[:, 1]), 2),
+ cmap=ListedColormap(cols),
+ extent=(
+ 0,
+ (
+ well_model.grid.regular_grid.extent[5]
+ - well_model.grid.regular_grid.extent[4]
+ )
+ / 8,
+ well_model.grid.regular_grid.extent[4],
+ well_model.grid.regular_grid.extent[5],
+ ),
+ )
list_values = np.unique(np.round(well.T[:, 1])[:, 0]).tolist()
# Display depths of layer boundaries
for i in boundaries:
- plt.text((well_model.grid.regular_grid.extent[5] - well_model.grid.regular_grid.extent[4]) / 7,
- i * geo_model.grid.regular_grid.dz + geo_model.grid.regular_grid.extent[
- 4] + geo_model.grid.regular_grid.dz,
- '%d m' % (i * geo_model.grid.regular_grid.dz + geo_model.grid.regular_grid.extent[4]), fontsize=14)
+ plt.text(
+ (
+ well_model.grid.regular_grid.extent[5]
+ - well_model.grid.regular_grid.extent[4]
+ )
+ / 7,
+ i * geo_model.grid.regular_grid.dz
+ + geo_model.grid.regular_grid.extent[4]
+ + geo_model.grid.regular_grid.dz,
+ "%d m"
+ % (
+ i * geo_model.grid.regular_grid.dz
+ + geo_model.grid.regular_grid.extent[4]
+ ),
+ fontsize=14,
+ )
del list_values[list_values.index(np.round(well.T[:, 1])[:, 0][i + 1])]
# Plot last depth
- plt.text((well_model.grid.regular_grid.extent[5] - well_model.grid.regular_grid.extent[4]) / 7,
- geo_model.grid.regular_grid.extent[4] + geo_model.grid.regular_grid.dz,
- '%d m' % (geo_model.grid.regular_grid.extent[4]), fontsize=14)
+ plt.text(
+ (
+ well_model.grid.regular_grid.extent[5]
+ - well_model.grid.regular_grid.extent[4]
+ )
+ / 7,
+ geo_model.grid.regular_grid.extent[4] + geo_model.grid.regular_grid.dz,
+ "%d m" % (geo_model.grid.regular_grid.extent[4]),
+ fontsize=14,
+ )
list_values = np.unique(np.round(well.T[:, 1])[:, 0]).tolist()
# Display lithology IDs
for i in boundaries:
- plt.text((well_model.grid.regular_grid.extent[5] - well_model.grid.regular_grid.extent[4]) / 24,
- i * geo_model.grid.regular_grid.dz + geo_model.grid.regular_grid.extent[
- 4] + 2 * geo_model.grid.regular_grid.dz,
- 'ID: %d' % (np.round(well.T[:, 1])[:, 0][i + 1]), fontsize=14)
+ plt.text(
+ (
+ well_model.grid.regular_grid.extent[5]
+ - well_model.grid.regular_grid.extent[4]
+ )
+ / 24,
+ i * geo_model.grid.regular_grid.dz
+ + geo_model.grid.regular_grid.extent[4]
+ + 2 * geo_model.grid.regular_grid.dz,
+ "ID: %d" % (np.round(well.T[:, 1])[:, 0][i + 1]),
+ fontsize=14,
+ )
del list_values[list_values.index(np.round(well.T[:, 1])[:, 0][i + 1])]
# Plot last ID
- plt.text((well_model.grid.regular_grid.extent[5] - well_model.grid.regular_grid.extent[4]) / 24,
- geo_model.grid.regular_grid.extent[4] + 1 * geo_model.grid.regular_grid.dz, 'ID: %d' % (list_values[0]),
- fontsize=14)
+ plt.text(
+ (
+ well_model.grid.regular_grid.extent[5]
+ - well_model.grid.regular_grid.extent[4]
+ )
+ / 24,
+ geo_model.grid.regular_grid.extent[4] + 1 * geo_model.grid.regular_grid.dz,
+ "ID: %d" % (list_values[0]),
+ fontsize=14,
+ )
# Set legend handles
patches = [
- mpatches.Patch(color=cols[i], label="{formation}".format(
- formation=surface[surface['id'].isin(np.unique(np.round(sol.lith_block)))].surface.to_list()[i]))
- for i in range(len(surface[surface['id'].isin(np.unique(np.round(sol.lith_block)))].surface.to_list()))]
+ mpatches.Patch(
+ color=cols[i],
+ label="{formation}".format(
+ formation=surface[
+ surface["id"].isin(np.unique(np.round(sol.lith_block)))
+ ].surface.to_list()[i]
+ ),
+ )
+ for i in range(
+ len(
+ surface[
+ surface["id"].isin(np.unique(np.round(sol.lith_block)))
+ ].surface.to_list()
+ )
+ )
+ ]
# Remove xticks
- plt.tick_params(axis='x', labelsize=0, length=0)
+ plt.tick_params(axis="x", labelsize=0, length=0)
# Set ylabel
- plt.ylabel('Depth [m]')
+ plt.ylabel("Depth [m]")
# Set legend
plt.legend(handles=patches, bbox_to_anchor=(3, 1))
# Create depth dict
- depth_dict = {int(np.round(well.T[:, 1])[:, 0][i + 1]): i * geo_model.grid.regular_grid.dz +
- geo_model.grid.regular_grid.extent[4] for i in boundaries}
+ depth_dict = {
+ int(np.round(well.T[:, 1])[:, 0][i + 1]): i * geo_model.grid.regular_grid.dz
+ + geo_model.grid.regular_grid.extent[4]
+ for i in boundaries
+ }
depth_dict[int(list_values[0])] = geo_model.grid.regular_grid.extent[4]
depth_dict = dict(sorted(depth_dict.items()))
@@ -342,7 +422,7 @@ def extract_borehole(geo_model, #: gp.core.model.Project,
def save_model(geo_model, path):
- """ Function to save the model parameters to files
+ """Function to save the model parameters to files
Parameters
___________
@@ -363,15 +443,16 @@ def save_model(geo_model, path):
import gempy as gp
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ "GemPy package is not installed. Use pip install gempy to install the latest version"
+ )
# Checking if the geo_model is a GemPy Geo Model
if not isinstance(geo_model, gp.core.model.Project):
- raise TypeError('Geo Model must be a GemPy Geo Model')
+ raise TypeError("Geo Model must be a GemPy Geo Model")
# Checking if the path is of type string
if not isinstance(path, str):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
project_name = open(path + "01_project_name.txt", "w")
project_name.write(geo_model.meta.project_name)
@@ -381,8 +462,9 @@ def save_model(geo_model, path):
np.save(path + "03_resolution.npy", geo_model.grid.regular_grid.resolution)
-def extract_orientations_from_mesh(mesh: pv.core.pointset.PolyData,
- crs: Union[str, pyproj.crs.crs.CRS]) -> gpd.geodataframe.GeoDataFrame:
+def extract_orientations_from_mesh(
+ mesh: pv.core.pointset.PolyData, crs: Union[str, pyproj.crs.crs.CRS]
+) -> gpd.geodataframe.GeoDataFrame:
"""Extracting orientations (dip and azimuth) from PyVista Mesh
Parameters
@@ -406,43 +488,51 @@ def extract_orientations_from_mesh(mesh: pv.core.pointset.PolyData,
# Checking that the provided mesh is of type Polydata
if not isinstance(mesh, pv.core.pointset.PolyData):
- raise TypeError('Mesh must be provided as PyVista Polydata')
+ raise TypeError("Mesh must be provided as PyVista Polydata")
# Checking that the provided mesh if of type string or a pyproj CRS object
if not isinstance(crs, (str, pyproj.crs.crs.CRS)):
- raise TypeError('CRS must be provided as string or pyproj CRS object')
+ raise TypeError("CRS must be provided as string or pyproj CRS object")
# Computing the normals of the mesh
mesh_normals = mesh.compute_normals()
# Calculating the dips
- dips = [90 - np.rad2deg(-np.arcsin(mesh_normals['Normals'][i][2])) * (-1) for i in
- range(len(mesh_normals['Normals']))]
+ dips = [
+ 90 - np.rad2deg(-np.arcsin(mesh_normals["Normals"][i][2])) * (-1)
+ for i in range(len(mesh_normals["Normals"]))
+ ]
# Calculating the azimuths
- azimuths = [np.rad2deg(np.arctan(mesh_normals['Normals'][i][0] / mesh_normals['Normals'][i][1])) + 180 for i in
- range(len(mesh_normals['Normals']))]
+ azimuths = [
+ np.rad2deg(
+ np.arctan(mesh_normals["Normals"][i][0] / mesh_normals["Normals"][i][1])
+ )
+ + 180
+ for i in range(len(mesh_normals["Normals"]))
+ ]
# Getting cell centers
points_z = [geometry.Point(point) for point in mesh.cell_centers().points]
# Creating GeoDataFrame
- gdf_orientations = gpd.GeoDataFrame(geometry=points_z,
- crs=crs)
+ gdf_orientations = gpd.GeoDataFrame(geometry=points_z, crs=crs)
# Appending X, Y, Z Locations
- gdf_orientations['X'] = mesh.cell_centers().points[:, 0]
- gdf_orientations['Y'] = mesh.cell_centers().points[:, 1]
- gdf_orientations['Z'] = mesh.cell_centers().points[:, 2]
+ gdf_orientations["X"] = mesh.cell_centers().points[:, 0]
+ gdf_orientations["Y"] = mesh.cell_centers().points[:, 1]
+ gdf_orientations["Z"] = mesh.cell_centers().points[:, 2]
# Appending dips and azimuths
- gdf_orientations['dip'] = dips
- gdf_orientations['azimuth'] = azimuths
+ gdf_orientations["dip"] = dips
+ gdf_orientations["azimuth"] = azimuths
return gdf_orientations
-def calculate_dip_and_azimuth_from_mesh(mesh: pv.core.pointset.PolyData) -> pv.core.pointset.PolyData:
+def calculate_dip_and_azimuth_from_mesh(
+ mesh: pv.core.pointset.PolyData,
+) -> pv.core.pointset.PolyData:
"""Calculating dip and azimuth values for a mesh and setting them as scalars for subsequent plotting
Parameters
@@ -463,22 +553,29 @@ def calculate_dip_and_azimuth_from_mesh(mesh: pv.core.pointset.PolyData) -> pv.c
# Checking that the provided mesh is of type Polydata
if not isinstance(mesh, pv.core.pointset.PolyData):
- raise TypeError('Mesh must be provided as PyVista Polydata')
+ raise TypeError("Mesh must be provided as PyVista Polydata")
# Computing the normals of the mesh
mesh.compute_normals(inplace=True)
# Calculating the dips
- dips = [90 - np.rad2deg(-np.arcsin(mesh['Normals'][i][2])) * (-1) for i in
- range(len(mesh['Normals']))]
+ dips = [
+ 90 - np.rad2deg(-np.arcsin(mesh["Normals"][i][2])) * (-1)
+ for i in range(len(mesh["Normals"]))
+ ]
# Calculating the azimuths
- azimuths = [np.rad2deg(np.arctan(mesh['Normals'][i][0] / mesh['Normals'][i][1])) + 180 for i in
- range(len(mesh['Normals']))]
+ azimuths = [
+ np.rad2deg(np.arctan2(mesh["Normals"][i][0], mesh["Normals"][i][1]))
+ for i in range(len(mesh["Normals"]))
+ ]
+
+ # Shifting values
+ azimuths[azimuths < 0] += 360
# Assigning dips and azimuths to scalars
- mesh['Dips [°]'] = dips
- mesh['Azimuths [°]'] = azimuths
+ mesh["Dips [°]"] = dips
+ mesh["Azimuths [°]"] = azimuths
return mesh
@@ -502,41 +599,54 @@ def crop_block_to_topography(geo_model) -> pv.core.pointset.UnstructuredGrid:
"""
# Trying to import GemPy
- try:
- import gempy as gp
- except ModuleNotFoundError:
- raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ # try:
+ # import gempy as gp
+ # except ModuleNotFoundError:
+ # raise ModuleNotFoundError(
+ # 'GemPy package is not installed. Use pip install gempy to install the latest version')
# Trying to import PVGeo
try:
from PVGeo.grids import ExtractTopography
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'PVGeo package is not installed. Use pip install pvgeo to install the lastest version')
+ "PVGeo package is not installed. Use pip install pvgeo to install the lastest version"
+ )
# Creating StructuredGrid
grid = pv.UniformGrid()
# Setting Grid Dimensions
- grid.dimensions = np.array(geo_model.solutions.lith_block.reshape(geo_model.grid.regular_grid.resolution).shape) + 1
+ grid.dimensions = (
+ np.array(
+ geo_model.solutions.lith_block.reshape(
+ geo_model.grid.regular_grid.resolution
+ ).shape
+ )
+ + 1
+ )
# Setting Grid Origin
- grid.origin = (geo_model.grid.regular_grid.extent[0],
- geo_model.grid.regular_grid.extent[2],
- geo_model.grid.regular_grid.extent[4])
+ grid.origin = (
+ geo_model.grid.regular_grid.extent[0],
+ geo_model.grid.regular_grid.extent[2],
+ geo_model.grid.regular_grid.extent[4],
+ )
# Setting Grid Spacing
- grid.spacing = ((geo_model.grid.regular_grid.extent[1] - geo_model.grid.regular_grid.extent[0]) /
- geo_model.grid.regular_grid.resolution[0],
- (geo_model.grid.regular_grid.extent[3] - geo_model.grid.regular_grid.extent[2]) /
- geo_model.grid.regular_grid.resolution[1],
- (geo_model.grid.regular_grid.extent[5] - geo_model.grid.regular_grid.extent[4]) /
- geo_model.grid.regular_grid.resolution[2])
+ grid.spacing = (
+ (geo_model.grid.regular_grid.extent[1] - geo_model.grid.regular_grid.extent[0])
+ / geo_model.grid.regular_grid.resolution[0],
+ (geo_model.grid.regular_grid.extent[3] - geo_model.grid.regular_grid.extent[2])
+ / geo_model.grid.regular_grid.resolution[1],
+ (geo_model.grid.regular_grid.extent[5] - geo_model.grid.regular_grid.extent[4])
+ / geo_model.grid.regular_grid.resolution[2],
+ )
# Setting Cell Data
- grid.cell_data['values'] = geo_model.solutions.lith_block.reshape(geo_model.grid.regular_grid.resolution).flatten(
- order='F')
+ grid.cell_data["values"] = geo_model.solutions.lith_block.reshape(
+ geo_model.grid.regular_grid.resolution
+ ).flatten(order="F")
# Creating Polydata Dataset
topo = pv.PolyData(geo_model._grid.topography.values)
@@ -544,14 +654,12 @@ def crop_block_to_topography(geo_model) -> pv.core.pointset.UnstructuredGrid:
# Interpolating topography
topo.delaunay_2d(inplace=True)
- extracted = ExtractTopography(tolerance=5,
- remove=True).apply(grid, topo)
+ extracted = ExtractTopography(tolerance=5, remove=True).apply(grid, topo)
return extracted
-def create_attributes(keys: list,
- values: list) -> list:
+def create_attributes(keys: list, values: list) -> list:
"""Creating a list of attribute dicts
@@ -576,19 +684,19 @@ def create_attributes(keys: list,
# Checking that the keys are of type list
if not isinstance(keys, list):
- raise TypeError('keys must be provided as list')
+ raise TypeError("keys must be provided as list")
# Checking that all elements of the keys are of type str
if not all(isinstance(n, str) for n in keys):
- raise TypeError('key values must be of type str')
+ raise TypeError("key values must be of type str")
# Checking that all elements of the values are of type list
if not all(isinstance(n, list) for n in values):
- raise TypeError('values must be of type list')
+ raise TypeError("values must be of type list")
# Checking that the values are provided as list
if not isinstance(values, list):
- raise TypeError('values must be provided as list')
+ raise TypeError("values must be provided as list")
# Resorting the values
values = [[value[i] for value in values] for i in range(len(values[0]))]
@@ -599,9 +707,7 @@ def create_attributes(keys: list,
return dicts
-def create_subelement(parent: xml.etree.ElementTree.Element,
- name: str,
- attrib: dict):
+def create_subelement(parent: xml.etree.ElementTree.Element, name: str, attrib: dict):
"""Creating Subelement
Parameters
@@ -624,31 +730,31 @@ def create_subelement(parent: xml.etree.ElementTree.Element,
try:
import xml.etree.cElementTree as ET
except ModuleNotFoundError:
- raise ModuleNotFoundError('xml package is not installed')
+ raise ModuleNotFoundError("xml package is not installed")
# Checking that the parent is a XML element
if not isinstance(parent, xml.etree.ElementTree.Element):
- raise TypeError('The parent must a xml.etree.ElementTree.Element')
+ raise TypeError("The parent must a xml.etree.ElementTree.Element")
# Checking that the name is of type string
if not isinstance(name, str):
- raise TypeError('The element name must be of type string')
+ raise TypeError("The element name must be of type string")
# Checking that the attributes are of type dict
if not isinstance(attrib, dict):
- raise TypeError('The attributes must be provided as dict')
+ raise TypeError("The attributes must be provided as dict")
# Adding the element
- ET.SubElement(parent,
- name,
- attrib)
+ ET.SubElement(parent, name, attrib)
-def create_symbol(parent: xml.etree.ElementTree.Element,
- color: str,
- symbol_text: str,
- outline_width: str = '0.26',
- alpha: str = '1'):
+def create_symbol(
+ parent: xml.etree.ElementTree.Element,
+ color: str,
+ symbol_text: str,
+ outline_width: str = "0.26",
+ alpha: str = "1",
+):
"""Creating symbol entry
Parameters
@@ -677,167 +783,159 @@ def create_symbol(parent: xml.etree.ElementTree.Element,
try:
import xml.etree.cElementTree as ET
except ModuleNotFoundError:
- raise ModuleNotFoundError('xml package is not installed')
+ raise ModuleNotFoundError("xml package is not installed")
# Checking that the parent is a XML element
if not isinstance(parent, xml.etree.ElementTree.Element):
- raise TypeError('The parent must a xml.etree.ElementTree.Element')
+ raise TypeError("The parent must a xml.etree.ElementTree.Element")
# Checking that the color is of type string
if not isinstance(color, str):
- raise TypeError('The color values must be of type string')
+ raise TypeError("The color values must be of type string")
# Checking that the symbol_text is of type string
if not isinstance(symbol_text, str):
- raise TypeError('The symbol_text must be of type string')
+ raise TypeError("The symbol_text must be of type string")
# Checking that the outline_width is of type string
if not isinstance(outline_width, str):
- raise TypeError('The outline_width must be of type string')
+ raise TypeError("The outline_width must be of type string")
# Checking that the opacity value is of type string
if not isinstance(alpha, str):
- raise TypeError('The opacity value alpha must be of type string')
+ raise TypeError("The opacity value alpha must be of type string")
# Creating symbol element
- symbol = ET.SubElement(parent,
- 'symbol',
- attrib={"force_rhr": "0",
- "alpha": alpha,
- "is_animated": "0",
- "type": "fill",
- "frame_rate": "10",
- "name": symbol_text,
- "clip_to_extent": "1"})
-
- data_defined_properties1 = ET.SubElement(symbol,
- 'data_defined_properties')
-
- option1 = ET.SubElement(data_defined_properties1,
- 'Option',
- attrib={"type": 'Map'})
-
- option1_1 = ET.SubElement(option1,
- 'Option',
- attrib={"value": '',
- "type": 'QString',
- "name": 'name'})
-
- option1_2 = ET.SubElement(option1,
- 'Option',
- attrib={"name": 'properties'})
-
- option1_3 = ET.SubElement(option1,
- 'Option',
- attrib={"value": 'collection',
- "type": 'QString',
- "name": 'type'})
-
- layer = ET.SubElement(symbol,
- 'layer',
- attrib={"locked": '0',
- "pass": '0',
- "class": 'SimpleFill',
- "enabled": '1'})
-
- option2 = ET.SubElement(layer,
- 'Option',
- attrib={"type": 'Map'})
-
- option2_1 = ET.SubElement(option2,
- 'Option',
- attrib={"value": '3x:0,0,0,0,0,0',
- "type": 'QString',
- "name": 'border_width_map_unit_scale'})
-
- option2_2 = ET.SubElement(option2,
- 'Option',
- attrib={"value": color,
- "type": 'QString',
- "name": 'color'})
-
- option2_3 = ET.SubElement(option2,
- 'Option',
- attrib={"value": 'bevel',
- "type": 'QString',
- "name": 'joinstyle'})
-
- option2_4 = ET.SubElement(option2,
- 'Option',
- attrib={"value": '0,0',
- "type": 'QString',
- "name": 'offset'})
-
- option2_5 = ET.SubElement(option2,
- 'Option',
- attrib={"value": '3x:0,0,0,0,0,0',
- "type": 'QString',
- "name": 'offset_map_unit_scale'})
-
- option2_6 = ET.SubElement(option2,
- 'Option',
- attrib={"value": 'MM',
- "type": 'QString',
- "name": 'offset_unit'})
-
- option2_7 = ET.SubElement(option2,
- 'Option',
- attrib={"value": '35,35,35,255',
- "type": 'QString',
- "name": 'outline_color'})
-
- option2_8 = ET.SubElement(option2,
- 'Option',
- attrib={"value": 'solid',
- "type": 'QString',
- "name": 'outline_style'})
-
- option2_9 = ET.SubElement(option2,
- 'Option',
- attrib={"value": outline_width,
- "type": 'QString',
- "name": 'outline_width'})
-
- option2_10 = ET.SubElement(option2,
- 'Option',
- attrib={"value": 'MM',
- "type": 'QString',
- "name": 'outline_width_unit'})
-
- option2_11 = ET.SubElement(option2,
- 'Option',
- attrib={"value": 'solid',
- "type": 'QString',
- "name": 'style'})
-
- data_defined_properties2 = ET.SubElement(layer,
- 'data_defined_properties')
-
- option3 = ET.SubElement(data_defined_properties2,
- 'Option',
- attrib={"type": 'Map'})
-
- option3_1 = ET.SubElement(option3,
- 'Option', attrib={"value": '',
- "type": 'QString',
- "name": 'name'})
- option3_2 = ET.SubElement(option3,
- 'Option',
- attrib={"name": 'properties'})
-
- option3_3 = ET.SubElement(option3,
- 'Option',
- attrib={"value": 'collection',
- "type": 'QString',
- "name": 'type'})
-
-
-def save_qgis_qml_file(gdf: gpd.geodataframe.GeoDataFrame,
- value: str = 'formation',
- color: str = 'color',
- outline_width: Union[int, float] = 0.26,
- alpha: Union[int, float] = 1,
- path: str = ''):
+ symbol = ET.SubElement(
+ parent,
+ "symbol",
+ attrib={
+ "force_rhr": "0",
+ "alpha": alpha,
+ "is_animated": "0",
+ "type": "fill",
+ "frame_rate": "10",
+ "name": symbol_text,
+ "clip_to_extent": "1",
+ },
+ )
+
+ data_defined_properties1 = ET.SubElement(symbol, "data_defined_properties")
+
+ option1 = ET.SubElement(data_defined_properties1, "Option", attrib={"type": "Map"})
+
+ option1_1 = ET.SubElement(
+ option1, "Option", attrib={"value": "", "type": "QString", "name": "name"}
+ )
+
+ option1_2 = ET.SubElement(option1, "Option", attrib={"name": "properties"})
+
+ option1_3 = ET.SubElement(
+ option1,
+ "Option",
+ attrib={"value": "collection", "type": "QString", "name": "type"},
+ )
+
+ layer = ET.SubElement(
+ symbol,
+ "layer",
+ attrib={"locked": "0", "pass": "0", "class": "SimpleFill", "enabled": "1"},
+ )
+
+ option2 = ET.SubElement(layer, "Option", attrib={"type": "Map"})
+
+ option2_1 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={
+ "value": "3x:0,0,0,0,0,0",
+ "type": "QString",
+ "name": "border_width_map_unit_scale",
+ },
+ )
+
+ option2_2 = ET.SubElement(
+ option2, "Option", attrib={"value": color, "type": "QString", "name": "color"}
+ )
+
+ option2_3 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": "bevel", "type": "QString", "name": "joinstyle"},
+ )
+
+ option2_4 = ET.SubElement(
+ option2, "Option", attrib={"value": "0,0", "type": "QString", "name": "offset"}
+ )
+
+ option2_5 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={
+ "value": "3x:0,0,0,0,0,0",
+ "type": "QString",
+ "name": "offset_map_unit_scale",
+ },
+ )
+
+ option2_6 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": "MM", "type": "QString", "name": "offset_unit"},
+ )
+
+ option2_7 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": "35,35,35,255", "type": "QString", "name": "outline_color"},
+ )
+
+ option2_8 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": "solid", "type": "QString", "name": "outline_style"},
+ )
+
+ option2_9 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": outline_width, "type": "QString", "name": "outline_width"},
+ )
+
+ option2_10 = ET.SubElement(
+ option2,
+ "Option",
+ attrib={"value": "MM", "type": "QString", "name": "outline_width_unit"},
+ )
+
+ option2_11 = ET.SubElement(
+ option2, "Option", attrib={"value": "solid", "type": "QString", "name": "style"}
+ )
+
+ data_defined_properties2 = ET.SubElement(layer, "data_defined_properties")
+
+ option3 = ET.SubElement(data_defined_properties2, "Option", attrib={"type": "Map"})
+
+ option3_1 = ET.SubElement(
+ option3, "Option", attrib={"value": "", "type": "QString", "name": "name"}
+ )
+ option3_2 = ET.SubElement(option3, "Option", attrib={"name": "properties"})
+
+ option3_3 = ET.SubElement(
+ option3,
+ "Option",
+ attrib={"value": "collection", "type": "QString", "name": "type"},
+ )
+
+
+def save_qgis_qml_file(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ value: str = "formation",
+ color: str = "color",
+ outline_width: Union[int, float] = 0.26,
+ alpha: Union[int, float] = 1,
+ path: str = "",
+):
"""Creating and saving a QGIS Style File/QML File based on a GeoDataFrame
Parameters
@@ -867,56 +965,67 @@ def save_qgis_qml_file(gdf: gpd.geodataframe.GeoDataFrame,
from PIL import ImageColor
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Pillow package is not installed. Use "pip install Pillow" to install the latest version')
+ 'Pillow package is not installed. Use "pip install Pillow" to install the latest version'
+ )
# Trying to import xml but returning an error if xml is not installed
try:
import xml.etree.cElementTree as ET
except ModuleNotFoundError:
- raise ModuleNotFoundError('xml package is not installed')
+ raise ModuleNotFoundError("xml package is not installed")
# Checking that the gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be a GeoDataFrame')
+ raise TypeError("gdf must be a GeoDataFrame")
# Checking that the geometry column is present in the gdf
- if not 'geometry' in gdf:
- raise ValueError('geometry column not present in GeoDataFrame')
+ if "geometry" not in gdf:
+ raise ValueError("geometry column not present in GeoDataFrame")
# Checking that all geometries are Polygons
- if not all(gdf.geom_type == 'Polygon'):
- raise ValueError('All geometries of the GeoDataFrame must be polygons')
+ if not all(gdf.geom_type == "Polygon"):
+ raise ValueError("All geometries of the GeoDataFrame must be polygons")
# Checking that the value used for the categorization in QGIS is of type string
if not isinstance(value, str):
- raise TypeError('value column name must be of type string')
+ raise TypeError("value column name must be of type string")
# Checking that the value column is present in the gdf
- if not value in gdf:
+ if value not in gdf:
raise ValueError('"%s" not in gdf. Please provide a valid column name.' % value)
# Checking that the color column is of type string
if not isinstance(color, str):
- raise TypeError('color column name must be of type string')
+ raise TypeError("color column name must be of type string")
# Checking that the value column is present in the gdf
- if not color in gdf:
+ if color not in gdf:
raise ValueError('"%s" not in gdf. Please provide a valid column name.' % color)
# Creating RGBA column from hex colors
- gdf['RGBA'] = [str(ImageColor.getcolor(color, "RGBA")).lstrip('(').rstrip(')').replace(' ', '') for color in
- gdf[color]]
+ gdf["RGBA"] = [
+ str(ImageColor.getcolor(color, "RGBA")).lstrip("(").rstrip(")").replace(" ", "")
+ for color in gdf[color]
+ ]
# Defining category subelement values
- render_text = ['true'] * len(gdf['formation'].unique())
- value_text = gdf['formation'].unique().tolist()
- type_text = ['string'] * len(gdf['formation'].unique())
- label_text = gdf['formation'].unique().tolist()
- symbol_text = [str(value) for value in np.arange(0, len(gdf['formation'].unique())).tolist()]
- outline_width = [str(outline_width)] * len(gdf['formation'].unique())
- alpha = [str(alpha)] * len(gdf['formation'].unique())
-
- list_values_categories = [render_text, value_text, type_text, label_text, symbol_text]
+ render_text = ["true"] * len(gdf["formation"].unique())
+ value_text = gdf["formation"].unique().tolist()
+ type_text = ["string"] * len(gdf["formation"].unique())
+ label_text = gdf["formation"].unique().tolist()
+ symbol_text = [
+ str(value) for value in np.arange(0, len(gdf["formation"].unique())).tolist()
+ ]
+ outline_width = [str(outline_width)] * len(gdf["formation"].unique())
+ alpha = [str(alpha)] * len(gdf["formation"].unique())
+
+ list_values_categories = [
+ render_text,
+ value_text,
+ type_text,
+ label_text,
+ symbol_text,
+ ]
# Defining category subelement keys
list_keys_categories = ["render", "value", "type", "label", "symbol"]
@@ -925,92 +1034,92 @@ def save_qgis_qml_file(gdf: gpd.geodataframe.GeoDataFrame,
category_name = "category"
# Creating Root Element
- root = ET.Element("qgis", attrib={"version": '3.28.1-Firenze',
- "styleCategories": 'Symbology'})
+ root = ET.Element(
+ "qgis", attrib={"version": "3.28.1-Firenze", "styleCategories": "Symbology"}
+ )
# Inserting Comment
comment = ET.Comment("DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM''")
root.insert(0, comment)
# Creating renderer element
- renderer = ET.SubElement(root, "renderer-v2", attrib={"attr": value,
- "symbollevels": '0',
- "type": 'categorizedSymbol',
- "forecaster": '0',
- "referencescale": '-1',
- "enableorderby": '0'})
+ renderer = ET.SubElement(
+ root,
+ "renderer-v2",
+ attrib={
+ "attr": value,
+ "symbollevels": "0",
+ "type": "categorizedSymbol",
+ "forecaster": "0",
+ "referencescale": "-1",
+ "enableorderby": "0",
+ },
+ )
# Creating categories element
- categories = ET.SubElement(renderer, 'categories')
+ categories = ET.SubElement(renderer, "categories")
# Creating elements and attributes
- list_attributes = create_attributes(list_keys_categories,
- list_values_categories)
- [create_subelement(categories,
- category_name,
- attrib) for attrib in list_attributes]
+ list_attributes = create_attributes(list_keys_categories, list_values_categories)
+ [create_subelement(categories, category_name, attrib) for attrib in list_attributes]
# Creating Symbols
- symbols = ET.SubElement(renderer,
- 'symbols')
-
- [create_symbol(symbols,
- color,
- symbol,
- outline_w,
- opacity) for color, symbol, outline_w, opacity in zip(gdf['RGBA'].unique(),
- symbol_text,
- outline_width, alpha)]
-
- source_symbol = ET.SubElement(renderer,
- 'source_symbol')
-
- create_symbol(source_symbol,
- color='152,125,183,255',
- symbol_text='0',
- outline_width=outline_width[0],
- alpha=alpha[0])
-
- roation = ET.SubElement(renderer,
- 'rotation',
- attrib={})
-
- sizescale = ET.SubElement(renderer,
- 'sizescale',
- attrib={})
-
- blendMode = ET.SubElement(root,
- "blendMode", )
+ symbols = ET.SubElement(renderer, "symbols")
+
+ [
+ create_symbol(symbols, color, symbol, outline_w, opacity)
+ for color, symbol, outline_w, opacity in zip(
+ gdf["RGBA"].unique(), symbol_text, outline_width, alpha
+ )
+ ]
+
+ source_symbol = ET.SubElement(renderer, "source_symbol")
+
+ create_symbol(
+ source_symbol,
+ color="152,125,183,255",
+ symbol_text="0",
+ outline_width=outline_width[0],
+ alpha=alpha[0],
+ )
+
+ roation = ET.SubElement(renderer, "rotation", attrib={})
+
+ sizescale = ET.SubElement(renderer, "sizescale", attrib={})
+
+ blendMode = ET.SubElement(
+ root,
+ "blendMode",
+ )
blendMode.text = "0"
- featureblendMode = ET.SubElement(root,
- "featureBlendMode")
+ featureblendMode = ET.SubElement(root, "featureBlendMode")
featureblendMode.text = "0"
- layerGeometryType = ET.SubElement(root,
- "layerGeometryType")
+ layerGeometryType = ET.SubElement(root, "layerGeometryType")
layerGeometryType.text = "2"
# Creating tree
tree = ET.ElementTree(root)
# Insert line breaks
- ET.indent(tree, ' ')
+ ET.indent(tree, " ")
# Saving file
tree.write(path, encoding="utf-8", xml_declaration=False)
- print('QML file successfully saved as %s' % path)
+ print("QML file successfully saved as %s" % path)
-def clip_fault_of_gempy_model(geo_model,
- fault: str,
- which: str = 'first',
- buffer_first: Union[int, float] = None,
- buffer_last: Union[int, float] = None,
- i_size: Union[int, float] = 1000,
- j_size: Union[int, float] = 1000,
- invert_first: bool = True,
- invert_last: bool = False) -> Union[
- pv.core.pointset.PolyData, List[pv.core.pointset.PolyData]]:
+def clip_fault_of_gempy_model(
+ geo_model,
+ fault: str,
+ which: str = "first",
+ buffer_first: Union[int, float] = None,
+ buffer_last: Union[int, float] = None,
+ i_size: Union[int, float] = 1000,
+ j_size: Union[int, float] = 1000,
+ invert_first: bool = True,
+ invert_last: bool = False,
+) -> Union[pv.core.pointset.PolyData, List[pv.core.pointset.PolyData]]:
"""
Clip fault of a GemPy model.
@@ -1058,143 +1167,170 @@ def clip_fault_of_gempy_model(geo_model,
"""
# Trying to import gempy but returning error if gempy is not installed
- try:
- import gempy as gp
- except ModuleNotFoundError:
- raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ # try:
+ # import gempy as gp
+ # except ModuleNotFoundError:
+ # raise ModuleNotFoundError(
+ # 'GemPy package is not installed. Use pip install gempy to install the latest version')
# Checking that the fault is provided as string
if not isinstance(fault, str):
- raise TypeError('Faults must be provided as one string for one fault ')
+ raise TypeError("Faults must be provided as one string for one fault ")
# Checking that the fault is a fault of the geo_model
if isinstance(fault, str):
- if not fault in geo_model.surfaces.df['surface'][geo_model.surfaces.df['isFault'] == True].tolist():
- raise ValueError('Fault is not part of the GemPy geo_model')
+ if (
+ fault
+ not in geo_model.surfaces.df["surface"][
+ geo_model.surfaces.df["isFault"] == True
+ ].tolist()
+ ):
+ raise ValueError("Fault is not part of the GemPy geo_model")
# Getting the fault DataFrames
fault_df_interfaces = geo_model.surface_points.df[
- geo_model.surface_points.df['surface'] == fault].reset_index(drop=True)
+ geo_model.surface_points.df["surface"] == fault
+ ].reset_index(drop=True)
fault_df_orientations = geo_model.orientations.df[
- geo_model.orientations.df['surface'] == fault].reset_index(drop=True)
+ geo_model.orientations.df["surface"] == fault
+ ].reset_index(drop=True)
# Checking that the parameter which is of type string or list of strings
if not isinstance(which, str):
raise TypeError(
- 'The parameter "which" must be provided as string. Options for each fault include "first", "last", or "both"')
+ 'The parameter "which" must be provided as string. Options for each fault include "first", "last", or "both"'
+ )
# Checking that the correct values are provided for the parameter which
if isinstance(which, str):
- if not which in ['first', 'last', 'both']:
- raise ValueError('The options for the parameter "which" include "first", "last", or "both"')
+ if which not in ["first", "last", "both"]:
+ raise ValueError(
+ 'The options for the parameter "which" include "first", "last", or "both"'
+ )
# Checking that the i size is of type int or float
if not isinstance(i_size, (int, float)):
- raise TypeError('i_size must be provided as int or float')
+ raise TypeError("i_size must be provided as int or float")
# Checking that the j size is of type int or float
if not isinstance(j_size, (int, float)):
- raise TypeError('j_size must be provided as int or float')
+ raise TypeError("j_size must be provided as int or float")
# Extracting depth map
- mesh = visualization.create_depth_maps_from_gempy(geo_model,
- surfaces=fault)
+ mesh = visualization.create_depth_maps_from_gempy(geo_model, surfaces=fault)
# Getting the first interface points
- if which == 'first':
+ if which == "first":
- fault_df_interfaces_selected = fault_df_interfaces.iloc[0:1].reset_index(drop=True)
+ fault_df_interfaces_selected = fault_df_interfaces.iloc[0:1].reset_index(
+ drop=True
+ )
# Creating plane from DataFrames
- plane, azimuth = create_plane_from_interface_and_orientation_dfs(df_interface=fault_df_interfaces_selected,
- df_orientations=fault_df_orientations,
- i_size=i_size,
- j_size=j_size)
+ plane, azimuth = create_plane_from_interface_and_orientation_dfs(
+ df_interface=fault_df_interfaces_selected,
+ df_orientations=fault_df_orientations,
+ i_size=i_size,
+ j_size=j_size,
+ )
# Translating Clipping Plane
if buffer_first:
# Checking that buffer_first is of type int or float
if not isinstance(buffer_first, (int, float)):
- raise TypeError('buffer_first must be provided as int or float')
+ raise TypeError("buffer_first must be provided as int or float")
- plane = translate_clipping_plane(plane=plane,
- azimuth=azimuth,
- buffer=buffer_first)
+ plane = translate_clipping_plane(
+ plane=plane, azimuth=azimuth, buffer=buffer_first
+ )
# Clipping mesh
- mesh[fault][0] = mesh[fault][0].clip_surface(plane,
- invert=invert_first)
+ mesh[fault][0] = mesh[fault][0].clip_surface(plane, invert=invert_first)
# Getting the last interface points
- elif which == 'last':
+ elif which == "last":
- fault_df_interfaces_selected = fault_df_interfaces.iloc[-1:].reset_index(drop=True)
+ fault_df_interfaces_selected = fault_df_interfaces.iloc[-1:].reset_index(
+ drop=True
+ )
# Creating plane from DataFrames
- plane, azimuth = create_plane_from_interface_and_orientation_dfs(df_interface=fault_df_interfaces_selected,
- df_orientations=fault_df_orientations,
- i_size=i_size,
- j_size=j_size)
+ plane, azimuth = create_plane_from_interface_and_orientation_dfs(
+ df_interface=fault_df_interfaces_selected,
+ df_orientations=fault_df_orientations,
+ i_size=i_size,
+ j_size=j_size,
+ )
# Translating Clipping Plane
if buffer_last:
# Checking that buffer_last is of type int or float
if not isinstance(buffer_last, (int, float)):
- raise TypeError('buffer_last must be provided as int or float')
+ raise TypeError("buffer_last must be provided as int or float")
- plane = translate_clipping_plane(plane=plane,
- azimuth=azimuth,
- buffer=buffer_last)
+ plane = translate_clipping_plane(
+ plane=plane, azimuth=azimuth, buffer=buffer_last
+ )
# Clipping mesh
- mesh[fault][0] = mesh[fault][0].clip_surface(plane,
- invert_last)
+ mesh[fault][0] = mesh[fault][0].clip_surface(plane, invert_last)
- if which == 'both':
+ if which == "both":
# First point
- fault_df_interfaces_selected = fault_df_interfaces.iloc[0:1].reset_index(drop=True)
+ fault_df_interfaces_selected = fault_df_interfaces.iloc[0:1].reset_index(
+ drop=True
+ )
# Creating plane from DataFrames
- plane1, azimuth1 = create_plane_from_interface_and_orientation_dfs(df_interface=fault_df_interfaces_selected,
- df_orientations=fault_df_orientations,
- i_size=i_size,
- j_size=j_size)
+ plane1, azimuth1 = create_plane_from_interface_and_orientation_dfs(
+ df_interface=fault_df_interfaces_selected,
+ df_orientations=fault_df_orientations,
+ i_size=i_size,
+ j_size=j_size,
+ )
# Translating Clipping Plane
if buffer_first:
- plane1 = translate_clipping_plane(plane=plane1,
- azimuth=azimuth1,
- buffer=buffer_first)
+ plane1 = translate_clipping_plane(
+ plane=plane1, azimuth=azimuth1, buffer=buffer_first
+ )
# Last Point
- fault_df_interfaces_selected = fault_df_interfaces.iloc[-1:].reset_index(drop=True)
+ fault_df_interfaces_selected = fault_df_interfaces.iloc[-1:].reset_index(
+ drop=True
+ )
# Creating plane from DataFrames
- plane2, azimuth2 = create_plane_from_interface_and_orientation_dfs(df_interface=fault_df_interfaces_selected,
- df_orientations=fault_df_orientations,
- i_size=i_size,
- j_size=j_size)
+ plane2, azimuth2 = create_plane_from_interface_and_orientation_dfs(
+ df_interface=fault_df_interfaces_selected,
+ df_orientations=fault_df_orientations,
+ i_size=i_size,
+ j_size=j_size,
+ )
# Translating Clipping Plane
if buffer_last:
- plane2 = translate_clipping_plane(plane=plane2,
- azimuth=azimuth2,
- buffer=-buffer_last)
+ plane2 = translate_clipping_plane(
+ plane=plane2, azimuth=azimuth2, buffer=-buffer_last
+ )
# Clipping mesh
- mesh[fault][0] = mesh[fault][0].clip_surface(plane1,
- invert=invert_first).clip_surface(plane2,
- invert=invert_last)
+ mesh[fault][0] = (
+ mesh[fault][0]
+ .clip_surface(plane1, invert=invert_first)
+ .clip_surface(plane2, invert=invert_last)
+ )
return mesh
-def create_plane_from_interface_and_orientation_dfs(df_interface: pd.DataFrame,
- df_orientations: pd.DataFrame,
- i_size: Union[int, float] = 1000,
- j_size: Union[int, float] = 1000) -> pv.core.pointset.PolyData:
+def create_plane_from_interface_and_orientation_dfs(
+ df_interface: pd.DataFrame,
+ df_orientations: pd.DataFrame,
+ i_size: Union[int, float] = 1000,
+ j_size: Union[int, float] = 1000,
+) -> pv.core.pointset.PolyData:
"""
Create PyVista plane from GemPy interface and orientations DataFrames.
@@ -1229,54 +1365,57 @@ def create_plane_from_interface_and_orientation_dfs(df_interface: pd.DataFrame,
"""
# Checking that the interface DataFrame is a DataFrame
if not isinstance(df_interface, pd.DataFrame):
- raise TypeError('Interface must be provided as Pandas DataFrame')
+ raise TypeError("Interface must be provided as Pandas DataFrame")
# Checking that the orientations DataFrame is a DataFrame
if not isinstance(df_orientations, pd.DataFrame):
- raise TypeError('Orientations must be provided as Pandas DataFrame')
+ raise TypeError("Orientations must be provided as Pandas DataFrame")
# Checking that the i size is of type int or float
if not isinstance(i_size, (int, float)):
- raise TypeError('i_size must be provided as int or float')
+ raise TypeError("i_size must be provided as int or float")
# Checking that the j size is of type int or float
if not isinstance(j_size, (int, float)):
- raise TypeError('j_size must be provided as int or float')
+ raise TypeError("j_size must be provided as int or float")
# Creating GeoDataFrame from interface
- gdf_interface = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=df_interface['X'],
- y=df_interface['Y']),
- data=df_interface)
+ gdf_interface = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(x=df_interface["X"], y=df_interface["Y"]),
+ data=df_interface,
+ )
# Creating GeoDataFrame from orientations
- gdf_orientations = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=df_orientations['X'],
- y=df_orientations['Y']),
- data=df_orientations)
+ gdf_orientations = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(x=df_orientations["X"], y=df_orientations["Y"]),
+ data=df_orientations,
+ )
# Finding nearest orientation to the respective interface to set the orientation of the plane
- gdf_orientations_nearest = gpd.sjoin_nearest(gdf_interface,
- gdf_orientations)
+ gdf_orientations_nearest = gpd.sjoin_nearest(gdf_interface, gdf_orientations)
# Extracting azimuth for clipping plane
- azimuth = gdf_orientations_nearest['azimuth'][0]
+ azimuth = gdf_orientations_nearest["azimuth"][0]
# Extracting center of clipping plane
- center = df_interface[['X', 'Y', 'Z']].values[0]
+ center = df_interface[["X", "Y", "Z"]].values[0]
# Creating clipping plane, direction is created from the orientation of the fault.
- plane = pv.Plane(center=center,
- direction=(np.cos(np.radians(azimuth)),
- np.sin(np.radians(azimuth)),
- 0.0),
- i_size=i_size,
- j_size=j_size)
+ plane = pv.Plane(
+ center=center,
+ direction=(np.cos(np.radians(azimuth)), np.sin(np.radians(azimuth)), 0.0),
+ i_size=i_size,
+ j_size=j_size,
+ )
return plane, azimuth
-def translate_clipping_plane(plane: pv.core.pointset.PolyData,
- azimuth: Union[int, float, np.int64],
- buffer: Union[int, float]) -> pv.core.pointset.PolyData:
+def translate_clipping_plane(
+ plane: pv.core.pointset.PolyData,
+ azimuth: Union[int, float, np.int64],
+ buffer: Union[int, float],
+) -> pv.core.pointset.PolyData:
"""
Translate clipping plane.
@@ -1308,23 +1447,27 @@ def translate_clipping_plane(plane: pv.core.pointset.PolyData,
"""
# Checking that the plane is of type PyVista PolyData
if not isinstance(plane, pv.core.pointset.PolyData):
- raise TypeError('The clipping plane must be provided as PyVista PolyData')
+ raise TypeError("The clipping plane must be provided as PyVista PolyData")
# Checking that the azimuth is of type int or float
if not isinstance(azimuth, (int, float, np.int64)):
- raise TypeError('The azimuth must be provided as int or float')
+ raise TypeError("The azimuth must be provided as int or float")
# Checking that the buffer is of type int or float
if not isinstance(buffer, (int, float, type(None))):
- raise TypeError('The buffer must be provided as int or float')
+ raise TypeError("The buffer must be provided as int or float")
# Calculating translation factor in X and Y Directio
x_translation = -np.cos(np.radians(azimuth)) * buffer
y_translation = -np.sin(np.radians(azimuth)) * buffer
# Translating plane
- plane = plane.translate((x_translation * np.cos(np.radians(azimuth)),
- y_translation * np.sin(np.radians(azimuth)),
- 0.0))
+ plane = plane.translate(
+ (
+ x_translation * np.cos(np.radians(azimuth)),
+ y_translation * np.sin(np.radians(azimuth)),
+ 0.0,
+ )
+ )
return plane
diff --git a/gemgis/raster.py b/gemgis/raster.py
index 8f619bec..8a5b5f17 100644
--- a/gemgis/raster.py
+++ b/gemgis/raster.py
@@ -28,18 +28,19 @@
import pandas as pd
import geopandas as gpd
from typing import Union, List, Sequence, Optional, Iterable, Dict, Tuple
-from rasterio.mask import mask
-from shapely.geometry import box, Polygon, LineString
+from shapely.geometry import Polygon, LineString
import shapely
from pathlib import Path
import affine
import pyproj
-def sample_from_array(array: np.ndarray,
- extent: Sequence[float],
- point_x: Union[float, int, list, np.ndarray],
- point_y: Union[float, int, list, np.ndarray], ) -> Union[np.ndarray, float]:
+def sample_from_array(
+ array: np.ndarray,
+ extent: Sequence[float],
+ point_x: Union[float, int, list, np.ndarray],
+ point_y: Union[float, int, list, np.ndarray],
+) -> Union[np.ndarray, float]:
"""Sampling the value of a np.ndarray at a given point and given the arrays true extent
Parameters
@@ -96,58 +97,58 @@ def sample_from_array(array: np.ndarray,
# Checking is the array is a np.ndarray
if not isinstance(array, np.ndarray):
- raise TypeError('Object must be of type np.ndarray')
+ raise TypeError("Object must be of type np.ndarray")
# Checking if the extent is a list
if not isinstance(extent, Sequence):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that the length of the list is either four or six
if len(extent) not in [4, 6]:
- raise ValueError('The extent must include only four or six values')
+ raise ValueError("The extent must include only four or six values")
# Checking if the point coordinates are stored as a list
if not isinstance(point_x, (list, np.ndarray, float, int)):
- raise TypeError('Point_x must be of type list or np.ndarray')
+ raise TypeError("Point_x must be of type list or np.ndarray")
# Checking if the point coordinates are stored as a list
if not isinstance(point_y, (list, np.ndarray, float, int)):
- raise TypeError('Point_y must be of type list or np.ndarray')
+ raise TypeError("Point_y must be of type list or np.ndarray")
# Checking the length of the point list
if not isinstance(point_x, (float, int)) and not isinstance(point_y, (float, int)):
if len(point_x) != len(point_y):
- raise ValueError('Length of both point lists/arrays must be equal')
+ raise ValueError("Length of both point lists/arrays must be equal")
# Checking that all elements of the extent are of type int or float
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ raise TypeError("Extent values must be of type int or float")
# Checking that all elements of the point list are of type int or float
if isinstance(point_x, (list, np.ndarray)):
if not all(isinstance(n, (int, float, np.int32)) for n in point_x):
- raise TypeError('Point values must be of type int or float')
+ raise TypeError("Point values must be of type int or float")
# Checking that all elements of the point list are of type int or float
if isinstance(point_y, (list, np.ndarray)):
if not all(isinstance(n, (int, float)) for n in point_y):
- raise TypeError('Point values must be of type int or float')
+ raise TypeError("Point values must be of type int or float")
# Checking if the point is located within the provided extent
if isinstance(point_x, (list, np.ndarray)):
if any(x < extent[0] for x in point_x) or any(x > extent[1] for x in point_x):
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError("One or multiple points are located outside of the extent")
if isinstance(point_y, (list, np.ndarray)):
if any(y < extent[2] for y in point_y) or any(y > extent[3] for y in point_y):
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError("One or multiple points are located outside of the extent")
# Checking if the point is located within the provided extent
if isinstance(point_x, (float, int)):
if point_x < extent[0] or point_x > extent[1]:
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError("One or multiple points are located outside of the extent")
if isinstance(point_y, (float, int)):
if point_y < extent[2] or point_y > extent[3]:
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError("One or multiple points are located outside of the extent")
# Converting lists of coordinates to np.ndarrays
if isinstance(point_x, list) and isinstance(point_y, list):
@@ -155,15 +156,21 @@ def sample_from_array(array: np.ndarray,
point_y = np.array(point_y)
# Getting the column number based on the extent and shape of the array
- column = np.int32(np.round((point_x - extent[0]) / (extent[1] - extent[0]) * array.shape[1]))
+ column = np.int32(
+ np.round((point_x - extent[0]) / (extent[1] - extent[0]) * array.shape[1])
+ )
# Getting the row number based on the extent and shape of the array
- row = np.int32(np.round((point_y - extent[2]) / (extent[3] - extent[2]) * array.shape[0]))
+ row = np.int32(
+ np.round((point_y - extent[2]) / (extent[3] - extent[2]) * array.shape[0])
+ )
# Checking that all elements for the column and row numbers are of type int
if isinstance(row, np.ndarray) and isinstance(column, np.ndarray):
- if not all(isinstance(n, np.int32) for n in column) and not all(isinstance(n, np.int32) for n in row):
- raise TypeError('Column and row values must be of type int for indexing')
+ if not all(isinstance(n, np.int32) for n in column) and not all(
+ isinstance(n, np.int32) for n in row
+ ):
+ raise TypeError("Column and row values must be of type int for indexing")
# Flip array so that the column and row indices are correct
array = np.flipud(array)
@@ -179,11 +186,13 @@ def sample_from_array(array: np.ndarray,
return sample
-def sample_from_rasterio(raster: rasterio.io.DatasetReader,
- point_x: Union[float, int, list, np.ndarray],
- point_y: Union[float, int, list, np.ndarray],
- sample_outside_extent: bool = True,
- sample_all_bands: bool = False) -> Union[list, float]:
+def sample_from_rasterio(
+ raster: rasterio.io.DatasetReader,
+ point_x: Union[float, int, list, np.ndarray],
+ point_y: Union[float, int, list, np.ndarray],
+ sample_outside_extent: bool = True,
+ sample_all_bands: bool = False,
+) -> Union[list, float]:
"""Sampling the value of a rasterio object at a given point within the extent of the raster
Parameters
@@ -241,56 +250,68 @@ def sample_from_rasterio(raster: rasterio.io.DatasetReader,
# Checking that the raster is a rasterio object
if not isinstance(raster, rasterio.io.DatasetReader):
- raise TypeError('Raster must be provided as rasterio object')
+ raise TypeError("Raster must be provided as rasterio object")
# Checking if the point coordinates are stored as a list
if not isinstance(point_x, (list, np.ndarray, float, int)):
- raise TypeError('Point_x must be of type list or np.ndarray')
+ raise TypeError("Point_x must be of type list or np.ndarray")
# Checking if the point coordinates are stored as a list
if not isinstance(point_y, (list, np.ndarray, float, int)):
- raise TypeError('Point_y must be of type list or np.ndarray')
+ raise TypeError("Point_y must be of type list or np.ndarray")
# Checking the length of the point list
if not isinstance(point_x, (float, int)) and not isinstance(point_y, (float, int)):
if len(point_x) != len(point_y):
- raise ValueError('Length of both point lists/arrays must be equal')
+ raise ValueError("Length of both point lists/arrays must be equal")
# Checking that all elements of the point list are of type int or float
if isinstance(point_x, (list, np.ndarray)):
if not all(isinstance(n, (int, float, np.int32, np.float64)) for n in point_x):
- raise TypeError('Point values must be of type int or float')
+ raise TypeError("Point values must be of type int or float")
# Checking that all elements of the point list are of type int or float
if isinstance(point_y, (list, np.ndarray)):
if not all(isinstance(n, (int, float, np.int32, np.float64)) for n in point_y):
- raise TypeError('Point values must be of type int or float')
+ raise TypeError("Point values must be of type int or float")
# Checking that sample_outside_extent is of type bool
if not isinstance(sample_outside_extent, bool):
- raise TypeError('Sample_outside_extent argument must be of type bool')
+ raise TypeError("Sample_outside_extent argument must be of type bool")
# Checking that sample_all_bands is of type bool
if not isinstance(sample_all_bands, bool):
- raise TypeError('Sample_all_bands argument must be of type bool')
+ raise TypeError("Sample_all_bands argument must be of type bool")
# If sample_outside extent is true, a nodata value will be assigned
if not sample_outside_extent:
# Checking if the point is located within the provided raster extent
if isinstance(point_x, (list, np.ndarray)):
- if any(x < raster.bounds[0] for x in point_x) or any(x > raster.bounds[2] for x in point_x):
- raise ValueError('One or multiple points are located outside of the extent')
+ if any(x < raster.bounds[0] for x in point_x) or any(
+ x > raster.bounds[2] for x in point_x
+ ):
+ raise ValueError(
+ "One or multiple points are located outside of the extent"
+ )
if isinstance(point_y, (list, np.ndarray)):
- if any(y < raster.bounds[1] for y in point_y) or any(y > raster.bounds[3] for y in point_y):
- raise ValueError('One or multiple points are located outside of the extent')
+ if any(y < raster.bounds[1] for y in point_y) or any(
+ y > raster.bounds[3] for y in point_y
+ ):
+ raise ValueError(
+ "One or multiple points are located outside of the extent"
+ )
# Checking if the point is located within the provided raster extent
if isinstance(point_x, (float, int)):
if point_x < raster.bounds[0] or point_x > raster.bounds[2]:
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError(
+ "One or multiple points are located outside of the extent"
+ )
if isinstance(point_y, (float, int)):
if point_y < raster.bounds[1] or point_y > raster.bounds[3]:
- raise ValueError('One or multiple points are located outside of the extent')
+ raise ValueError(
+ "One or multiple points are located outside of the extent"
+ )
# Converting lists of coordinates to np.ndarrays
if isinstance(point_x, list) and isinstance(point_y, list):
@@ -315,10 +336,12 @@ def sample_from_rasterio(raster: rasterio.io.DatasetReader,
return sample
-def sample_randomly(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- n: int = 1,
- extent: Optional[Sequence[float]] = None,
- seed: int = None) -> tuple:
+def sample_randomly(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ n: int = 1,
+ extent: Optional[Sequence[float]] = None,
+ seed: int = None,
+) -> tuple:
"""Sampling randomly from a raster (array or rasterio object) using sample_from_array or sample_from_rasterio
and a randomly drawn point within the array/raster extent
@@ -371,31 +394,31 @@ def sample_randomly(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if the array is of type np.ndarrays
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Array must be of type np.ndarray')
+ raise TypeError("Array must be of type np.ndarray")
# Checking that n is of type int
if not isinstance(n, int):
- raise TypeError('Number of samples n must be provided as int')
+ raise TypeError("Number of samples n must be provided as int")
# Checking if seed is of type int
if not isinstance(seed, (int, type(None))):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that if a seed was provided that the seed is of type int
if seed is not None:
if not isinstance(seed, int):
- raise TypeError('Seed must be of type int')
+ raise TypeError("Seed must be of type int")
np.random.seed(seed)
# Checking if extent is a list
if not isinstance(extent, (list, type(None))):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Sampling from Array
# Checking that all values are either ints or floats
if isinstance(raster, np.ndarray):
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ raise TypeError("Extent values must be of type int or float")
# Drawing random values x and y within the provided extent
x = np.random.uniform(extent[0], extent[1], n)
@@ -403,9 +426,9 @@ def sample_randomly(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if the drawn values are floats
if not isinstance(x, np.ndarray):
- raise TypeError('x must be of type np.ndarray')
+ raise TypeError("x must be of type np.ndarray")
if not isinstance(y, np.ndarray):
- raise TypeError('y must be of type np.ndarray')
+ raise TypeError("y must be of type np.ndarray")
# Sampling from the provided array and the random point
sample = sample_from_array(array=raster, extent=extent, point_x=x, point_y=y)
@@ -420,9 +443,9 @@ def sample_randomly(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if the drawn values are floats
if not isinstance(x, np.ndarray):
- raise TypeError('x must be of type np.ndarray')
+ raise TypeError("x must be of type np.ndarray")
if not isinstance(y, np.ndarray):
- raise TypeError('y must be of type np.ndarray')
+ raise TypeError("y must be of type np.ndarray")
sample = sample_from_rasterio(raster=raster, point_x=x, point_y=y)
@@ -435,15 +458,17 @@ def sample_randomly(raster: Union[np.ndarray, rasterio.io.DatasetReader],
return sample, [x, y]
-def sample_orientations(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- extent: List[Union[int, float]] = None,
- point_x: Union[float, int, list, np.ndarray] = None,
- point_y: Union[float, int, list, np.ndarray] = None,
- random_samples: int = None,
- formation: str = None,
- seed: int = None,
- sample_outside_extent: bool = False,
- crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None) -> gpd.geodataframe.GeoDataFrame:
+def sample_orientations(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ extent: List[Union[int, float]] = None,
+ point_x: Union[float, int, list, np.ndarray] = None,
+ point_y: Union[float, int, list, np.ndarray] = None,
+ random_samples: int = None,
+ formation: str = None,
+ seed: int = None,
+ sample_outside_extent: bool = False,
+ crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+) -> gpd.geodataframe.GeoDataFrame:
"""Sampling orientations from a raster
Parameters
@@ -515,92 +540,115 @@ def sample_orientations(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if the rasterio of type np.ndarray or a rasterio object
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster must be of type np.ndarray or a rasterio object")
# Checking if the extent is of type list if an array is provided
if isinstance(raster, np.ndarray) and not isinstance(extent, list):
- raise TypeError('Extent must be of type list when providing an array')
+ raise TypeError("Extent must be of type list when providing an array")
# Checking that all elements of the extent are of type float or int
- if isinstance(raster, np.ndarray) and not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ if isinstance(raster, np.ndarray) and not all(
+ isinstance(n, (int, float)) for n in extent
+ ):
+ raise TypeError("Extent values must be of type int or float")
# Checking if the number of samples is of type int
if point_x is None and point_y is None and not isinstance(random_samples, int):
- raise TypeError('Number of samples must be of type int if no points are provided')
+ raise TypeError(
+ "Number of samples must be of type int if no points are provided"
+ )
# Checking if the points are of the correct type
- if isinstance(random_samples, type(None)) and not isinstance(point_x, (float, int, list, np.ndarray)):
- raise TypeError('Point_x must either be an int, float or a list or array of coordinates')
+ if isinstance(random_samples, type(None)) and not isinstance(
+ point_x, (float, int, list, np.ndarray)
+ ):
+ raise TypeError(
+ "Point_x must either be an int, float or a list or array of coordinates"
+ )
# Checking if the points are of the correct type
- if isinstance(random_samples, type(None)) and not isinstance(point_y, (float, int, list, np.ndarray)):
- raise TypeError('Point_y must either be an int, float or a list or array of coordinates')
+ if isinstance(random_samples, type(None)) and not isinstance(
+ point_y, (float, int, list, np.ndarray)
+ ):
+ raise TypeError(
+ "Point_y must either be an int, float or a list or array of coordinates"
+ )
# Checking if the seed is of type int
if not isinstance(seed, (int, type(None))):
- raise TypeError('Seed must be of type int')
+ raise TypeError("Seed must be of type int")
# Checking that sampling outside extent is of type bool
if not isinstance(sample_outside_extent, bool):
- raise TypeError('Sampling_outside_extent must be of type bool')
+ raise TypeError("Sampling_outside_extent must be of type bool")
# Checking that the crs is either a string or of type bool
if not isinstance(crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS, type(None))):
- raise TypeError('CRS must be provided as string, pyproj or rasterio object')
+ raise TypeError("CRS must be provided as string, pyproj or rasterio object")
# Calculate slope and aspect of raster
- slope = calculate_slope(raster=raster,
- extent=extent)
+ slope = calculate_slope(raster=raster, extent=extent)
- aspect = calculate_aspect(raster=raster,
- extent=extent)
+ aspect = calculate_aspect(raster=raster, extent=extent)
# Sampling interfaces
- gdf = sample_interfaces(raster=raster,
- extent=extent,
- point_x=point_x,
- point_y=point_y,
- random_samples=random_samples,
- formation=formation,
- seed=seed,
- sample_outside_extent=sample_outside_extent,
- crs=crs)
+ gdf = sample_interfaces(
+ raster=raster,
+ extent=extent,
+ point_x=point_x,
+ point_y=point_y,
+ random_samples=random_samples,
+ formation=formation,
+ seed=seed,
+ sample_outside_extent=sample_outside_extent,
+ crs=crs,
+ )
# Setting the array extent for the dip and azimuth sampling
if isinstance(raster, rasterio.io.DatasetReader):
- raster_extent = [raster.bounds[0], raster.bounds[2], raster.bounds[1], raster.bounds[3]]
+ raster_extent = [
+ raster.bounds[0],
+ raster.bounds[2],
+ raster.bounds[1],
+ raster.bounds[3],
+ ]
else:
raster_extent = extent
# Sampling dip and azimuth at the given locations
- dip = sample_from_array(array=slope,
- extent=raster_extent,
- point_x=gdf['X'].values,
- point_y=gdf['Y'].values)
-
- azimuth = sample_from_array(array=aspect,
- extent=raster_extent,
- point_x=gdf['X'].values,
- point_y=gdf['Y'].values)
+ dip = sample_from_array(
+ array=slope,
+ extent=raster_extent,
+ point_x=gdf["X"].values,
+ point_y=gdf["Y"].values,
+ )
+
+ azimuth = sample_from_array(
+ array=aspect,
+ extent=raster_extent,
+ point_x=gdf["X"].values,
+ point_y=gdf["Y"].values,
+ )
# Adding columns to the GeoDataFrame
- gdf['dip'] = dip
- gdf['azimuth'] = azimuth
- gdf['polarity'] = 1
+ gdf["dip"] = dip
+ gdf["azimuth"] = azimuth
+ gdf["polarity"] = 1
return gdf
-def sample_interfaces(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- extent: List[Union[int, float]] = None,
- point_x: Union[float, int, list, np.ndarray] = None,
- point_y: Union[float, int, list, np.ndarray] = None,
- random_samples: int = None,
- formation: str = None,
- seed: int = None,
- sample_outside_extent: bool = False,
- crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None) -> gpd.geodataframe.GeoDataFrame:
+def sample_interfaces(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ extent: List[Union[int, float]] = None,
+ point_x: Union[float, int, list, np.ndarray] = None,
+ point_y: Union[float, int, list, np.ndarray] = None,
+ random_samples: int = None,
+ formation: str = None,
+ seed: int = None,
+ sample_outside_extent: bool = False,
+ crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+) -> gpd.geodataframe.GeoDataFrame:
"""Sampling interfaces from a raster
Parameters
@@ -672,60 +720,72 @@ def sample_interfaces(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if the rasterio of type np.ndarray or a rasterio object
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster must be of type np.ndarray or a rasterio object")
# Checking if the extent is of type list if an array is provided
if isinstance(raster, np.ndarray) and not isinstance(extent, list):
- raise TypeError('Extent must be of type list when providing an array')
+ raise TypeError("Extent must be of type list when providing an array")
# Checking that all elements of the extent are of type float or int
- if isinstance(raster, np.ndarray) and not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ if isinstance(raster, np.ndarray) and not all(
+ isinstance(n, (int, float)) for n in extent
+ ):
+ raise TypeError("Extent values must be of type int or float")
# Checking if the number of samples is of type int
if point_x is None and point_y is None and not isinstance(random_samples, int):
- raise TypeError('Number of samples must be of type int if no points are provided')
+ raise TypeError(
+ "Number of samples must be of type int if no points are provided"
+ )
# Checking if the points are of the correct type
- if isinstance(random_samples, type(None)) and not isinstance(point_x, (float, int, list, np.ndarray)):
- raise TypeError('Point_x must either be an int, float or a list or array of coordinates')
+ if isinstance(random_samples, type(None)) and not isinstance(
+ point_x, (float, int, list, np.ndarray)
+ ):
+ raise TypeError(
+ "Point_x must either be an int, float or a list or array of coordinates"
+ )
# Checking if the points are of the correct type
- if isinstance(random_samples, type(None)) and not isinstance(point_y, (float, int, list, np.ndarray)):
- raise TypeError('Point_y must either be an int, float or a list or array of coordinates')
+ if isinstance(random_samples, type(None)) and not isinstance(
+ point_y, (float, int, list, np.ndarray)
+ ):
+ raise TypeError(
+ "Point_y must either be an int, float or a list or array of coordinates"
+ )
# Checking if the seed is of type int
if not isinstance(seed, (int, type(None))):
- raise TypeError('Seed must be of type int')
+ raise TypeError("Seed must be of type int")
# Checking that sampling outside extent is of type bool
if not isinstance(sample_outside_extent, bool):
- raise TypeError('Sampling_outside_extent must be of type bool')
+ raise TypeError("Sampling_outside_extent must be of type bool")
# Checking that the crs is either a string or of type bool
if not isinstance(crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS, type(None))):
- raise TypeError('CRS must be provided as string, pyproj CRS or rasterio CRS')
+ raise TypeError("CRS must be provided as string, pyproj CRS or rasterio CRS")
# Sampling by points
if random_samples is None and point_x is not None and point_y is not None:
# Sampling from Raster
if isinstance(raster, rasterio.io.DatasetReader):
- z = sample_from_rasterio(raster=raster,
- point_x=point_x,
- point_y=point_y,
- sample_outside_extent=sample_outside_extent)
+ z = sample_from_rasterio(
+ raster=raster,
+ point_x=point_x,
+ point_y=point_y,
+ sample_outside_extent=sample_outside_extent,
+ )
# Sampling from array
else:
- z = sample_from_array(array=raster,
- extent=extent,
- point_x=point_x,
- point_y=point_y)
+ z = sample_from_array(
+ array=raster, extent=extent, point_x=point_x, point_y=point_y
+ )
# Sampling randomly
elif random_samples is not None and point_x is None and point_y is None:
- samples = sample_randomly(raster=raster,
- n=random_samples,
- extent=extent,
- seed=seed)
+ samples = sample_randomly(
+ raster=raster, n=random_samples, extent=extent, seed=seed
+ )
# Assigning X, Y and Z values
z = [i for i in samples[0]]
@@ -735,31 +795,31 @@ def sample_interfaces(raster: Union[np.ndarray, rasterio.io.DatasetReader],
point_y = [i for i in samples[1][1]]
else:
- raise TypeError('Either provide only lists or array of points or a number of random samples, not both.')
+ raise TypeError(
+ "Either provide only lists or array of points or a number of random samples, not both."
+ )
# Creating GeoDataFrame
if isinstance(point_x, Iterable) and isinstance(point_y, Iterable):
- gdf = gpd.GeoDataFrame(data=pd.DataFrame(data=[point_x, point_y, z]).T,
- geometry=gpd.points_from_xy(x=point_x,
- y=point_y,
- crs=crs)
- )
+ gdf = gpd.GeoDataFrame(
+ data=pd.DataFrame(data=[point_x, point_y, z]).T,
+ geometry=gpd.points_from_xy(x=point_x, y=point_y, crs=crs),
+ )
else:
- gdf = gpd.GeoDataFrame(data=pd.DataFrame(data=[point_x, point_y, z]).T,
- geometry=gpd.points_from_xy(x=[point_x],
- y=[point_y],
- crs=crs)
- )
+ gdf = gpd.GeoDataFrame(
+ data=pd.DataFrame(data=[point_x, point_y, z]).T,
+ geometry=gpd.points_from_xy(x=[point_x], y=[point_y], crs=crs),
+ )
# Setting the column names
- gdf.columns = ['X', 'Y', 'Z', 'geometry']
+ gdf.columns = ["X", "Y", "Z", "geometry"]
# Assigning formation name
if formation is not None:
if isinstance(formation, str):
- gdf['formation'] = formation
+ gdf["formation"] = formation
else:
- raise TypeError('Formation must be provided as string or set to None')
+ raise TypeError("Formation must be provided as string or set to None")
return gdf
@@ -768,11 +828,13 @@ def sample_interfaces(raster: Union[np.ndarray, rasterio.io.DatasetReader],
###############################
-def calculate_hillshades(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- extent: List[Union[int, float]] = None,
- azdeg: Union[int, float] = 225,
- altdeg: Union[int, float] = 45,
- band_no: int = 1) -> np.ndarray:
+def calculate_hillshades(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ extent: List[Union[int, float]] = None,
+ azdeg: Union[int, float] = 225,
+ altdeg: Union[int, float] = 45,
+ band_no: int = 1,
+) -> np.ndarray:
"""Calculating Hillshades based on digital elevation model/raster
Parameters
@@ -827,27 +889,27 @@ def calculate_hillshades(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking that the raster is of type rasterio object or numpy array
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be provided as rasterio object or NumPy array')
+ raise TypeError("Raster must be provided as rasterio object or NumPy array")
# Checking if extent is of type list
if not isinstance(extent, (type(None), list)):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that altdeg is of type float or int
if not isinstance(altdeg, (float, int)):
- raise TypeError('altdeg must be of type int or float')
+ raise TypeError("altdeg must be of type int or float")
# Checking that azdeg is of type float or int
if not isinstance(azdeg, (float, int)):
- raise TypeError('azdeg must be of type int or float')
+ raise TypeError("azdeg must be of type int or float")
# Checking that altdeg is not out of bounds
if altdeg > 90 or altdeg < 0:
- raise ValueError('altdeg must be between 0 and 90 degrees')
+ raise ValueError("altdeg must be between 0 and 90 degrees")
# Checking that azdeg is not out of bounds
if azdeg > 360 or azdeg < 0:
- raise ValueError('azdeg must be between 0 and 360 degrees')
+ raise ValueError("azdeg must be between 0 and 360 degrees")
# Checking if object is rasterio object
if isinstance(raster, rasterio.io.DatasetReader):
@@ -862,24 +924,25 @@ def calculate_hillshades(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if object is of type np.ndarray
if not isinstance(raster, np.ndarray):
- raise TypeError('Input object must be of type np.ndarray')
+ raise TypeError("Input object must be of type np.ndarray")
# Checking if dimension of array is correct
if not raster.ndim == 2:
- raise ValueError('Array must be of dimension 2')
+ raise ValueError("Array must be of dimension 2")
# Calculate hillshades
azdeg = 360 - azdeg
x, y = np.gradient(raster)
x = x / res[0]
y = y / res[1]
- slope = np.pi / 2. - np.arctan(np.sqrt(x * x + y * y))
+ slope = np.pi / 2.0 - np.arctan(np.sqrt(x * x + y * y))
aspect = np.arctan2(-x, y)
- azimuthrad = azdeg * np.pi / 180.
- altituderad = altdeg * np.pi / 180.
+ azimuthrad = azdeg * np.pi / 180.0
+ altituderad = altdeg * np.pi / 180.0
- shaded = np.sin(altituderad) * np.sin(slope) + np.cos(altituderad) * np.cos(slope) * np.cos(
- (azimuthrad - np.pi / 2.) - aspect)
+ shaded = np.sin(altituderad) * np.sin(slope) + np.cos(altituderad) * np.cos(
+ slope
+ ) * np.cos((azimuthrad - np.pi / 2.0) - aspect)
# Calculate color values
hillshades = 255 * (shaded + 1) / 2
@@ -887,9 +950,11 @@ def calculate_hillshades(raster: Union[np.ndarray, rasterio.io.DatasetReader],
return hillshades
-def calculate_slope(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- extent: List[Union[int, float]] = None,
- band_no: int = 1) -> np.ndarray:
+def calculate_slope(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ extent: List[Union[int, float]] = None,
+ band_no: int = 1,
+) -> np.ndarray:
"""Calculating the slope based on digital elevation model/raster
Parameters
@@ -938,11 +1003,11 @@ def calculate_slope(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking that the raster is of type rasterio object or numpy array
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be provided as rasterio object or NumPy array')
+ raise TypeError("Raster must be provided as rasterio object or NumPy array")
# Checking if extent is of type list
if not isinstance(extent, (type(None), list)):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking if object is rasterio object
if isinstance(raster, rasterio.io.DatasetReader):
@@ -957,11 +1022,11 @@ def calculate_slope(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if object is of type np.ndarray
if not isinstance(raster, np.ndarray):
- raise TypeError('Input object must be of type np.ndarray')
+ raise TypeError("Input object must be of type np.ndarray")
# Checking if dimension of array is correct
if not raster.ndim == 2:
- raise ValueError('Array must be of dimension 2')
+ raise ValueError("Array must be of dimension 2")
# Calculate slope
y, x = np.gradient(raster)
@@ -973,9 +1038,11 @@ def calculate_slope(raster: Union[np.ndarray, rasterio.io.DatasetReader],
return slope
-def calculate_aspect(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- extent: List[Union[int, float]] = None,
- band_no: int = 1) -> np.ndarray:
+def calculate_aspect(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ extent: List[Union[int, float]] = None,
+ band_no: int = 1,
+) -> np.ndarray:
"""Calculating the aspect based on a digital elevation model/raster
Parameters
@@ -1024,11 +1091,11 @@ def calculate_aspect(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking that the raster is of type rasterio object or numpy array
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be provided as rasterio object or NumPy array')
+ raise TypeError("Raster must be provided as rasterio object or NumPy array")
# Checking if extent is of type list
if not isinstance(extent, (type(None), list)):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking if object is rasterio object
if isinstance(raster, rasterio.io.DatasetReader):
@@ -1043,11 +1110,11 @@ def calculate_aspect(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if object is of type np.ndarray
if not isinstance(raster, np.ndarray):
- raise TypeError('Input object must be of type np.ndarray')
+ raise TypeError("Input object must be of type np.ndarray")
# Checking if dimension of array is correct
if not raster.ndim == 2:
- raise ValueError('Array must be of dimension 2')
+ raise ValueError("Array must be of dimension 2")
# Calculate aspect
y, x = np.gradient(raster)
@@ -1060,9 +1127,11 @@ def calculate_aspect(raster: Union[np.ndarray, rasterio.io.DatasetReader],
return aspect
-def calculate_difference(raster1: Union[np.ndarray, rasterio.io.DatasetReader],
- raster2: Union[np.ndarray, rasterio.io.DatasetReader],
- flip_array: bool = False) -> np.ndarray:
+def calculate_difference(
+ raster1: Union[np.ndarray, rasterio.io.DatasetReader],
+ raster2: Union[np.ndarray, rasterio.io.DatasetReader],
+ flip_array: bool = False,
+) -> np.ndarray:
"""Calculating the difference between two rasters
Parameters
@@ -1112,14 +1181,16 @@ def calculate_difference(raster1: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if array1 is of type np.ndarray or a rasterio object
if not isinstance(raster1, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster1 must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster1 must be of type np.ndarray or a rasterio object")
# Checking if array2 is of type np.ndarray or a rasterio object
if not isinstance(raster2, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster2 must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster2 must be of type np.ndarray or a rasterio object")
# Subtracting rasterio objects
- if isinstance(raster1, rasterio.io.DatasetReader) and isinstance(raster2, rasterio.io.DatasetReader):
+ if isinstance(raster1, rasterio.io.DatasetReader) and isinstance(
+ raster2, rasterio.io.DatasetReader
+ ):
array_diff = raster1.read() - raster2.read()
else:
@@ -1127,8 +1198,7 @@ def calculate_difference(raster1: Union[np.ndarray, rasterio.io.DatasetReader],
if raster1.shape != raster2.shape:
# Rescale array
- array_rescaled = resize_by_array(raster=raster2,
- array=raster1)
+ array_rescaled = resize_by_array(raster=raster2, array=raster1)
# Flip array if flip_array is True
if flip_array:
array_rescaled = np.flipud(array_rescaled)
@@ -1151,13 +1221,15 @@ def calculate_difference(raster1: Union[np.ndarray, rasterio.io.DatasetReader],
######################
-def clip_by_bbox(raster: Union[rasterio.io.DatasetReader, np.ndarray],
- bbox: List[Union[int, float]],
- raster_extent: List[Union[int, float]] = None,
- save_clipped_raster: bool = False,
- path: str = 'raster_clipped.tif',
- overwrite_file: bool = False,
- create_directory: bool = False) -> np.ndarray:
+def clip_by_bbox(
+ raster: Union[rasterio.io.DatasetReader, np.ndarray],
+ bbox: List[Union[int, float]],
+ raster_extent: List[Union[int, float]] = None,
+ save_clipped_raster: bool = False,
+ path: str = "raster_clipped.tif",
+ overwrite_file: bool = False,
+ create_directory: bool = False,
+) -> np.ndarray:
"""Clipping a rasterio raster or np.ndarray by a given extent
Parameters
@@ -1225,23 +1297,23 @@ def clip_by_bbox(raster: Union[rasterio.io.DatasetReader, np.ndarray],
# Checking that the raster is of type np.ndarray or a rasterio object
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster must be of type np.ndarray or a rasterio object")
# Checking that the extent is of type list
if not isinstance(bbox, list):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that all values are either ints or floats
if not all(isinstance(n, (int, float)) for n in bbox):
- raise TypeError('Bounds values must be of type int or float')
+ raise TypeError("Bounds values must be of type int or float")
# Checking that save_clipped_raster is of type bool
if not isinstance(save_clipped_raster, bool):
- raise TypeError('save_clipped_raster must either be True or False')
+ raise TypeError("save_clipped_raster must either be True or False")
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('The path must be provided as string')
+ raise TypeError("The path must be provided as string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -1258,75 +1330,110 @@ def clip_by_bbox(raster: Union[rasterio.io.DatasetReader, np.ndarray],
if create_directory:
os.makedirs(path_dir)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
if not overwrite_file:
if os.path.exists(path):
- raise FileExistsError("The file already exists. Pass overwrite_file=True to overwrite the existing file")
+ raise FileExistsError(
+ "The file already exists. Pass overwrite_file=True to overwrite the existing file"
+ )
# Checking if raster is rasterio object
if isinstance(raster, rasterio.io.DatasetReader):
- raster_clipped, raster_transform = rasterio.mask.mask(dataset=raster,
- shapes=[Polygon([(bbox[0], bbox[2]),
- (bbox[1], bbox[2]),
- (bbox[1], bbox[3]),
- (bbox[0], bbox[3])])],
- crop=True,
- filled=False,
- pad=False,
- pad_width=0)
+ raster_clipped, raster_transform = rasterio.mask.mask(
+ dataset=raster,
+ shapes=[
+ Polygon(
+ [
+ (bbox[0], bbox[2]),
+ (bbox[1], bbox[2]),
+ (bbox[1], bbox[3]),
+ (bbox[0], bbox[3]),
+ ]
+ )
+ ],
+ crop=True,
+ filled=False,
+ pad=False,
+ pad_width=0,
+ )
# Saving the raster
if save_clipped_raster:
# Updating meta data
raster_clipped_meta = raster.meta
- raster_clipped_meta.update({"driver": "GTiff",
- "height": raster_clipped.shape[1],
- "width": raster_clipped.shape[2],
- "transform": raster_transform})
+ raster_clipped_meta.update(
+ {
+ "driver": "GTiff",
+ "height": raster_clipped.shape[1],
+ "width": raster_clipped.shape[2],
+ "transform": raster_transform,
+ }
+ )
# Writing the file
with rasterio.open(path, "w", **raster_clipped_meta) as dest:
dest.write(raster_clipped)
# Swap axes and remove dimension
- raster_clipped = np.flipud(np.rot90(np.swapaxes(raster_clipped, 0, 2)[:, :, 0], 1))
+ raster_clipped = np.flipud(
+ np.rot90(np.swapaxes(raster_clipped, 0, 2)[:, :, 0], 1)
+ )
else:
# Checking that the extent is provided as list
if not isinstance(raster_extent, list):
- raise TypeError('The raster extent must be provided as list of corner values')
+ raise TypeError(
+ "The raster extent must be provided as list of corner values"
+ )
# Checking that all values are either ints or floats
if not all(isinstance(n, (int, float)) for n in raster_extent):
- raise TypeError('Bounds values must be of type int or float')
+ raise TypeError("Bounds values must be of type int or float")
# Create column and row indices for clipping
- column1 = int((bbox[0] - raster_extent[0]) / (raster_extent[1] - raster_extent[0]) * raster.shape[1])
- row1 = int((bbox[1] - raster_extent[2]) / (raster_extent[3] - raster_extent[2]) * raster.shape[0])
- column2 = int((bbox[2] - raster_extent[0]) / (raster_extent[1] - raster_extent[0]) * raster.shape[1])
- row2 = int((bbox[3] - raster_extent[2]) / (raster_extent[3] - raster_extent[2]) * raster.shape[0])
+ column1 = int(
+ (bbox[0] - raster_extent[0])
+ / (raster_extent[1] - raster_extent[0])
+ * raster.shape[1]
+ )
+ row1 = int(
+ (bbox[1] - raster_extent[2])
+ / (raster_extent[3] - raster_extent[2])
+ * raster.shape[0]
+ )
+ column2 = int(
+ (bbox[2] - raster_extent[0])
+ / (raster_extent[1] - raster_extent[0])
+ * raster.shape[1]
+ )
+ row2 = int(
+ (bbox[3] - raster_extent[2])
+ / (raster_extent[3] - raster_extent[2])
+ * raster.shape[0]
+ )
# Clip raster
raster_clipped = raster[column1:row1, column2:row2]
# Save raster
if save_clipped_raster:
- save_as_tiff(raster=raster_clipped,
- path=path,
- extent=bbox,
- crs='EPSG:4326')
+ save_as_tiff(raster=raster_clipped, path=path, extent=bbox, crs="EPSG:4326")
return raster_clipped
-def clip_by_polygon(raster: Union[rasterio.io.DatasetReader, np.ndarray],
- polygon: shapely.geometry.polygon.Polygon,
- raster_extent: List[Union[int, float]] = None,
- save_clipped_raster: bool = False,
- path: str = 'raster_clipped.tif',
- overwrite_file: bool = False,
- create_directory: bool = False) -> np.ndarray:
+def clip_by_polygon(
+ raster: Union[rasterio.io.DatasetReader, np.ndarray],
+ polygon: shapely.geometry.polygon.Polygon,
+ raster_extent: List[Union[int, float]] = None,
+ save_clipped_raster: bool = False,
+ path: str = "raster_clipped.tif",
+ overwrite_file: bool = False,
+ create_directory: bool = False,
+) -> np.ndarray:
"""Clipping/masking a rasterio raster or np.ndarray by a given shapely Polygon
Parameters
@@ -1395,19 +1502,19 @@ def clip_by_polygon(raster: Union[rasterio.io.DatasetReader, np.ndarray],
# Checking that the raster is of type np.ndarray or a rasterio object
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster must be of type np.ndarray or a rasterio object")
# Checking that the polygon is a Shapely Polygon
if not isinstance(polygon, shapely.geometry.polygon.Polygon):
- raise TypeError('Polygon must be a Shapely Polygon')
+ raise TypeError("Polygon must be a Shapely Polygon")
# Checking that save_clipped_raster is of type bool
if not isinstance(save_clipped_raster, bool):
- raise TypeError('save_clipped_raster must either be True or False')
+ raise TypeError("save_clipped_raster must either be True or False")
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('The path must be provided as string')
+ raise TypeError("The path must be provided as string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -1424,48 +1531,66 @@ def clip_by_polygon(raster: Union[rasterio.io.DatasetReader, np.ndarray],
if create_directory:
os.makedirs(path_dir)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
if not overwrite_file:
if os.path.exists(path):
raise FileExistsError(
- "The file already exists. Pass overwrite_file=True to overwrite the existing file")
+ "The file already exists. Pass overwrite_file=True to overwrite the existing file"
+ )
# Masking raster
if isinstance(raster, rasterio.io.DatasetReader):
- raster_clipped, raster_transform = rasterio.mask.mask(dataset=raster,
- shapes=[polygon],
- crop=True,
- filled=False,
- pad=False,
- pad_width=0)
+ raster_clipped, raster_transform = rasterio.mask.mask(
+ dataset=raster,
+ shapes=[polygon],
+ crop=True,
+ filled=False,
+ pad=False,
+ pad_width=0,
+ )
# Saving the raster
if save_clipped_raster:
# Updating meta data
raster_clipped_meta = raster.meta
- raster_clipped_meta.update({"driver": "GTiff",
- "height": raster_clipped.shape[1],
- "width": raster_clipped.shape[2],
- "transform": raster_transform})
+ raster_clipped_meta.update(
+ {
+ "driver": "GTiff",
+ "height": raster_clipped.shape[1],
+ "width": raster_clipped.shape[2],
+ "transform": raster_transform,
+ }
+ )
# Writing the raster to file
with rasterio.open(path, "w", **raster_clipped_meta) as dest:
dest.write(raster_clipped)
# Swap axes and remove dimension
- raster_clipped = np.flipud(np.rot90(np.swapaxes(raster_clipped, 0, 2)[:, :, 0], 1))
+ raster_clipped = np.flipud(
+ np.rot90(np.swapaxes(raster_clipped, 0, 2)[:, :, 0], 1)
+ )
else:
# Converting the polygon to a rectangular bbox
- bbox = [polygon.bounds[0], polygon.bounds[2], polygon.bounds[1], polygon.bounds[2]]
+ bbox = [
+ polygon.bounds[0],
+ polygon.bounds[2],
+ polygon.bounds[1],
+ polygon.bounds[2],
+ ]
# Clipping raster
- raster_clipped = clip_by_bbox(raster=raster,
- bbox=bbox,
- raster_extent=raster_extent,
- save_clipped_raster=save_clipped_raster,
- path=path)
+ raster_clipped = clip_by_bbox(
+ raster=raster,
+ bbox=bbox,
+ raster_extent=raster_extent,
+ save_clipped_raster=save_clipped_raster,
+ path=path,
+ )
return raster_clipped
@@ -1474,8 +1599,10 @@ def clip_by_polygon(raster: Union[rasterio.io.DatasetReader, np.ndarray],
######################
-def resize_by_array(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- array: Union[np.ndarray, rasterio.io.DatasetReader]) -> np.ndarray:
+def resize_by_array(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader],
+ array: Union[np.ndarray, rasterio.io.DatasetReader],
+) -> np.ndarray:
"""Rescaling raster to the size of another raster
Parameters
@@ -1525,23 +1652,23 @@ def resize_by_array(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if array1 is of type np.ndarray
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray or a rasterio object')
+ raise TypeError("Raster must be of type np.ndarray or a rasterio object")
# Checking if array2 is of type np.ndarray
if not isinstance(array, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('array must be of type np.ndarray or a rasterio object')
+ raise TypeError("array must be of type np.ndarray or a rasterio object")
# Resize raster by shape of array
- array_resized = resize_raster(raster=raster,
- width=array.shape[1],
- height=array.shape[0])
+ array_resized = resize_raster(
+ raster=raster, width=array.shape[1], height=array.shape[0]
+ )
return array_resized
-def resize_raster(raster: Union[np.ndarray, rasterio.io.DatasetReader],
- width: int,
- height: int) -> np.ndarray:
+def resize_raster(
+ raster: Union[np.ndarray, rasterio.io.DatasetReader], width: int, height: int
+) -> np.ndarray:
"""Resizing raster to given dimensions
Parameters
@@ -1592,11 +1719,12 @@ def resize_raster(raster: Union[np.ndarray, rasterio.io.DatasetReader],
from skimage.transform import resize
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Scikit Image package is not installed. Use pip install scikit-image to install the latest version')
+ "Scikit Image package is not installed. Use pip install scikit-image to install the latest version"
+ )
# Checking if array1 is of type np.ndarray
if not isinstance(raster, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Raster must be of type np.ndarray')
+ raise TypeError("Raster must be of type np.ndarray")
# Converting rasterio object to array
if isinstance(raster, rasterio.io.DatasetReader):
@@ -1604,14 +1732,13 @@ def resize_raster(raster: Union[np.ndarray, rasterio.io.DatasetReader],
# Checking if dimensions are of type int
if not isinstance(width, int):
- raise TypeError('Width must be of type int')
+ raise TypeError("Width must be of type int")
if not isinstance(height, int):
- raise TypeError('Height must be of type int')
+ raise TypeError("Height must be of type int")
# Resizing the array
- array_resized = resize(image=raster,
- output_shape=(height, width))
+ array_resized = resize(image=raster, output_shape=(height, width))
return array_resized
@@ -1620,10 +1747,7 @@ def resize_raster(raster: Union[np.ndarray, rasterio.io.DatasetReader],
#############################################
# Defining dtype Conversion
-dtype_conversion = {
- "Integer": np.int32,
- "Double": np.float64
-}
+dtype_conversion = {"Integer": np.int32, "Double": np.float64}
def read_msh(path: Union[str, Path]) -> Dict[str, np.ndarray]:
@@ -1676,7 +1800,7 @@ def read_msh(path: Union[str, Path]) -> Dict[str, np.ndarray]:
# Checking that the path is of type string or a path
if not isinstance(path, (str, Path)):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -1694,15 +1818,16 @@ def read_msh(path: Union[str, Path]) -> Dict[str, np.ndarray]:
f.seek(header_end + 0x14)
# Extracting data from each line
- for line in chunk[chunk.find(b"[index]") + 8:header_end].decode("utf-8").strip().split("\n"):
+ for line in (
+ chunk[chunk.find(b"[index]") + 8 : header_end]
+ .decode("utf-8")
+ .strip()
+ .split("\n")
+ ):
name, dtype, *shape = line.strip().rstrip(";").split()
shape = list(map(int, reversed(shape)))
dtype = dtype_conversion[dtype]
- data[name] = np.fromfile(
- f,
- dtype,
- np.prod(shape)
- ).reshape(shape)
+ data[name] = np.fromfile(f, dtype, np.prod(shape)).reshape(shape)
return data
@@ -1761,7 +1886,7 @@ def read_ts(path: Union[str, Path]) -> Tuple[list, list]:
# Checking that the path is of type string or a path
if not isinstance(path, (str, Path)):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -1790,7 +1915,10 @@ def read_ts(path: Union[str, Path]) -> Tuple[list, list]:
if line_type == "PROPERTIES":
columns += values
- elif line_type == "TFACE":
+ # Deleting duplicate column names
+ columns = list(dict.fromkeys(columns))
+
+ elif line_type == "TFACE" or line_type == "END":
# Creating array for faces
faces = np.array(faces, dtype=np.int32)
@@ -1868,7 +1996,7 @@ def read_asc(path: Union[str, Path]) -> dict:
# Checking that the path is of type string or a path
if not isinstance(path, (str, Path)):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -1883,21 +2011,21 @@ def read_asc(path: Union[str, Path]) -> dict:
if not line.strip():
continue
line_value, *values = line.split()
- if line_value == 'ncols':
+ if line_value == "ncols":
ncols = int(values[0])
- if line_value == 'nrows':
+ if line_value == "nrows":
nrows = int(values[0])
- if line_value == 'xllcenter':
+ if line_value == "xllcenter":
xllcenter = float(values[0])
- if line_value == 'yllcenter':
+ if line_value == "yllcenter":
yllcenter = float(values[0])
- if line_value == 'cellsize':
+ if line_value == "cellsize":
res = float(values[0])
- if line_value == 'xllcorner':
+ if line_value == "xllcorner":
xllcenter = float(values[0]) + 0.5 * res
- if line_value == 'yllcorner':
+ if line_value == "yllcorner":
yllcenter = float(values[0]) + 0.5 * res
- if line_value == 'NODATA_value' or line_value == 'nodata_value':
+ if line_value == "NODATA_value" or line_value == "nodata_value":
nodata_val = float(values[0])
# Load data and replace nodata_values with np.nan
@@ -1905,10 +2033,17 @@ def read_asc(path: Union[str, Path]) -> dict:
data[data == nodata_val] = np.nan
# Creating dict and store data
- data = {'Data': data,
- 'Extent': [xllcenter, xllcenter + res * ncols, yllcenter, yllcenter + res * nrows],
- 'Resolution': res,
- 'Nodata_val': np.nan}
+ data = {
+ "Data": data,
+ "Extent": [
+ xllcenter,
+ xllcenter + res * ncols,
+ yllcenter,
+ yllcenter + res * nrows,
+ ],
+ "Resolution": res,
+ "Nodata_val": np.nan,
+ }
return data
@@ -1966,7 +2101,7 @@ def read_zmap(path: Union[str, Path]) -> dict:
# Checking that the path is of type string or a path
if not isinstance(path, (str, Path)):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -2007,20 +2142,22 @@ def read_zmap(path: Union[str, Path]) -> dict:
# Getting array data
data = [
- (float(d) if d.strip() != nodata else np.nan) for line in f for d in line.split()
+ (float(d) if d.strip() != nodata else np.nan)
+ for line in f
+ for d in line.split()
]
# Creating dict for data
data = {
- 'Data': np.array(data).reshape((nrows, ncols), order="F"),
- 'Extent': extent,
- 'Resolution': resolution,
- 'Nodata_val': float(nodata),
- 'Dimensions': (nrows, ncols),
- 'CRS': crs,
- 'Creation_date': creation_date,
- 'Creation_time': creation_time,
- 'File_name': zmap_file_name
+ "Data": np.array(data).reshape((nrows, ncols), order="F"),
+ "Extent": extent,
+ "Resolution": resolution,
+ "Nodata_val": float(nodata),
+ "Dimensions": (nrows, ncols),
+ "CRS": crs,
+ "Creation_date": creation_date,
+ "Creation_time": creation_time,
+ "File_name": zmap_file_name,
}
return data
@@ -2030,14 +2167,16 @@ def read_zmap(path: Union[str, Path]) -> dict:
################################
-def save_as_tiff(raster: np.ndarray,
- path: str,
- extent: Union[List[Union[int, float]], Tuple[Union[int, float]]],
- crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS],
- nodata: Union[float, int] = None,
- transform=None,
- overwrite_file: bool = False,
- create_directory: bool = False):
+def save_as_tiff(
+ raster: np.ndarray,
+ path: str,
+ extent: Union[List[Union[int, float]], Tuple[Union[int, float]]],
+ crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS],
+ nodata: Union[float, int] = None,
+ transform=None,
+ overwrite_file: bool = False,
+ create_directory: bool = False,
+):
"""Saving a np.array as tif file
Parameters
@@ -2092,7 +2231,7 @@ def save_as_tiff(raster: np.ndarray,
# Checking if path is of type string
if not isinstance(path, str):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Checking that the file has the correct file ending
if not path.endswith(".tif"):
@@ -2109,57 +2248,62 @@ def save_as_tiff(raster: np.ndarray,
if create_directory:
os.makedirs(path_dir)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
if not overwrite_file:
if os.path.exists(path):
raise FileExistsError(
- "The file already exists. Pass overwrite_file=True to overwrite the existing file")
+ "The file already exists. Pass overwrite_file=True to overwrite the existing file"
+ )
# Checking if the array is of type np.ndarray
if not isinstance(raster, np.ndarray):
- raise TypeError('array must be of type np.ndarray')
+ raise TypeError("array must be of type np.ndarray")
# Checking if the extent is of type list
if not isinstance(extent, (list, tuple)):
- raise TypeError('Extent must be of type list or be a tuple')
+ raise TypeError("Extent must be of type list or be a tuple")
# Checking that all values are either ints or floats
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Bound values must be of type int or float')
+ raise TypeError("Bound values must be of type int or float")
# Checking if the crs is of type string
if not isinstance(crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS, dict)):
- raise TypeError('CRS must be of type string, dict, rasterio CRS or pyproj CRS')
+ raise TypeError("CRS must be of type string, dict, rasterio CRS or pyproj CRS")
# Extracting the bounds
minx, miny, maxx, maxy = extent[0], extent[2], extent[1], extent[3]
# Creating the transform
if not transform:
- transform = rasterio.transform.from_bounds(minx, miny, maxx, maxy, raster.shape[1], raster.shape[0])
+ transform = rasterio.transform.from_bounds(
+ minx, miny, maxx, maxy, raster.shape[1], raster.shape[0]
+ )
# Creating and saving the array as tiff
with rasterio.open(
- path,
- 'w',
- driver='GTiff',
- height=raster.shape[0],
- width=raster.shape[1],
- count=1,
- dtype=raster.dtype,
- crs=crs,
- transform=transform,
- nodata=nodata
+ path,
+ "w",
+ driver="GTiff",
+ height=raster.shape[0],
+ width=raster.shape[1],
+ count=1,
+ dtype=raster.dtype,
+ crs=crs,
+ transform=transform,
+ nodata=nodata,
) as dst:
dst.write(np.flipud(raster), 1)
- print('Raster successfully saved')
+ print("Raster successfully saved")
-def create_filepaths(dirpath: str,
- search_criteria: str,
- create_directory: bool = False) -> List[str]:
+def create_filepaths(
+ dirpath: str, search_criteria: str, create_directory: bool = False
+) -> List[str]:
"""Retrieving the file paths of the tiles to load and to process them later
Parameters
@@ -2205,7 +2349,7 @@ def create_filepaths(dirpath: str,
# Checking if dirpath is of type string
if not isinstance(dirpath, str):
- raise TypeError('Path to directory must be of type string')
+ raise TypeError("Path to directory must be of type string")
# Getting the absolute path
dirpath = os.path.abspath(path=dirpath)
@@ -2218,11 +2362,13 @@ def create_filepaths(dirpath: str,
if create_directory:
os.makedirs(path_dir)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
# Checking that the search criterion is of type string
if not isinstance(search_criteria, str):
- raise TypeError('Search Criterion must be of Type string')
+ raise TypeError("Search Criterion must be of Type string")
# Join paths to form path to files
source = os.path.join(dirpath, search_criteria)
@@ -2233,10 +2379,12 @@ def create_filepaths(dirpath: str,
return filepaths
-def create_src_list(dirpath: str = '',
- search_criteria: str = '',
- filepaths: List[str] = None,
- create_directory: bool = False) -> List[rasterio.io.DatasetReader]:
+def create_src_list(
+ dirpath: str = "",
+ search_criteria: str = "",
+ filepaths: List[str] = None,
+ create_directory: bool = False,
+) -> List[rasterio.io.DatasetReader]:
"""Creating a list of source files
Parameters
@@ -2293,7 +2441,7 @@ def create_src_list(dirpath: str = '',
# Checking if dirpath is of type string
if not isinstance(dirpath, str):
- raise TypeError('Path to directory must be of type string')
+ raise TypeError("Path to directory must be of type string")
# Getting the absolute path
dirpath = os.path.abspath(path=dirpath)
@@ -2306,24 +2454,27 @@ def create_src_list(dirpath: str = '',
if create_directory:
os.makedirs(path_dir)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
# Checking that the search criterion is of type string
if not isinstance(search_criteria, str):
- raise TypeError('Search Criterion must be of Type string')
+ raise TypeError("Search Criterion must be of Type string")
# Checking that the filepaths are of type list
if not isinstance(filepaths, (list, type(None))):
- raise TypeError('Filepaths must be of type list')
+ raise TypeError("Filepaths must be of type list")
# Retrieving the file paths of the tiles
- if not dirpath == '':
- if not search_criteria == '':
+ if not dirpath == "":
+ if not search_criteria == "":
if not filepaths:
- filepaths = create_filepaths(dirpath=dirpath,
- search_criteria=search_criteria)
+ filepaths = create_filepaths(
+ dirpath=dirpath, search_criteria=search_criteria
+ )
else:
- raise ValueError('Either provide a file path or a list of filepaths')
+ raise ValueError("Either provide a file path or a list of filepaths")
# Create empty list for source files
src_files = []
@@ -2338,13 +2489,15 @@ def create_src_list(dirpath: str = '',
return src_files
-def merge_tiles(src_files: List[rasterio.io.DatasetReader],
- extent: List[Union[float, int]] = None,
- res: int = None,
- nodata: Union[float, int] = None,
- precision: int = None,
- indices: int = None,
- method: str = 'first') -> Tuple[np.ndarray, affine.Affine]:
+def merge_tiles(
+ src_files: List[rasterio.io.DatasetReader],
+ extent: List[Union[float, int]] = None,
+ res: int = None,
+ nodata: Union[float, int] = None,
+ precision: int = None,
+ indices: int = None,
+ method: str = "first",
+) -> Tuple[np.ndarray, affine.Affine]:
"""Merging downloaded tiles to mosaic
Parameters
@@ -2434,45 +2587,47 @@ def merge_tiles(src_files: List[rasterio.io.DatasetReader],
# Checking if source files are stored in a list
if not isinstance(src_files, list):
- raise TypeError('Files must be stored as list')
+ raise TypeError("Files must be stored as list")
# Checking if extent is a list
if not isinstance(extent, (list, type(None))):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that all values are either ints or floats
if extent:
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ raise TypeError("Extent values must be of type int or float")
# Checking that the resolution is of type int
if not isinstance(res, (int, type(None))):
- raise TypeError('Resolution must be of type int')
+ raise TypeError("Resolution must be of type int")
# Checking that the nodata value is of type int or float
if not isinstance(nodata, (int, float, type(None))):
- raise TypeError('Nodata value must be of type int or float')
+ raise TypeError("Nodata value must be of type int or float")
# Checking that the precision is of type int
if not isinstance(precision, (int, type(None))):
- raise TypeError('Precision value must be of type int')
+ raise TypeError("Precision value must be of type int")
# Checking that the indices for the bands are of type int
if not isinstance(indices, (int, type(None))):
- raise TypeError('Band indices must be of type int')
+ raise TypeError("Band indices must be of type int")
# Checking that the method is of type string
if not isinstance(method, (str, type(None))):
- raise TypeError('Type of method must be provided as string')
+ raise TypeError("Type of method must be provided as string")
# Merging tiles
- mosaic, transformation = merge(src_files,
- bounds=extent,
- res=res,
- nodata=nodata,
- precision=precision,
- indexes=indices,
- method=method)
+ mosaic, transformation = merge(
+ src_files,
+ bounds=extent,
+ res=res,
+ nodata=nodata,
+ precision=precision,
+ indexes=indices,
+ method=method,
+ )
# Swap axes and remove dimension
mosaic = np.flipud(np.rot90(np.swapaxes(mosaic, 0, 2)[:, 0:, 0], 1))
@@ -2480,11 +2635,13 @@ def merge_tiles(src_files: List[rasterio.io.DatasetReader],
return mosaic, transformation
-def reproject_raster(path_in: str,
- path_out: str,
- dst_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS],
- overwrite_file: bool = False,
- create_directory: bool = False):
+def reproject_raster(
+ path_in: str,
+ path_out: str,
+ dst_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS],
+ overwrite_file: bool = False,
+ create_directory: bool = False,
+):
"""Reprojecting a raster into different CRS
Parameters
@@ -2525,7 +2682,7 @@ def reproject_raster(path_in: str,
# Checking that the path_in is of type string
if not isinstance(path_in, str):
- raise TypeError('The path of the source file must be of type string')
+ raise TypeError("The path of the source file must be of type string")
# Getting the absolute path
path_in = os.path.abspath(path=path_in)
@@ -2536,7 +2693,7 @@ def reproject_raster(path_in: str,
# Checking that the path_out is type string
if not isinstance(path_out, str):
- raise TypeError('The path of the destination file must be of type string')
+ raise TypeError("The path of the destination file must be of type string")
# Getting the absolute path
path_out = os.path.abspath(path=path_out)
@@ -2553,31 +2710,34 @@ def reproject_raster(path_in: str,
if create_directory:
os.makedirs(path_dir_out)
else:
- raise LookupError('Directory not found. Pass create_directory=True to create a new directory')
+ raise LookupError(
+ "Directory not found. Pass create_directory=True to create a new directory"
+ )
if not overwrite_file:
if os.path.exists(path_out):
raise FileExistsError(
- "The file already exists. Pass overwrite_file=True to overwrite the existing file")
+ "The file already exists. Pass overwrite_file=True to overwrite the existing file"
+ )
# Checking that the dst_crs is of type string or a pyproj object
if not isinstance(dst_crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS)):
- raise TypeError('The destination CRS must be of type string, pyproj CRS or rasterio CRS')
+ raise TypeError(
+ "The destination CRS must be of type string, pyproj CRS or rasterio CRS"
+ )
# Opening the Source DataSet
with rasterio.open(path_in) as src:
transform, width, height = calculate_default_transform(
- src.crs, dst_crs, src.width, src.height, *src.bounds)
+ src.crs, dst_crs, src.width, src.height, *src.bounds
+ )
kwargs = src.meta.copy()
- kwargs.update({
- 'crs': dst_crs,
- 'transform': transform,
- 'width': width,
- 'height': height
- })
+ kwargs.update(
+ {"crs": dst_crs, "transform": transform, "width": width, "height": height}
+ )
# Writing the Destination DataSet
- with rasterio.open(path_out, 'w', **kwargs) as dst:
+ with rasterio.open(path_out, "w", **kwargs) as dst:
for i in range(1, src.count + 1):
reproject(
source=rasterio.band(src, i),
@@ -2586,14 +2746,16 @@ def reproject_raster(path_in: str,
src_crs=src.crs,
dst_transform=transform,
dst_crs=dst_crs,
- resampling=Resampling.nearest)
+ resampling=Resampling.nearest,
+ )
-def extract_contour_lines_from_raster(raster: Union[rasterio.io.DatasetReader, np.ndarray, str],
- interval: int,
- extent: Union[Optional[Sequence[float]], Optional[Sequence[int]]] = None,
- target_crs: Union[
- str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None) -> gpd.GeoDataFrame:
+def extract_contour_lines_from_raster(
+ raster: Union[rasterio.io.DatasetReader, np.ndarray, str],
+ interval: int,
+ extent: Union[Optional[Sequence[float]], Optional[Sequence[int]]] = None,
+ target_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+) -> gpd.GeoDataFrame:
"""Extracting contour lines from raster with a provided interval.
Parameters
@@ -2625,11 +2787,14 @@ def extract_contour_lines_from_raster(raster: Union[rasterio.io.DatasetReader, n
from skimage import measure
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'skimage package is not installed. Use pip install skimage to install the latest version')
+ "skimage package is not installed. Use pip install skimage to install the latest version"
+ )
# Checking if provided raster is either a file loaded with rasterio, an np.ndarray or a path directing to a .tif file
if not isinstance(raster, (rasterio.io.DatasetReader, np.ndarray, str)):
- raise TypeError("Raster must be a raster loaded with rasterio or a path directing to a .tif file")
+ raise TypeError(
+ "Raster must be a raster loaded with rasterio or a path directing to a .tif file"
+ )
# Checking if provided raster is of type str. If provided raster is a path (directing to a .tif file), load the file with rasterio
if isinstance(raster, str):
@@ -2639,26 +2804,35 @@ def extract_contour_lines_from_raster(raster: Union[rasterio.io.DatasetReader, n
if isinstance(raster, np.ndarray):
if extent is None:
raise UnboundLocalError(
- "For np.ndarray an extent must be provided to extract contour lines from an array")
+ "For np.ndarray an extent must be provided to extract contour lines from an array"
+ )
if extent is not None and not isinstance(extent, Sequence):
raise TypeError("extent values must be of type float or int")
if len(extent) != 4:
- raise TypeError("Not enough arguments in extent to extract contour lines from an array")
+ raise TypeError(
+ "Not enough arguments in extent to extract contour lines from an array"
+ )
if target_crs is None:
raise UnboundLocalError("For np.ndarray a target crs must be provided")
- if target_crs is not None and not isinstance(target_crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS)):
- raise TypeError("target_crs must be of type string, pyproj CRS or rasterio CRS")
-
- save_as_tiff(raster=np.flipud(raster),
- path='input_raster.tif',
- extent=extent,
- crs=target_crs,
- overwrite_file=True)
- raster = rasterio.open('input_raster.tif')
+ if target_crs is not None and not isinstance(
+ target_crs, (str, pyproj.crs.crs.CRS, rasterio.crs.CRS)
+ ):
+ raise TypeError(
+ "target_crs must be of type string, pyproj CRS or rasterio CRS"
+ )
+
+ save_as_tiff(
+ raster=np.flipud(raster),
+ path="input_raster.tif",
+ extent=extent,
+ crs=target_crs,
+ overwrite_file=True,
+ )
+ raster = rasterio.open("input_raster.tif")
# Checking if provided interval is of type int
if not isinstance(interval, int):
@@ -2673,15 +2847,16 @@ def extract_contour_lines_from_raster(raster: Union[rasterio.io.DatasetReader, n
values = []
# Calculating minimum and maximum value from the given raster value
- min_val = int(interval * round(np.amin(raster.read(1)[~np.isnan(raster.read(1))]) / interval))
- max_val = int(interval * round(np.amax(raster.read(1)[~np.isnan(raster.read(1))]) / interval))
+ min_val = int(
+ interval * round(np.amin(raster.read(1)[~np.isnan(raster.read(1))]) / interval)
+ )
+ max_val = int(
+ interval * round(np.amax(raster.read(1)[~np.isnan(raster.read(1))]) / interval)
+ )
# Extracting contour lines and appending to lists
- for value in range(min_val,
- max_val,
- interval):
- contour = measure.find_contours(np.fliplr(raster.read(1).T),
- value)
+ for value in range(min_val, max_val, interval):
+ contour = measure.find_contours(np.fliplr(raster.read(1).T), value)
contours.append(contour)
values.extend([value for i in range(len(contour))])
@@ -2696,28 +2871,32 @@ def extract_contour_lines_from_raster(raster: Union[rasterio.io.DatasetReader, n
x_left, y_bottom, x_right, y_top = raster.bounds
# Transforming and defining the coordinates of contours based on raster extent
- x_new = [x_left + (x_right - x_left) / columns * contours_new[i][:, 0] for i in range(len(contours_new))]
- y_new = [y_bottom + (y_top - y_bottom) / rows * contours_new[i][:, 1] for i in range(len(contours_new))]
+ x_new = [
+ x_left + (x_right - x_left) / columns * contours_new[i][:, 0]
+ for i in range(len(contours_new))
+ ]
+ y_new = [
+ y_bottom + (y_top - y_bottom) / rows * contours_new[i][:, 1]
+ for i in range(len(contours_new))
+ ]
# Converting the contours to lines (LineStrings - Shapely)
- lines = [LineString(np.array([x_new[i],
- y_new[i]]).T) for i in range(len(x_new))]
+ lines = [LineString(np.array([x_new[i], y_new[i]]).T) for i in range(len(x_new))]
# Creating GeoDataFrame from lines
- gdf_lines = gpd.GeoDataFrame(geometry=lines,
- crs=raster.crs)
+ gdf_lines = gpd.GeoDataFrame(geometry=lines, crs=raster.crs)
# Adding value column to GeoDataframe
- gdf_lines['Z'] = values
+ gdf_lines["Z"] = values
return gdf_lines
-def read_raster_gdb(path: str,
- crs: Union[str,
- pyproj.crs.crs.CRS,
- rasterio.crs.CRS] = None,
- path_out: str = ''):
+def read_raster_gdb(
+ path: str,
+ crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+ path_out: str = "",
+):
"""Read Raster from OpenFileGDB.
Parameters
@@ -2736,15 +2915,15 @@ def read_raster_gdb(path: str,
try:
from osgeo import gdal, osr
except ModuleNotFoundError:
- raise ModuleNotFoundError('osgeo package is not installed')
+ raise ModuleNotFoundError("osgeo package is not installed")
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('Path to the OpenFileGDB must be provided as string')
+ raise TypeError("Path to the OpenFileGDB must be provided as string")
# Checking that the output path is of type string
if not isinstance(path_out, str):
- raise TypeError('Output path must be provided as string')
+ raise TypeError("Output path must be provided as string")
# Opening Database
ds = gdal.Open(path)
@@ -2766,26 +2945,30 @@ def read_raster_gdb(path: str,
# Creating CRS from projection or manually
if dataset.GetProjection():
proj = osr.SpatialReference(wkt=dataset.GetProjection())
- epsg = proj.GetAttrValue('AUTHORITY', 1)
- crs = 'EPSG:' + epsg
+ epsg = proj.GetAttrValue("AUTHORITY", 1)
+ crs = "EPSG:" + epsg
else:
if not crs:
raise ValueError(
- 'Raster does not have a projection, please provide a valid coordinate reference system')
+ "Raster does not have a projection, please provide a valid coordinate reference system"
+ )
# Saving raster to file
with rasterio.open(
- path_out + ds.GetSubDatasets()[i][1].replace(' ', '') + '.tif',
- 'w',
- driver='GTiff',
- height=raster.shape[0],
- width=raster.shape[1],
- count=1,
- dtype=raster.dtype,
- crs=crs,
- transform=affine.Affine.from_gdal(*dataset.GetGeoTransform()),
- nodata=raster_band.GetNoDataValue()
+ path_out + ds.GetSubDatasets()[i][1].replace(" ", "") + ".tif",
+ "w",
+ driver="GTiff",
+ height=raster.shape[0],
+ width=raster.shape[1],
+ count=1,
+ dtype=raster.dtype,
+ crs=crs,
+ transform=affine.Affine.from_gdal(*dataset.GetGeoTransform()),
+ nodata=raster_band.GetNoDataValue(),
) as dst:
dst.write(raster, 1)
- print(ds.GetSubDatasets()[i][1].replace(' ', '') + '.tif successfully saved to file')
\ No newline at end of file
+ print(
+ ds.GetSubDatasets()[i][1].replace(" ", "")
+ + ".tif successfully saved to file"
+ )
diff --git a/gemgis/utils.py b/gemgis/utils.py
index 596b3e60..4bc5f0d7 100644
--- a/gemgis/utils.py
+++ b/gemgis/utils.py
@@ -37,9 +37,11 @@
__all__ = [series, crs]
-def to_section_dict(gdf: gpd.geodataframe.GeoDataFrame,
- section_column: str = 'section_name',
- resolution: List[int] = None) -> dict:
+def to_section_dict(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ section_column: str = "section_name",
+ resolution: List[int] = None,
+) -> dict:
"""Converting custom sections stored in Shape files to GemPy section_dicts
Parameters
@@ -85,49 +87,73 @@ def to_section_dict(gdf: gpd.geodataframe.GeoDataFrame,
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if the section_column is of type string
if not isinstance(section_column, str):
- raise TypeError('Name for section_column must be of type string')
+ raise TypeError("Name for section_column must be of type string")
# Checking if resolution is of type list
if not isinstance(resolution, (list, type(None))):
- raise TypeError('Resolution must be of type list')
+ raise TypeError("Resolution must be of type list")
# Setting resolution
if resolution is None:
resolution = [100, 80]
# Checking if X and Y values are in column
- if not {'X', 'Y'}.issubset(gdf.columns):
+ if not {"X", "Y"}.issubset(gdf.columns):
gdf = vector.extract_xy(gdf)
# Checking the length of the resolution list
if len(resolution) != 2:
- raise ValueError('resolution list must be of length two')
+ raise ValueError("resolution list must be of length two")
# Extracting Section names
section_names = gdf[section_column].unique()
# Create section dicts for Point Shape Files
if all(gdf.geom_type == "Point"):
- section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
- [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
- resolution) for i in section_names}
+ section_dict = {
+ i: (
+ [
+ gdf[gdf[section_column] == i].X.iloc[0],
+ gdf[gdf[section_column] == i].Y.iloc[0],
+ ],
+ [
+ gdf[gdf[section_column] == i].X.iloc[1],
+ gdf[gdf[section_column] == i].Y.iloc[1],
+ ],
+ resolution,
+ )
+ for i in section_names
+ }
# Create section dicts for Line Shape Files
else:
- section_dict = {i: ([gdf[gdf[section_column] == i].X.iloc[0], gdf[gdf[section_column] == i].Y.iloc[0]],
- [gdf[gdf[section_column] == i].X.iloc[1], gdf[gdf[section_column] == i].Y.iloc[1]],
- resolution) for i in section_names}
+ section_dict = {
+ i: (
+ [
+ gdf[gdf[section_column] == i].X.iloc[0],
+ gdf[gdf[section_column] == i].Y.iloc[0],
+ ],
+ [
+ gdf[gdf[section_column] == i].X.iloc[1],
+ gdf[gdf[section_column] == i].Y.iloc[1],
+ ],
+ resolution,
+ )
+ for i in section_names
+ }
return section_dict
-def convert_to_gempy_df(gdf: gpd.geodataframe.GeoDataFrame,
- dem: Union[rasterio.io.DatasetReader, np.ndarray] = None,
- extent: List[Union[float, int]] = None) -> pd.DataFrame:
+def convert_to_gempy_df(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ dem: Union[rasterio.io.DatasetReader, np.ndarray] = None,
+ extent: List[Union[float, int]] = None,
+) -> pd.DataFrame:
"""Converting a GeoDataFrame into a Pandas DataFrame ready to be read in for GemPy
Parameters
@@ -190,80 +216,81 @@ def convert_to_gempy_df(gdf: gpd.geodataframe.GeoDataFrame,
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking that the dem is a np.ndarray
if not isinstance(dem, (np.ndarray, rasterio.io.DatasetReader, type(None))):
- raise TypeError('DEM must be a numpy.ndarray or rasterio object')
+ raise TypeError("DEM must be a numpy.ndarray or rasterio object")
# Checking if extent is a list
if not isinstance(extent, (list, type(None))):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Extracting Coordinates from gdf
- if not {'X', 'Y', 'Z'}.issubset(gdf.columns):
+ if not {"X", "Y", "Z"}.issubset(gdf.columns):
# Extracting coordinates from array
if isinstance(dem, np.ndarray):
if not isinstance(extent, type(None)):
- gdf = vector.extract_xyz(gdf=gdf,
- dem=dem,
- extent=extent)
+ gdf = vector.extract_xyz(gdf=gdf, dem=dem, extent=extent)
else:
- raise FileNotFoundError('Extent not provided')
+ raise FileNotFoundError("Extent not provided")
# Extracting coordinates from raster
elif isinstance(dem, rasterio.io.DatasetReader):
- gdf = vector.extract_xyz(gdf=gdf,
- dem=dem)
+ gdf = vector.extract_xyz(gdf=gdf, dem=dem)
else:
- raise FileNotFoundError('DEM not provided')
+ raise FileNotFoundError("DEM not provided")
# Checking if the formation column is in the gdf and setting type
- if 'formation' not in gdf:
- raise ValueError('Formation names not defined')
+ if "formation" not in gdf:
+ raise ValueError("Formation names not defined")
else:
- gdf['formation'] = gdf['formation'].astype(str)
+ gdf["formation"] = gdf["formation"].astype(str)
# Checking if the dip column is in the gdf and setting type
- if 'dip' in gdf:
- gdf['dip'] = gdf['dip'].astype(float)
+ if "dip" in gdf:
+ gdf["dip"] = gdf["dip"].astype(float)
# Checking if the azimuth column is in the gdf and setting type
- if 'azimuth' in gdf:
- gdf['azimuth'] = gdf['azimuth'].astype(float)
+ if "azimuth" in gdf:
+ gdf["azimuth"] = gdf["azimuth"].astype(float)
# Checking if DataFrame is an orientation or interfaces df
- if 'dip' in gdf:
+ if "dip" in gdf:
- if (gdf['dip'] > 90).any():
- raise ValueError('dip values exceed 90 degrees')
- if 'azimuth' not in gdf:
- raise ValueError('azimuth values not defined')
- if (gdf['azimuth'] > 360).any():
- raise ValueError('azimuth values exceed 360 degrees')
+ if (gdf["dip"] > 90).any():
+ raise ValueError("dip values exceed 90 degrees")
+ if "azimuth" not in gdf:
+ raise ValueError("azimuth values not defined")
+ if (gdf["azimuth"] > 360).any():
+ raise ValueError("azimuth values exceed 360 degrees")
# Create orientations dataframe
- if 'polarity' not in gdf:
- df = pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation', 'dip', 'azimuth']])
- df['polarity'] = 1
+ if "polarity" not in gdf:
+ df = pd.DataFrame(gdf[["X", "Y", "Z", "formation", "dip", "azimuth"]])
+ df["polarity"] = 1
return df
else:
- df = pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation', 'dip', 'azimuth', 'polarity']])
+ df = pd.DataFrame(
+ gdf[["X", "Y", "Z", "formation", "dip", "azimuth", "polarity"]]
+ )
return df
else:
# Create interfaces dataframe
- df = pd.DataFrame(gdf[['X', 'Y', 'Z', 'formation']])
+ df = pd.DataFrame(gdf[["X", "Y", "Z", "formation"]])
return df
-def set_extent(minx: Union[int, float] = 0,
- maxx: Union[int, float] = 0,
- miny: Union[int, float] = 0,
- maxy: Union[int, float] = 0,
- minz: Union[int, float] = 0,
- maxz: Union[int, float] = 0,
- gdf: gpd.geodataframe.GeoDataFrame = None) -> List[Union[int, float]]:
+def set_extent(
+ minx: Union[int, float] = 0,
+ maxx: Union[int, float] = 0,
+ miny: Union[int, float] = 0,
+ maxy: Union[int, float] = 0,
+ minz: Union[int, float] = 0,
+ maxz: Union[int, float] = 0,
+ gdf: gpd.geodataframe.GeoDataFrame = None,
+) -> List[Union[int, float]]:
"""Setting the extent for a model
Parameters
@@ -311,11 +338,13 @@ def set_extent(minx: Union[int, float] = 0,
# Checking that the GeoDataFrame is a gdf or of type None
if not isinstance(gdf, (type(None), gpd.geodataframe.GeoDataFrame)):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if bounds are of type int or float
- if not all(isinstance(i, (int, float)) for i in [minx, maxx, miny, maxy, minz, maxz]):
- raise TypeError('bounds must be of type int or float')
+ if not all(
+ isinstance(i, (int, float)) for i in [minx, maxx, miny, maxy, minz, maxz]
+ ):
+ raise TypeError("bounds must be of type int or float")
# Checking if the gdf is of type None
if isinstance(gdf, type(None)):
@@ -334,15 +363,17 @@ def set_extent(minx: Union[int, float] = 0,
# Create extent from gdf of geom_type point or linestring
else:
bounds = gdf.bounds
- extent = [round(bounds.minx.min(), 2), round(bounds.maxx.max(), 2), round(bounds.miny.min(), 2),
- round(bounds.maxy.max(), 2)]
+ extent = [
+ round(bounds.minx.min(), 2),
+ round(bounds.maxx.max(), 2),
+ round(bounds.miny.min(), 2),
+ round(bounds.maxy.max(), 2),
+ ]
return extent
-def set_resolution(x: int,
- y: int,
- z: int) -> List[int]:
+def set_resolution(x: int, y: int, z: int) -> List[int]:
"""Setting the resolution for a model
Parameters
@@ -378,15 +409,15 @@ def set_resolution(x: int,
# Checking if x is of type int
if not isinstance(x, int):
- raise TypeError('X must be of type int')
+ raise TypeError("X must be of type int")
# Checking if y is of type int
if not isinstance(y, int):
- raise TypeError('Y must be of type int')
+ raise TypeError("Y must be of type int")
# Checking if y is of type int
if not isinstance(z, int):
- raise TypeError('Z must be of type int')
+ raise TypeError("Z must be of type int")
# Create list of resolution values
resolution = [x, y, z]
@@ -394,12 +425,14 @@ def set_resolution(x: int,
return resolution
-def read_csv_as_gdf(path: str,
- crs: Union[str, pyproj.crs.crs.CRS],
- x: str = 'X',
- y: str = 'Y',
- z: str = None,
- delimiter: str = ',') -> gpd.geodataframe.GeoDataFrame:
+def read_csv_as_gdf(
+ path: str,
+ crs: Union[str, pyproj.crs.crs.CRS],
+ x: str = "X",
+ y: str = "Y",
+ z: str = None,
+ delimiter: str = ",",
+) -> gpd.geodataframe.GeoDataFrame:
"""Reading CSV files as GeoDataFrame
Parameters
@@ -449,7 +482,7 @@ def read_csv_as_gdf(path: str,
# Checking that the path is of type string
if not isinstance(path, str):
- raise TypeError('Path must be provided as string')
+ raise TypeError("Path must be provided as string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -460,45 +493,43 @@ def read_csv_as_gdf(path: str,
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Checking that the x column is of type string
if not isinstance(x, str):
- raise TypeError('X column name must be provided as string')
+ raise TypeError("X column name must be provided as string")
# Checking that the y column is of type string
if not isinstance(y, str):
- raise TypeError('Y column name must be provided as string')
+ raise TypeError("Y column name must be provided as string")
# Checking that the z column is of type string
if not isinstance(z, (str, type(None))):
- raise TypeError('Z column name must be provided as string')
+ raise TypeError("Z column name must be provided as string")
# Checking that the crs is provided as string
if not isinstance(crs, (str, pyproj.crs.crs.CRS)):
- raise TypeError('CRS must be provided as string or pyproj CRS object')
+ raise TypeError("CRS must be provided as string or pyproj CRS object")
# Checking that the delimiter is of type string
if not isinstance(delimiter, str):
- raise TypeError('Delimiter must be of type string')
+ raise TypeError("Delimiter must be of type string")
# Loading the csv file
- df = pd.read_csv(filepath_or_buffer=path,
- sep=delimiter)
+ df = pd.read_csv(filepath_or_buffer=path, sep=delimiter)
# Checking that the file loaded is a DataFrame
if not isinstance(df, pd.DataFrame):
- raise TypeError('df must be of type DataFrame')
+ raise TypeError("df must be of type DataFrame")
# Create GeoDataFrame
if (x in df) and (y in df):
- gdf = gpd.GeoDataFrame(data=df,
- geometry=gpd.points_from_xy(x=df[x],
- y=df[y],
- crs=crs))
+ gdf = gpd.GeoDataFrame(
+ data=df, geometry=gpd.points_from_xy(x=df[x], y=df[y], crs=crs)
+ )
else:
- raise ValueError('X and/or Y columns could not be found')
+ raise ValueError("X and/or Y columns could not be found")
return gdf
@@ -541,11 +572,11 @@ def show_number_of_data_points(geo_model):
"""
# Trying to import gempy but returning error if gempy is not installed
- try:
- import gempy as gp
- except ModuleNotFoundError:
- raise ModuleNotFoundError(
- 'GemPy package is not installed. Use pip install gempy to install the latest version')
+ # try:
+ # import gempy as gp
+ # except ModuleNotFoundError:
+ # raise ModuleNotFoundError(
+ # 'GemPy package is not installed. Use pip install gempy to install the latest version')
# Create empty lists to store values
no_int = []
@@ -553,26 +584,32 @@ def show_number_of_data_points(geo_model):
# Store values of number of interfaces and orientations in list
for i in geo_model.surfaces.df.surface.unique():
- length = len(geo_model.surface_points.df[geo_model.surface_points.df['surface'] == i])
+ length = len(
+ geo_model.surface_points.df[geo_model.surface_points.df["surface"] == i]
+ )
no_int.append(length)
- length = len(geo_model.orientations.df[geo_model.orientations.df['surface'] == i])
+ length = len(
+ geo_model.orientations.df[geo_model.orientations.df["surface"] == i]
+ )
no_ori.append(length)
# Copying GeoDataFrame
gdf = geo_model.surfaces.df.copy(deep=True)
# Add columns to geo_model surface table
- gdf['No. of Interfaces'] = no_int
- gdf['No. of Orientations'] = no_ori
+ gdf["No. of Interfaces"] = no_int
+ gdf["No. of Orientations"] = no_ori
return gdf
-def getfeatures(extent: Union[List[Union[int, float]], type(None)],
- crs_raster: Union[str, dict],
- crs_bbox: Union[str, dict],
- bbox: shapely.geometry.polygon.Polygon = None) -> list:
+def getfeatures(
+ extent: Union[List[Union[int, float]], type(None)],
+ crs_raster: Union[str, dict],
+ crs_bbox: Union[str, dict],
+ bbox: shapely.geometry.polygon.Polygon = None,
+) -> list:
"""Creating a list containing a dict with keys and values to clip a raster
Parameters
@@ -603,23 +640,23 @@ def getfeatures(extent: Union[List[Union[int, float]], type(None)],
# Checking if extent is of type list
if not isinstance(extent, (list, type(None))):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking if bounds are of type int or float
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Bounds must be of type int or float')
+ raise TypeError("Bounds must be of type int or float")
# Checking if the raster crs is of type string or dict
if not isinstance(crs_raster, (str, dict, rasterio.crs.CRS)):
- raise TypeError('Raster CRS must be of type dict or string')
+ raise TypeError("Raster CRS must be of type dict or string")
# Checking if the bbox crs is of type string or dict
if not isinstance(crs_bbox, (str, dict, rasterio.crs.CRS)):
- raise TypeError('Bbox CRS must be of type dict or string')
+ raise TypeError("Bbox CRS must be of type dict or string")
# Checking if the bbox is of type none or a shapely polygon
if not isinstance(bbox, (shapely.geometry.polygon.Polygon, type(None))):
- raise TypeError('Bbox must be a shapely polygon')
+ raise TypeError("Bbox must be a shapely polygon")
# Create bbox if bbox is not provided
if isinstance(bbox, type(None)):
@@ -628,7 +665,7 @@ def getfeatures(extent: Union[List[Union[int, float]], type(None)],
# Checking if the bbox is a shapely box
if not isinstance(bbox, shapely.geometry.polygon.Polygon):
- raise TypeError('Bbox is not of type shapely box')
+ raise TypeError("Bbox is not of type shapely box")
# Converting to dict
if isinstance(crs_raster, rasterio.crs.CRS):
@@ -639,17 +676,17 @@ def getfeatures(extent: Union[List[Union[int, float]], type(None)],
# Converting raster crs to dict
if isinstance(crs_raster, str):
- crs_raster = {'init': crs_raster}
+ crs_raster = {"init": crs_raster}
# Converting bbox raster to dict
if isinstance(crs_bbox, str):
- crs_bbox = {'init': crs_bbox}
+ crs_bbox = {"init": crs_bbox}
# Creating GeoDataFrame
- gdf = gpd.GeoDataFrame({'geometry': bbox}, index=[0], crs=crs_bbox)
+ gdf = gpd.GeoDataFrame({"geometry": bbox}, index=[0], crs=crs_bbox)
gdf = gdf.to_crs(crs=crs_raster)
- data = [json.loads(gdf.to_json())['features'][0]['geometry']]
+ data = [json.loads(gdf.to_json())["features"][0]["geometry"]]
return data
@@ -657,6 +694,7 @@ def getfeatures(extent: Union[List[Union[int, float]], type(None)],
# Parsing QGIS Style Files
########################
+
def parse_categorized_qml(qml_name: str) -> tuple:
"""Parsing a QGIS style file to retrieve surface color values
@@ -714,11 +752,12 @@ def parse_categorized_qml(qml_name: str) -> tuple:
import xmltodict
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'xmltodict package is not installed. Use pip install xmltodict to install the latest version')
+ "xmltodict package is not installed. Use pip install xmltodict to install the latest version"
+ )
# Checking if the path was provided as string
if not isinstance(qml_name, str):
- raise TypeError('Path must be of type string')
+ raise TypeError("Path must be of type string")
# Getting the absolute path
path = os.path.abspath(path=qml_name)
@@ -729,7 +768,7 @@ def parse_categorized_qml(qml_name: str) -> tuple:
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Opening the file
with open(qml_name, "rb") as f:
@@ -740,15 +779,13 @@ def parse_categorized_qml(qml_name: str) -> tuple:
# Extracting symbols
symbols = {
- symbol["@name"]: {
- prop["@k"]: prop["@v"] for prop in symbol["layer"]["prop"]
- }
+ symbol["@name"]: {prop["@k"]: prop["@v"] for prop in symbol["layer"]["prop"]}
for symbol in qml["qgis"]["renderer-v2"]["symbols"]["symbol"]
}
# Extracting styles
classes = {
- category['@value']: symbols[category['@symbol']]
+ category["@value"]: symbols[category["@symbol"]]
for category in qml["qgis"]["renderer-v2"]["categories"]["category"]
}
@@ -816,7 +853,7 @@ def build_style_dict(classes: dict) -> dict:
# Checking if classes is of type dict
if not isinstance(classes, dict):
- raise TypeError('Classes must be of type dict')
+ raise TypeError("Classes must be of type dict")
# Create empty styles dict
styles_dict = {}
@@ -832,14 +869,13 @@ def build_style_dict(classes: dict) -> dict:
"opacity": opacity / 255,
"weight": float(style["outline_width"]),
"fillColor": f"#{fillColor[0]:02x}{fillColor[1]:02x}{fillColor[2]:02x}",
- "fillOpacity": fill_opacity / 255
+ "fillOpacity": fill_opacity / 255,
}
return styles_dict
-def load_surface_colors(path: str,
- gdf: gpd.geodataframe.GeoDataFrame) -> List[str]:
+def load_surface_colors(path: str, gdf: gpd.geodataframe.GeoDataFrame) -> List[str]:
"""Loading surface colors from a QML file and storing the color values as list to be displayed with GeoPandas plots
Parameters
@@ -883,7 +919,7 @@ def load_surface_colors(path: str,
# Checking that the path is of type str
if not isinstance(path, str):
- raise TypeError('path must be provided as string')
+ raise TypeError("path must be provided as string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -894,11 +930,11 @@ def load_surface_colors(path: str,
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Checking that the gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('object must be of type GeoDataFrame')
+ raise TypeError("object must be of type GeoDataFrame")
# Parse qml
column, classes = parse_categorized_qml(qml_name=path)
@@ -919,7 +955,7 @@ def load_surface_colors(path: str,
gdf_copy = gdf_copy.groupby([column], as_index=False).last()
# Create list of remaining colors
- cols = gdf_copy['Color'].to_list()
+ cols = gdf_copy["Color"].to_list()
return cols
@@ -961,7 +997,7 @@ def create_surface_color_dict(path: str) -> dict:
# Checking that the path is of type str
if not isinstance(path, str):
- raise TypeError('path must be provided as string')
+ raise TypeError("path must be provided as string")
# Getting the absolute path
path = os.path.abspath(path=path)
@@ -972,7 +1008,7 @@ def create_surface_color_dict(path: str) -> dict:
# Checking that the file exists
if not os.path.exists(path):
- raise FileNotFoundError('File not found')
+ raise FileNotFoundError("File not found")
# Parse qml
columns, classes = parse_categorized_qml(qml_name=path)
@@ -1030,11 +1066,12 @@ def get_location_coordinate(name: str):
import geopy
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'GeoPy package is not installed. Use pip install geopy to install the latest version')
+ "GeoPy package is not installed. Use pip install geopy to install the latest version"
+ )
# Checking that the location name is of type string
if not isinstance(name, str):
- raise TypeError('Location name must be of type string')
+ raise TypeError("Location name must be of type string")
# Create geocoder for OpenStreetMap data
geolocator = geopy.geocoders.Nominatim(user_agent=name)
@@ -1045,8 +1082,9 @@ def get_location_coordinate(name: str):
return coordinates
-def transform_location_coordinate(coordinates,
- crs: Union[str, pyproj.crs.crs.CRS]) -> dict:
+def transform_location_coordinate(
+ coordinates, crs: Union[str, pyproj.crs.crs.CRS]
+) -> dict:
"""Transforming coordinates of GeoPy Location
Parameters
@@ -1097,18 +1135,19 @@ def transform_location_coordinate(coordinates,
import geopy
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'GeoPy package is not installed. Use pip install geopy to install the latest version')
+ "GeoPy package is not installed. Use pip install geopy to install the latest version"
+ )
# Checking that coordinates object is a GeoPy location object
if not isinstance(coordinates, geopy.location.Location):
- raise TypeError('The location must be provided as GeoPy Location object')
+ raise TypeError("The location must be provided as GeoPy Location object")
# Checking that the target crs is provided as string
if not isinstance(crs, str):
- raise TypeError('Target CRS must be of type string')
+ raise TypeError("Target CRS must be of type string")
# Setting source and target projection
- transformer = pyproj.Transformer.from_crs('EPSG:4326', crs)
+ transformer = pyproj.Transformer.from_crs("EPSG:4326", crs)
# Transforming coordinate systems
long, lat = transformer.transform(coordinates.latitude, coordinates.longitude)
@@ -1164,21 +1203,27 @@ def create_polygon_from_location(coordinates) -> shapely.geometry.polygon.Polygo
import geopy
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'GeoPy package is not installed. Use pip install geopy to install the latest version')
+ "GeoPy package is not installed. Use pip install geopy to install the latest version"
+ )
# Checking that coordinates object is a GeoPy location object
if not isinstance(coordinates, geopy.location.Location):
- raise TypeError('The location must be provided as GeoPy Location object')
+ raise TypeError("The location must be provided as GeoPy Location object")
# Create polygon from boundingbox
- polygon = box(float(coordinates.raw['boundingbox'][0]), float(coordinates.raw['boundingbox'][2]),
- float(coordinates.raw['boundingbox'][1]), float(coordinates.raw['boundingbox'][3]))
+ polygon = box(
+ float(coordinates.raw["boundingbox"][0]),
+ float(coordinates.raw["boundingbox"][2]),
+ float(coordinates.raw["boundingbox"][1]),
+ float(coordinates.raw["boundingbox"][3]),
+ )
return polygon
-def get_locations(names: Union[list, str],
- crs: Union[str, pyproj.crs.crs.CRS] = 'EPSG:4326') -> dict:
+def get_locations(
+ names: Union[list, str], crs: Union[str, pyproj.crs.crs.CRS] = "EPSG:4326"
+) -> dict:
"""Obtaining coordinates for one city or a list of given cities. A CRS other than 'EPSG:4326' can be passed to
transform the coordinates
@@ -1224,35 +1269,43 @@ def get_locations(names: Union[list, str],
# Checking that the location names are provided as list of strings or as string for one location
if not isinstance(names, (list, str)):
- raise TypeError('Names must be provided as list of strings')
+ raise TypeError("Names must be provided as list of strings")
# Checking that the target CRS is provided as string
if not isinstance(crs, str):
- raise TypeError('Target CRS must be of type string')
+ raise TypeError("Target CRS must be of type string")
if isinstance(names, list):
# Create list of GeoPy locations
coordinates_list = [get_location_coordinate(name=i) for i in names]
# Transform CRS and create result_dict
- if crs != 'EPSG:4326':
- dict_list = [transform_location_coordinate(coordinates=i,
- crs=crs) for i in coordinates_list]
+ if crs != "EPSG:4326":
+ dict_list = [
+ transform_location_coordinate(coordinates=i, crs=crs)
+ for i in coordinates_list
+ ]
result_dict = {k: v for d in dict_list for k, v in d.items()}
else:
- result_dict = {coordinates_list[i].address: (coordinates_list[i].longitude,
- coordinates_list[i].latitude)
- for i in range(len(coordinates_list))}
+ result_dict = {
+ coordinates_list[i].address: (
+ coordinates_list[i].longitude,
+ coordinates_list[i].latitude,
+ )
+ for i in range(len(coordinates_list))
+ }
else:
# Create GeoPy Object
coordinates = get_location_coordinate(name=names)
- if crs != 'EPSG:4326':
- result_dict = transform_location_coordinate(coordinates=coordinates,
- crs=crs)
+ if crs != "EPSG:4326":
+ result_dict = transform_location_coordinate(
+ coordinates=coordinates, crs=crs
+ )
else:
- result_dict = {coordinates.address: (coordinates.longitude,
- coordinates.latitude)}
+ result_dict = {
+ coordinates.address: (coordinates.longitude, coordinates.latitude)
+ }
return result_dict
@@ -1299,21 +1352,21 @@ def convert_location_dict_to_gdf(location_dict: dict) -> gpd.geodataframe.GeoDat
# Checking that the input data is of type dict
if not isinstance(location_dict, dict):
- raise TypeError('Input data must be provided as dict')
+ raise TypeError("Input data must be provided as dict")
# Creating GeoDataFrame
gdf = gpd.GeoDataFrame(data=location_dict).T.reset_index()
# Assigning column names
- gdf.columns = ['City', 'X', 'Y']
+ gdf.columns = ["City", "X", "Y"]
# Split city names to only show the name of the city
- gdf['City'] = [i.split(',')[0] for i in gdf['City'].to_list()]
+ gdf["City"] = [i.split(",")[0] for i in gdf["City"].to_list()]
# Recreate GeoDataFrame and set coordinates as geometry objects
- gdf = gpd.GeoDataFrame(data=gdf,
- geometry=gpd.points_from_xy(x=gdf['X'],
- y=gdf['Y']))
+ gdf = gpd.GeoDataFrame(
+ data=gdf, geometry=gpd.points_from_xy(x=gdf["X"], y=gdf["Y"])
+ )
return gdf
@@ -1322,8 +1375,7 @@ def convert_location_dict_to_gdf(location_dict: dict) -> gpd.geodataframe.GeoDat
############################
-def assign_properties(lith_block: np.ndarray,
- property_dict: dict) -> np.ndarray:
+def assign_properties(lith_block: np.ndarray, property_dict: dict) -> np.ndarray:
"""Replacing lith block IDs with physical properties
Parameters
@@ -1366,11 +1418,11 @@ def assign_properties(lith_block: np.ndarray,
# Checking that the lith block is a NumPy array
if not isinstance(lith_block, np.ndarray):
- raise TypeError('Lith block must be a NumPy Array')
+ raise TypeError("Lith block must be a NumPy Array")
# Checking that the properties dict is a dict
if not isinstance(property_dict, dict):
- raise TypeError('Properties must be provided as dict')
+ raise TypeError("Properties must be provided as dict")
# Store shape
shape = lith_block.shape
@@ -1449,26 +1501,27 @@ def get_nearest_neighbor(x: np.ndarray, y: np.ndarray) -> np.int64:
from sklearn.neighbors import NearestNeighbors
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'Scikit Learn package is not installed. Use pip install scikit-learn to install the latest version')
+ "Scikit Learn package is not installed. Use pip install scikit-learn to install the latest version"
+ )
# Checking that the point data set x is of type np.ndarray
if not isinstance(x, np.ndarray):
- raise TypeError('Point data set must be of type np.ndarray')
+ raise TypeError("Point data set must be of type np.ndarray")
# Checking that the shape of the array is correct
if x.shape[1] != 2:
- raise ValueError('Only coordinate pairs are allowed')
+ raise ValueError("Only coordinate pairs are allowed")
# Checking that point y is of type np.ndarray
if not isinstance(y, np.ndarray):
- raise TypeError('Point data set must be of type np.ndarray')
+ raise TypeError("Point data set must be of type np.ndarray")
# Checking that the shape of the array is correct
if y.shape != (2,):
- raise ValueError('y point must be of shape (2,)')
+ raise ValueError("y point must be of shape (2,)")
# Finding the nearest neighbor with ball_tree algorithm
- nbrs = NearestNeighbors(n_neighbors=1, algorithm='ball_tree').fit(y.reshape(1, -1))
+ nbrs = NearestNeighbors(n_neighbors=1, algorithm="ball_tree").fit(y.reshape(1, -1))
# Calculating the distances and indices for to find the nearest neighbor
distances, indices = nbrs.kneighbors(x)
@@ -1479,9 +1532,11 @@ def get_nearest_neighbor(x: np.ndarray, y: np.ndarray) -> np.int64:
return index
-def calculate_number_of_isopoints(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
- increment: Union[float, int],
- zcol: str = 'Z') -> int:
+def calculate_number_of_isopoints(
+ gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
+ increment: Union[float, int],
+ zcol: str = "Z",
+) -> int:
"""Creating the number of isopoints to further interpolate strike lines
Parameters
@@ -1531,19 +1586,21 @@ def calculate_number_of_isopoints(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.D
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, (gpd.geodataframe.GeoDataFrame, pd.DataFrame)):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if the increment is of type float or int
if not isinstance(increment, (float, int)):
- raise TypeError('The increment must be provided as float or int')
+ raise TypeError("The increment must be provided as float or int")
# Checking that the name of the Z column is provided as string
if not isinstance(zcol, str):
- raise TypeError('Z column name must be provided as string')
+ raise TypeError("Z column name must be provided as string")
# Checking that the Z column is in the GeoDataFrame
if zcol not in gdf:
- raise ValueError('Provide name of Z column as kwarg as Z column could not be recognized')
+ raise ValueError(
+ "Provide name of Z column as kwarg as Z column could not be recognized"
+ )
# Creating a list with the unique heights of the GeoDataFrame
heights = gdf[zcol].sort_values().unique().tolist()
@@ -1554,11 +1611,13 @@ def calculate_number_of_isopoints(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.D
return number
-def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
- increment: Union[float, int],
- xcol: str = 'X',
- ycol: str = 'Y',
- zcol: str = 'Z') -> gpd.geodataframe.GeoDataFrame:
+def calculate_lines(
+ gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
+ increment: Union[float, int],
+ xcol: str = "X",
+ ycol: str = "Y",
+ zcol: str = "Z",
+) -> gpd.geodataframe.GeoDataFrame:
"""Function to interpolate strike lines
Parameters
@@ -1606,27 +1665,27 @@ def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, (gpd.geodataframe.GeoDataFrame, pd.DataFrame)):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking that all geometries are valid
if not all(gdf.geometry.is_valid):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking if the increment is of type float or int
if not isinstance(increment, (float, int)):
- raise TypeError('The increment must be provided as float or int')
+ raise TypeError("The increment must be provided as float or int")
# Checking that xcol is of type string
if not isinstance(xcol, str):
- raise TypeError('X column name must be of type string')
+ raise TypeError("X column name must be of type string")
# Checking that ycol is of type string
if not isinstance(ycol, str):
- raise TypeError('Y column name must be of type string')
+ raise TypeError("Y column name must be of type string")
# Checking that zcol is of type string
if not isinstance(zcol, str):
- raise TypeError('Z column name must be of type string')
+ raise TypeError("Z column name must be of type string")
# Checking that the columns are in the GeoDataFrame
# if not {xcol, ycol, zcol}.issubset(gdf.columns):
@@ -1649,21 +1708,27 @@ def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
# Calculating vertices of lines
for i in range(len(gdf[gdf[zcol] == minval])):
# Getting index for nearest neighbor
- index = get_nearest_neighbor(np.array(gdf[gdf[zcol] == minval][[xcol, ycol]].values.tolist()),
- np.array([gdf[gdf[zcol] == minval][xcol].values.tolist()[i],
- gdf[gdf[zcol] == minval][ycol].values.tolist()[i]]))
+ index = get_nearest_neighbor(
+ np.array(gdf[gdf[zcol] == minval][[xcol, ycol]].values.tolist()),
+ np.array(
+ [
+ gdf[gdf[zcol] == minval][xcol].values.tolist()[i],
+ gdf[gdf[zcol] == minval][ycol].values.tolist()[i],
+ ]
+ ),
+ )
# Creating x and y points from existing gdf
- x1 = gdf[gdf['Z'] == minval][xcol].tolist()[i]
- y1 = gdf[gdf['Z'] == minval][ycol].tolist()[i]
- x2 = gdf[gdf['Z'] == maxval][xcol].tolist()[index]
- y2 = gdf[gdf['Z'] == maxval][ycol].tolist()[index]
+ x1 = gdf[gdf["Z"] == minval][xcol].tolist()[i]
+ y1 = gdf[gdf["Z"] == minval][ycol].tolist()[i]
+ x2 = gdf[gdf["Z"] == maxval][xcol].tolist()[index]
+ y2 = gdf[gdf["Z"] == maxval][ycol].tolist()[index]
# Calculating vertices of lines
for j in range(num):
# Calculating vertices
- pointx = ((j + 1) / (num + 1) * x2 + (1 - (j + 1) / (num + 1)) * x1)
- pointy = ((j + 1) / (num + 1) * y2 + (1 - (j + 1) / (num + 1)) * y1)
+ pointx = (j + 1) / (num + 1) * x2 + (1 - (j + 1) / (num + 1)) * x1
+ pointy = (j + 1) / (num + 1) * y2 + (1 - (j + 1) / (num + 1)) * y1
# Append vertices to list
pointsx.append(pointx)
@@ -1676,8 +1741,9 @@ def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
# Create linestring from point lists
for i in range(0, int(len(pointsx) / 2)):
# Creating linestrings
- ls = LineString([Point(pointsx[i], pointsy[i]),
- Point(pointsx[i + num], pointsy[i + num])])
+ ls = LineString(
+ [Point(pointsx[i], pointsy[i]), Point(pointsx[i + num], pointsy[i + num])]
+ )
# Appending line strings
ls_list.append(ls)
heights.append(minval + i * increment + increment)
@@ -1687,25 +1753,27 @@ def calculate_lines(gdf: Union[gpd.geodataframe.GeoDataFrame, pd.DataFrame],
lines = gpd.GeoDataFrame(gpd.GeoSeries(ls_list), crs=gdf.crs)
# Setting geometry column of GeoDataFrame
- lines['geometry'] = ls_list
+ lines["geometry"] = ls_list
# Extracting X and Y coordinate and deleting first entry
lines = vector.extract_xy(lines)
del lines[0]
# Adding formation and height information to GeoDataFrame
- lines['formation'] = gdf['formation'].unique().tolist()[0]
- lines['Z'] = heights
- lines['id'] = heights
+ lines["formation"] = gdf["formation"].unique().tolist()[0]
+ lines["Z"] = heights
+ lines["id"] = heights
return lines
-def interpolate_strike_lines(gdf: gpd.geodataframe.GeoDataFrame,
- increment: Union[float, int],
- xcol: str = 'X',
- ycol: str = 'Y',
- zcol: str = 'Z') -> gpd.geodataframe.GeoDataFrame:
+def interpolate_strike_lines(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ increment: Union[float, int],
+ xcol: str = "X",
+ ycol: str = "Y",
+ zcol: str = "Z",
+) -> gpd.geodataframe.GeoDataFrame:
"""Interpolating strike lines to calculate orientations
Parameters
@@ -1738,70 +1806,88 @@ def interpolate_strike_lines(gdf: gpd.geodataframe.GeoDataFrame,
# Checking if gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if the increment is of type float or int
if not isinstance(increment, (float, int)):
- raise TypeError('The increment must be provided as float or int')
+ raise TypeError("The increment must be provided as float or int")
# Checking that xcol is of type string
if not isinstance(xcol, str):
- raise TypeError('X column name must be of type string')
+ raise TypeError("X column name must be of type string")
# Checking that ycol is of type string
if not isinstance(ycol, str):
- raise TypeError('Y column name must be of type string')
+ raise TypeError("Y column name must be of type string")
# Checking that zcol is of type string
if not isinstance(zcol, str):
- raise TypeError('Z column name must be of type string')
+ raise TypeError("Z column name must be of type string")
# Create empty GeoDataFrame
gdf_out = gpd.GeoDataFrame()
# Extract vertices from gdf
- gdf = vector.extract_xy(gdf, drop_id=False, reset_index=False).sort_values(by='id')
+ gdf = vector.extract_xy(gdf, drop_id=False, reset_index=False).sort_values(by="id")
# Interpolate strike lines
- for i in range(len(gdf['id'].unique().tolist()) - 1):
+ for i in range(len(gdf["id"].unique().tolist()) - 1):
# Calculate distance between two strike lines in the original gdf
- diff = gdf.loc[gdf.index.unique().values.tolist()[i]][zcol].values.tolist()[0] - \
- gdf.loc[gdf.index.unique().values.tolist()[i + 1]][zcol].values.tolist()[0]
+ diff = (
+ gdf.loc[gdf.index.unique().values.tolist()[i]][zcol].values.tolist()[0]
+ - gdf.loc[gdf.index.unique().values.tolist()[i + 1]][zcol].values.tolist()[
+ 0
+ ]
+ )
# If the distance is larger than the increment, interpolate strike lines
if np.abs(diff) > increment:
gdf_strike = pd.concat(
- [gdf.loc[gdf.index.unique().values.tolist()[i]], gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])
+ [
+ gdf.loc[gdf.index.unique().values.tolist()[i]],
+ gdf.loc[gdf.index.unique().values.tolist()[i + 1]],
+ ]
+ )
# Calculate strike lines
lines = calculate_lines(gdf_strike, increment)
# Append interpolated lines to gdf that will be returned
gdf_new = pd.concat(
- [gdf.loc[gdf.index.unique().values.tolist()[i]], lines,
- gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])
+ [
+ gdf.loc[gdf.index.unique().values.tolist()[i]],
+ lines,
+ gdf.loc[gdf.index.unique().values.tolist()[i + 1]],
+ ]
+ )
gdf_out = gdf_out.append(gdf_new, ignore_index=True)
# If the distance is equal to the increment, append line to the gdf that will be returned
else:
gdf_new = pd.concat(
- [gdf.loc[gdf.index.unique().values.tolist()[i]], gdf.loc[gdf.index.unique().values.tolist()[i + 1]]])
+ [
+ gdf.loc[gdf.index.unique().values.tolist()[i]],
+ gdf.loc[gdf.index.unique().values.tolist()[i + 1]],
+ ]
+ )
gdf_out = gdf_out.append(gdf_new, ignore_index=True)
# Drop duplicates
- gdf_out = gdf_out.sort_values(by=['Y']).drop_duplicates('geometry')
+ gdf_out = gdf_out.sort_values(by=["Y"]).drop_duplicates("geometry")
# Redefine ID column with interpolated strike lines
- gdf_out['id'] = np.arange(1, len(gdf_out['id'].values.tolist()) + 1).tolist()
+ gdf_out["id"] = np.arange(1, len(gdf_out["id"].values.tolist()) + 1).tolist()
return gdf_out
-def convert_to_petrel_points_with_attributes(mesh: pv.core.pointset.PolyData,
- path: str,
- crs: Union[str, pyproj.crs.crs.CRS, type(None)] = None,
- target_crs: Union[str, pyproj.crs.crs.CRS, type(None)] = None):
+def convert_to_petrel_points_with_attributes(
+ mesh: pv.core.pointset.PolyData,
+ path: str,
+ crs: Union[str, pyproj.crs.crs.CRS, type(None)] = None,
+ target_crs: Union[str, pyproj.crs.crs.CRS, type(None)] = None,
+):
"""Function to convert vertices of a PyVista Mesh to Petrel Points with Attributes
Parameters
@@ -1826,22 +1912,26 @@ def convert_to_petrel_points_with_attributes(mesh: pv.core.pointset.PolyData,
# Checking that the mesh is a PyVista PolyData object
if not isinstance(mesh, pv.core.pointset.PolyData):
- raise TypeError('Mesh must be provided as PyVista PolyData object')
+ raise TypeError("Mesh must be provided as PyVista PolyData object")
# Checking that the CRS is provided as proper type
if not isinstance(crs, (str, pyproj.crs.crs.CRS, type(None))):
- raise TypeError('CRS must be provided as string or pyproj CRS object')
+ raise TypeError("CRS must be provided as string or pyproj CRS object")
# Checking that the target CRS is provided as proper type
if not isinstance(target_crs, (str, pyproj.crs.crs.CRS, type(None))):
- raise TypeError('CRS must be provided as string or pyproj CRS object')
+ raise TypeError("CRS must be provided as string or pyproj CRS object")
# Selecting vertices
vertices = np.array(mesh.points)
# Creating GeoDataFrame from vertices
- gdf = gpd.GeoDataFrame(geometry=gpd.points_from_xy(vertices[:, 0], vertices[:, 1]), data=vertices,
- columns=['X', 'Y', 'Z'], crs=crs)
+ gdf = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(vertices[:, 0], vertices[:, 1]),
+ data=vertices,
+ columns=["X", "Y", "Z"],
+ crs=crs,
+ )
# Reprojecting data and extracting X and Y coordinates
if target_crs and target_crs != crs:
@@ -1849,19 +1939,19 @@ def convert_to_petrel_points_with_attributes(mesh: pv.core.pointset.PolyData,
gdf = vector.extract_xy(gdf=gdf)
# Dropping Geometry Column
- df = gdf.drop('geometry', axis=1)
+ df = gdf.drop("geometry", axis=1)
- df.to_csv(fname=path,
- index=False,
- sep='\t')
+ df.to_csv(fname=path, index=False, sep="\t")
- print('CSV-File successfully saved')
+ print("CSV-File successfully saved")
-def ray_trace_one_surface(surface: Union[pv.core.pointset.PolyData, pv.core.pointset.UnstructuredGrid],
- origin: Union[np.ndarray, list],
- end_point: Union[np.ndarray, list],
- first_point: bool = False) -> tuple:
+def ray_trace_one_surface(
+ surface: Union[pv.core.pointset.PolyData, pv.core.pointset.UnstructuredGrid],
+ origin: Union[np.ndarray, list],
+ end_point: Union[np.ndarray, list],
+ first_point: bool = False,
+) -> tuple:
"""Function to return the depth of one surface in one well using PyVista ray tracing
Parameters
@@ -1890,25 +1980,29 @@ def ray_trace_one_surface(surface: Union[pv.core.pointset.PolyData, pv.core.poin
"""
# Checking that the provided surface is of type PoyData or UnstructuredGrid
- if not isinstance(surface, (pv.core.pointset.PolyData, pv.core.pointset.UnstructuredGrid)):
- raise TypeError('Surface must be provided as PolyData or UnstructuredGrid')
+ if not isinstance(
+ surface, (pv.core.pointset.PolyData, pv.core.pointset.UnstructuredGrid)
+ ):
+ raise TypeError("Surface must be provided as PolyData or UnstructuredGrid")
# Converting UnstructuredGrid to PolyData
if isinstance(surface, pv.core.pointset.UnstructuredGrid):
surface = surface.extract_surface()
# Extracting the intersection between a PolyData set and a mesh
- intersection_points, intersection_cells = surface.ray_trace(origin=origin,
- end_point=end_point,
- first_point=first_point)
+ intersection_points, intersection_cells = surface.ray_trace(
+ origin=origin, end_point=end_point, first_point=first_point
+ )
return intersection_points, intersection_cells
-def ray_trace_multiple_surfaces(surfaces: list,
- borehole_top: Union[np.ndarray, list],
- borehole_bottom: Union[np.ndarray, list],
- first_point: bool = False) -> list:
+def ray_trace_multiple_surfaces(
+ surfaces: list,
+ borehole_top: Union[np.ndarray, list],
+ borehole_bottom: Union[np.ndarray, list],
+ first_point: bool = False,
+) -> list:
"""Function to return the depth of multiple surfaces in one well using PyVista ray tracing
Parameters
@@ -1937,18 +2031,25 @@ def ray_trace_multiple_surfaces(surfaces: list,
"""
# Extracting multiple intersections from meshes
- intersections = [ray_trace_one_surface(surface=surface,
- origin=borehole_top,
- end_point=borehole_bottom,
- first_point=first_point) for surface in surfaces]
+ intersections = [
+ ray_trace_one_surface(
+ surface=surface,
+ origin=borehole_top,
+ end_point=borehole_bottom,
+ first_point=first_point,
+ )
+ for surface in surfaces
+ ]
return intersections
-def create_virtual_profile(names_surfaces: list,
- surfaces: list,
- borehole: pv.core.pointset.PolyData,
- first_point: bool = False) -> pd.DataFrame:
+def create_virtual_profile(
+ names_surfaces: list,
+ surfaces: list,
+ borehole: pv.core.pointset.PolyData,
+ first_point: bool = False,
+) -> pd.DataFrame:
"""Function to filter and sort the resulting well tops
Parameters
@@ -1977,13 +2078,21 @@ def create_virtual_profile(names_surfaces: list,
"""
# Creating well segments
- well_segments = [pv.Line(borehole.points[i], borehole.points[i + 1]) for i in range(len(borehole.points) - 1)]
+ well_segments = [
+ pv.Line(borehole.points[i], borehole.points[i + 1])
+ for i in range(len(borehole.points) - 1)
+ ]
# Extracting well tops
- well_tops = [ray_trace_multiple_surfaces(surfaces=surfaces,
- borehole_top=segment.points[0],
- borehole_bottom=segment.points[1],
- first_point=first_point) for segment in well_segments]
+ well_tops = [
+ ray_trace_multiple_surfaces(
+ surfaces=surfaces,
+ borehole_top=segment.points[0],
+ borehole_bottom=segment.points[1],
+ first_point=first_point,
+ )
+ for segment in well_segments
+ ]
# Flatten list
well_tops = [item for sublist in well_tops for item in sublist]
@@ -2023,14 +2132,18 @@ def create_virtual_profile(names_surfaces: list,
# well_dict = dict(sorted(well_dict.items(), key=lambda item: item[1], reverse=True))
# Creating DataFrame
- df = pd.DataFrame(list(zip(list_surfaces_filtered, z_values)), columns=['Surface', 'Z'])
+ df = pd.DataFrame(
+ list(zip(list_surfaces_filtered, z_values)), columns=["Surface", "Z"]
+ )
return df
-def extract_zmap_data(surface: pv.core.pointset.PolyData,
- cell_width: int,
- nodata: Union[float, int] = -9999):
+def extract_zmap_data(
+ surface: pv.core.pointset.PolyData,
+ cell_width: int,
+ nodata: Union[float, int] = -9999,
+):
"""Function to extract a meshgrid of values from a PyVista mesh
Parameters
@@ -2071,29 +2184,40 @@ def extract_zmap_data(surface: pv.core.pointset.PolyData,
y = np.arange(extent[2] + 0.5 * cell_width, extent[3], cell_width)
# Calculating the intersections
- intersections = [ray_trace_one_surface(surface=surface,
- origin=[x_value, y_value, extent[4]],
- end_point=[x_value, y_value, extent[5]],
- first_point=True) for x_value in x for y_value in y]
+ intersections = [
+ ray_trace_one_surface(
+ surface=surface,
+ origin=[x_value, y_value, extent[4]],
+ end_point=[x_value, y_value, extent[5]],
+ first_point=True,
+ )
+ for x_value in x
+ for y_value in y
+ ]
# Extracting the height values
- z_values = np.flipud(np.array([z[0][2] if len(z[0]) == 3 else nodata for z in intersections]).reshape(x_no_cells,
- y_no_cells).T)
+ z_values = np.flipud(
+ np.array([z[0][2] if len(z[0]) == 3 else nodata for z in intersections])
+ .reshape(x_no_cells, y_no_cells)
+ .T
+ )
return z_values
-def create_zmap_grid(surface: pv.core.pointset.PolyData,
- cell_width: int,
- comments: str = '',
- name: str = 'ZMAP_Grid',
- z_type: str = 'GRID',
- nodes_per_line: int = 5,
- field_width: int = 15,
- nodata: Union[int, float] = -9999.00000,
- nodata2: Union[int, float, str] = '',
- decimal_places: int = 5,
- start_column: int = 1):
+def create_zmap_grid(
+ surface: pv.core.pointset.PolyData,
+ cell_width: int,
+ comments: str = "",
+ name: str = "ZMAP_Grid",
+ z_type: str = "GRID",
+ nodes_per_line: int = 5,
+ field_width: int = 15,
+ nodata: Union[int, float] = -9999.00000,
+ nodata2: Union[int, float, str] = "",
+ decimal_places: int = 5,
+ start_column: int = 1,
+):
"""Function to write data to ZMAP Grid, This code is heavily inspired by https://github.com/abduhbm/zmapio
Parameters
@@ -2143,9 +2267,7 @@ def create_zmap_grid(surface: pv.core.pointset.PolyData,
"""
# Extracting z_values
- z_values = extract_zmap_data(surface=surface,
- cell_width=cell_width,
- nodata=nodata)
+ z_values = extract_zmap_data(surface=surface, cell_width=cell_width, nodata=nodata)
# Defining extent
extent = surface.bounds
@@ -2157,16 +2279,20 @@ def create_zmap_grid(surface: pv.core.pointset.PolyData,
# Defining auxiliary function
def chunks(x, n):
for i in range(0, len(x), n):
- yield x[i: i + n]
+ yield x[i : i + n]
# Create list of lines with first comments
- lines = ['!', '! This ZMAP Grid was created using the GemGIS Package',
- '! See https://github.com/cgre-aachen/gemgis for more information', '!']
+ lines = [
+ "!",
+ "! This ZMAP Grid was created using the GemGIS Package",
+ "! See https://github.com/cgre-aachen/gemgis for more information",
+ "!",
+ ]
# Appending comments to lines
for comment in comments:
- lines.append('! ' + comment)
- lines.append('!')
+ lines.append("! " + comment)
+ lines.append("!")
# Appending header information to lines
lines.append("@{}, {}, {}".format(name, z_type, nodes_per_line))
@@ -2185,12 +2311,7 @@ def chunks(x, n):
# Appending header information to lines
lines.append(
"{}, {}, {}, {}, {}, {}".format(
- no_rows,
- no_cols,
- extent[0],
- extent[1],
- extent[2],
- extent[3]
+ no_rows, no_cols, extent[0], extent[1], extent[2], extent[3]
)
)
@@ -2203,15 +2324,21 @@ def chunks(x, n):
for j in chunks(i, nodes_per_line):
j_fmt = "0.{}f".format(decimal_places)
j_fmt = "{0:" + j_fmt + "}"
- j = [j_fmt.format(float(x)) if not x is np.nan else j_fmt.format(float(nodata)) for x in j]
+ j = [
+ (
+ j_fmt.format(float(x))
+ if x is not np.nan
+ else j_fmt.format(float(nodata))
+ )
+ for x in j
+ ]
line = "{:>" + "{}".format(field_width) + "}"
lines.append("".join([line] * len(j)).format(*tuple(j)))
return lines
-def save_zmap_grid(zmap_grid: list,
- path: str = 'ZMAP_Grid.dat'):
+def save_zmap_grid(zmap_grid: list, path: str = "ZMAP_Grid.dat"):
"""Function to save ZMAP Grid information to file
Parameters
@@ -2228,20 +2355,22 @@ def save_zmap_grid(zmap_grid: list,
"""
# Writing the ZMAP Grid to file
- with open(path, 'w') as f:
+ with open(path, "w") as f:
f.write("\n".join(zmap_grid))
- print('ZMAP Grid successfully saved to file')
+ print("ZMAP Grid successfully saved to file")
-def rotate_gempy_input_data(extent: Union[np.ndarray, shapely.geometry.Polygon, gpd.geodataframe.GeoDataFrame],
- interfaces: Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame],
- orientations: Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame],
- zmin: Union[float, int] = None,
- zmax: Union[float, int] = None,
- rotate_reverse_direction: bool = False,
- return_extent_gdf: bool = False,
- manual_rotation_angle: Union[float, int] = None):
+def rotate_gempy_input_data(
+ extent: Union[np.ndarray, shapely.geometry.Polygon, gpd.geodataframe.GeoDataFrame],
+ interfaces: Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame],
+ orientations: Union[pd.DataFrame, gpd.geodataframe.GeoDataFrame],
+ zmin: Union[float, int] = None,
+ zmax: Union[float, int] = None,
+ rotate_reverse_direction: bool = False,
+ return_extent_gdf: bool = False,
+ manual_rotation_angle: Union[float, int] = None,
+):
"""Function to rotate the GemPy Input Data horizontally or vertically
Parameters
@@ -2288,143 +2417,210 @@ def rotate_gempy_input_data(extent: Union[np.ndarray, shapely.geometry.Polygon,
"""
# Checking that the extent is of type list, Shapely Polygon, or GeoDataFrame
- if not isinstance(extent, (np.ndarray, shapely.geometry.Polygon, gpd.geodataframe.GeoDataFrame)):
- raise TypeError('The extent must be provided as NumPy array, Shapely Polygon oder GeoDataFrame')
+ if not isinstance(
+ extent, (np.ndarray, shapely.geometry.Polygon, gpd.geodataframe.GeoDataFrame)
+ ):
+ raise TypeError(
+ "The extent must be provided as NumPy array, Shapely Polygon oder GeoDataFrame"
+ )
# Checking the number of coordinates of the extent and convert extent to Shapely Polygpon
if isinstance(extent, np.ndarray):
if len(extent) != 4:
- raise ValueError('Please only provide four corner coordinates as extent')
+ raise ValueError("Please only provide four corner coordinates as extent")
extent_polygon = Polygon(extent)
elif isinstance(extent, shapely.geometry.Polygon):
- if not (len(list(extent.exterior.coords)) != 4) or (len(list(extent.exterior.coords)) != 5):
- raise ValueError('Please only provide a polygon with four corner coordinates as extent')
+ if not (len(list(extent.exterior.coords)) != 4) or (
+ len(list(extent.exterior.coords)) != 5
+ ):
+ raise ValueError(
+ "Please only provide a polygon with four corner coordinates as extent"
+ )
extent_polygon = extent
else:
- if len(list(extent.iloc[0]['geometry'].exterior.coords)) != 5:
- raise ValueError('Please only provide a polygon with four corner coordinates as extent')
+ if len(list(extent.iloc[0]["geometry"].exterior.coords)) != 5:
+ raise ValueError(
+ "Please only provide a polygon with four corner coordinates as extent"
+ )
- extent_polygon = extent.iloc[0]['geometry']
+ extent_polygon = extent.iloc[0]["geometry"]
# Checking that the interfaces are of type DataFrame or GeoDataFrame
if not isinstance(interfaces, (pd.DataFrame, gpd.geodataframe.GeoDataFrame)):
- raise TypeError('Interfaces must be provided as Pandas DataFrame or GeoPandas GeoDataFrame')
+ raise TypeError(
+ "Interfaces must be provided as Pandas DataFrame or GeoPandas GeoDataFrame"
+ )
# Extracting X, Y, Z coordinates if interfaces are of type GeoDataFrame
- if (isinstance(interfaces, gpd.geodataframe.GeoDataFrame)) and (not {'X', 'Y', 'Z'}.issubset(interfaces.columns)):
+ if (isinstance(interfaces, gpd.geodataframe.GeoDataFrame)) and (
+ not {"X", "Y", "Z"}.issubset(interfaces.columns)
+ ):
interfaces = vector.extract_xy(interfaces)
# Checking if X, Y, Z coordinates are in columns
- if not {'X', 'Y', 'Z'}.issubset(interfaces.columns):
- raise ValueError('Please provide all X, Y and Z coordinates in the Pandas DataFrame or GeoPandas GeoDataFrame')
+ if not {"X", "Y", "Z"}.issubset(interfaces.columns):
+ raise ValueError(
+ "Please provide all X, Y and Z coordinates in the Pandas DataFrame or GeoPandas GeoDataFrame"
+ )
# Checking that the orientations are of type DataFrame or GeoDataFrame
if not isinstance(orientations, (pd.DataFrame, gpd.geodataframe.GeoDataFrame)):
- raise TypeError('Orientations must be provided as Pandas DataFrame or GeoPandas GeoDataFrame')
+ raise TypeError(
+ "Orientations must be provided as Pandas DataFrame or GeoPandas GeoDataFrame"
+ )
# Extracting X, Y, Z coordinates if orientations are of type GeoDataFrame
if (isinstance(orientations, gpd.geodataframe.GeoDataFrame)) and (
- not {'X', 'Y', 'Z'}.issubset(orientations.columns)):
+ not {"X", "Y", "Z"}.issubset(orientations.columns)
+ ):
orientations = vector.extract_xy(orientations)
# Checking if X, Y, Z coordinates are in columns
- if not {'X', 'Y', 'Z'}.issubset(orientations.columns):
- raise ValueError('Please provide all X, Y and Z coordinates in the Pandas DataFrame or GeoPandas GeoDataFrame')
+ if not {"X", "Y", "Z"}.issubset(orientations.columns):
+ raise ValueError(
+ "Please provide all X, Y and Z coordinates in the Pandas DataFrame or GeoPandas GeoDataFrame"
+ )
# Checking that zmin is of type float or int
if not isinstance(zmin, (float, int)):
- raise TypeError('zmin must be provided as float or int')
+ raise TypeError("zmin must be provided as float or int")
# Checking that zmax is of type float or int
if not isinstance(zmax, (float, int)):
- raise TypeError('zmax must be provided as float or int')
+ raise TypeError("zmax must be provided as float or int")
# Checking that rotate_reverse_direction is of type bool
if not isinstance(rotate_reverse_direction, bool):
- raise TypeError('rotate_reverse_direction must be of type bool')
+ raise TypeError("rotate_reverse_direction must be of type bool")
# Checking that return_extent_gdf is of type bool
if not isinstance(return_extent_gdf, bool):
- raise TypeError('return_extent_gdf must be of type bool')
+ raise TypeError("return_extent_gdf must be of type bool")
# Calculating the smallest angle to perform the rotation
- min_angle = min([vector.calculate_angle(LineString((list(extent_polygon.exterior.coords)[i],
- list(extent_polygon.exterior.coords)[i + 1]))) for i in
- range(len(list(extent_polygon.exterior.coords)) - 1)])
+ min_angle = min(
+ [
+ vector.calculate_angle(
+ LineString(
+ (
+ list(extent_polygon.exterior.coords)[i],
+ list(extent_polygon.exterior.coords)[i + 1],
+ )
+ )
+ )
+ for i in range(len(list(extent_polygon.exterior.coords)) - 1)
+ ]
+ )
# Using the manual rotation angle if provided
if manual_rotation_angle:
min_angle = manual_rotation_angle
# Creating GeoDataFrames from DataFrames
- interfaces = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=interfaces['X'],
- y=interfaces['Y']),
- data=interfaces)
+ interfaces = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(x=interfaces["X"], y=interfaces["Y"]),
+ data=interfaces,
+ )
- orientations = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=orientations['X'],
- y=orientations['Y']),
- data=orientations)
+ orientations = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(x=orientations["X"], y=orientations["Y"]),
+ data=orientations,
+ )
# Creating Polygons from Interfaces and Orientations
- interfaces_polygon = shapely.geometry.Polygon(interfaces['geometry'])
- orientations_polygon = shapely.geometry.Polygon(orientations['geometry'])
+ interfaces_polygon = shapely.geometry.Polygon(interfaces["geometry"])
+ orientations_polygon = shapely.geometry.Polygon(orientations["geometry"])
# Rotating extent to vertical or horizontal
if not rotate_reverse_direction:
# Rotating extent
- extent_rotated = shapely.affinity.rotate(extent_polygon, -min_angle, 'center')
+ extent_rotated = shapely.affinity.rotate(extent_polygon, -min_angle, "center")
# Rotating interfaces and orientations
- interfaces_polygon_rotated = shapely.affinity.rotate(interfaces_polygon,
- -min_angle,
- (list(extent_polygon.centroid.coords)[0][0],
- list(extent_polygon.centroid.coords)[0][1]))
+ interfaces_polygon_rotated = shapely.affinity.rotate(
+ interfaces_polygon,
+ -min_angle,
+ (
+ list(extent_polygon.centroid.coords)[0][0],
+ list(extent_polygon.centroid.coords)[0][1],
+ ),
+ )
- orientations_polygon_rotated = shapely.affinity.rotate(orientations_polygon,
- -min_angle,
- (list(extent_polygon.centroid.coords)[0][0],
- list(extent_polygon.centroid.coords)[0][1]))
+ orientations_polygon_rotated = shapely.affinity.rotate(
+ orientations_polygon,
+ -min_angle,
+ (
+ list(extent_polygon.centroid.coords)[0][0],
+ list(extent_polygon.centroid.coords)[0][1],
+ ),
+ )
else:
# Rotating extent
- extent_rotated = shapely.affinity.rotate(extent_polygon, min_angle, 'center')
+ extent_rotated = shapely.affinity.rotate(extent_polygon, min_angle, "center")
# Rotating interfaces and orientations
- interfaces_polygon_rotated = shapely.affinity.rotate(interfaces_polygon,
- min_angle,
- (list(extent_polygon.centroid.coords)[0][0],
- list(extent_polygon.centroid.coords)[0][1]))
+ interfaces_polygon_rotated = shapely.affinity.rotate(
+ interfaces_polygon,
+ min_angle,
+ (
+ list(extent_polygon.centroid.coords)[0][0],
+ list(extent_polygon.centroid.coords)[0][1],
+ ),
+ )
- orientations_polygon_rotated = shapely.affinity.rotate(orientations_polygon,
- min_angle,
- (list(extent_polygon.centroid.coords)[0][0],
- list(extent_polygon.centroid.coords)[0][1]))
+ orientations_polygon_rotated = shapely.affinity.rotate(
+ orientations_polygon,
+ min_angle,
+ (
+ list(extent_polygon.centroid.coords)[0][0],
+ list(extent_polygon.centroid.coords)[0][1],
+ ),
+ )
# Creating Bounding Box
- bbox = box(*extent_rotated.bounds)
- extent = [extent_rotated.bounds[0],
- extent_rotated.bounds[2],
- extent_rotated.bounds[1],
- extent_rotated.bounds[3],
- zmin,
- zmax]
+ extent = [
+ extent_rotated.bounds[0],
+ extent_rotated.bounds[2],
+ extent_rotated.bounds[1],
+ extent_rotated.bounds[3],
+ zmin,
+ zmax,
+ ]
# Converting Polygons back to Points and extracting Points
interfaces_rotated = gpd.GeoDataFrame(
- geometry=gpd.points_from_xy(x=[coords[0] for coords in list(interfaces_polygon_rotated.exterior.coords)[:-1]],
- y=[coords[1] for coords in list(interfaces_polygon_rotated.exterior.coords)[:-1]]),
- data=interfaces)
+ geometry=gpd.points_from_xy(
+ x=[
+ coords[0]
+ for coords in list(interfaces_polygon_rotated.exterior.coords)[:-1]
+ ],
+ y=[
+ coords[1]
+ for coords in list(interfaces_polygon_rotated.exterior.coords)[:-1]
+ ],
+ ),
+ data=interfaces,
+ )
interfaces_rotated = vector.extract_xy(interfaces_rotated)
orientations_rotated = gpd.GeoDataFrame(
- geometry=gpd.points_from_xy(x=[coords[0] for coords in list(orientations_polygon_rotated.exterior.coords)[:-1]],
- y=[coords[1] for coords in
- list(orientations_polygon_rotated.exterior.coords)[:-1]]),
- data=orientations)
+ geometry=gpd.points_from_xy(
+ x=[
+ coords[0]
+ for coords in list(orientations_polygon_rotated.exterior.coords)[:-1]
+ ],
+ y=[
+ coords[1]
+ for coords in list(orientations_polygon_rotated.exterior.coords)[:-1]
+ ],
+ ),
+ data=orientations,
+ )
orientations_rotated = vector.extract_xy(orientations_rotated)
# Return extent gdf if needed
@@ -2463,48 +2659,62 @@ def open_mpk(path_in: str):
import py7zr
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'py7zr package is not installed. Use pip install py7zr to install the latest version')
+ "py7zr package is not installed. Use pip install py7zr to install the latest version"
+ )
# Checking that the file path is of type string
if not isinstance(path_in, str):
- raise TypeError('The file path must be provided as string')
+ raise TypeError("The file path must be provided as string")
# Renaming .mpk file to .zip file
- path_out = path_in.split('.mpk')[0]
- os.rename(path_in, path_out + '.zip')
+ path_out = path_in.split(".mpk")[0]
+ os.rename(path_in, path_out + ".zip")
# Unzipping files
- with py7zr.SevenZipFile(path_out + '.zip',
- 'r') as archive:
+ with py7zr.SevenZipFile(path_out + ".zip", "r") as archive:
archive.extractall(path=path_out)
# Getting vector data files
- files_vector_data = [os.path.join(path, name) for path, subdirs, files in os.walk(path_out)
- for name in files if name.endswith(".shp")]
+ files_vector_data = [
+ os.path.join(path, name)
+ for path, subdirs, files in os.walk(path_out)
+ for name in files
+ if name.endswith(".shp")
+ ]
# Creating vector data dict
- dict_vector_data = {file.rsplit('\\')[-1]: gpd.read_file(file) for file in files_vector_data}
+ dict_vector_data = {
+ file.rsplit("\\")[-1]: gpd.read_file(file) for file in files_vector_data
+ }
# TODO: Add support for .tif files if case arises
# Getting raster data files
- files_raster_data_adf = [os.path.join(path, name) for path, subdirs, files in os.walk(path_out) for name in files if
- (name.endswith(".adf")) & (name.startswith("w001001."))]
+ files_raster_data_adf = [
+ os.path.join(path, name)
+ for path, subdirs, files in os.walk(path_out)
+ for name in files
+ if (name.endswith(".adf")) & (name.startswith("w001001."))
+ ]
# Creating raster data dict
- dict_raster_data = {file.rsplit('\\')[-1]: rasterio.open(file) for file in files_raster_data_adf}
+ dict_raster_data = {
+ file.rsplit("\\")[-1]: rasterio.open(file) for file in files_raster_data_adf
+ }
return dict_vector_data, dict_raster_data
-def convert_crs_seismic_data(path_in: str,
- path_out: str,
- crs_in: Union[str, pyproj.crs.crs.CRS],
- crs_out: Union[str, pyproj.crs.crs.CRS],
- cdpx: int = 181,
- cdpy: int = 185,
- vert_domain: str = 'TWT',
- coord_scalar: int = None):
+def convert_crs_seismic_data(
+ path_in: str,
+ path_out: str,
+ crs_in: Union[str, pyproj.crs.crs.CRS],
+ crs_out: Union[str, pyproj.crs.crs.CRS],
+ cdpx: int = 181,
+ cdpy: int = 185,
+ vert_domain: str = "TWT",
+ coord_scalar: int = None,
+):
"""Convert CDP coordinates of seismic data to a new CRS.
Parameters
@@ -2534,45 +2744,44 @@ def convert_crs_seismic_data(path_in: str,
from segysak.segy import segy_loader, segy_writer
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'segysak package is not installed. Use pip install segysak to install the latest version')
+ "segysak package is not installed. Use pip install segysak to install the latest version"
+ )
# Checking that path_in is of type string
if not isinstance(path_in, str):
- raise TypeError('path_in must be provided as string')
+ raise TypeError("path_in must be provided as string")
# Checking that path_out is of type string
if not isinstance(path_out, str):
- raise TypeError('path_out must be provided as string')
+ raise TypeError("path_out must be provided as string")
# Checking that crs_in is of type string or pyproj CRS
if not isinstance(crs_in, (str, pyproj.crs.crs.CRS)):
- raise TypeError('crs_in must be provided as string or pyproj CRS')
+ raise TypeError("crs_in must be provided as string or pyproj CRS")
# Checking that crs_out is of type string or pyproj CRS
if not isinstance(crs_out, (str, pyproj.crs.crs.CRS)):
- raise TypeError('crs_out must be provided as string or pyproj CRS')
+ raise TypeError("crs_out must be provided as string or pyproj CRS")
# Checking that vert_domain is of type str
if not isinstance(vert_domain, str):
- raise TypeError('vert_domain must be provided as string')
+ raise TypeError("vert_domain must be provided as string")
# Checking that the coord_scalar is of type int or None
if not isinstance(coord_scalar, (int, type(None))):
- raise TypeError('coord_scalar must be provided as int')
+ raise TypeError("coord_scalar must be provided as int")
# Loading seismic data
- seismic = segy_loader(path_in,
- vert_domain=vert_domain,
- cdpx=cdpx,
- cdpy=cdpy)
+ seismic = segy_loader(path_in, vert_domain=vert_domain, cdpx=cdpx, cdpy=cdpy)
# Converting Seismic to DataFrame
df_seismic = seismic.to_dataframe()
# Checking that the CDP coordinates are in the DataFrame
- if not {'cdp_x', 'cdp_y'}.issubset(df_seismic.columns):
+ if not {"cdp_x", "cdp_y"}.issubset(df_seismic.columns):
raise ValueError(
- 'No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored')
+ "No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored"
+ )
# Extracting the length of the samples to reduce computing time
samples = len(df_seismic.index.get_level_values(1).unique())
@@ -2581,36 +2790,39 @@ def convert_crs_seismic_data(path_in: str,
df_seismic_resampled = df_seismic[::samples]
# Reprojecting Coordinates
- df_seismic_reprojected = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=df_seismic_resampled['cdp_x'].values,
- y=df_seismic_resampled['cdp_y'].values),
- crs=crs_in).to_crs(crs_out)
+ df_seismic_reprojected = gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(
+ x=df_seismic_resampled["cdp_x"].values,
+ y=df_seismic_resampled["cdp_y"].values,
+ ),
+ crs=crs_in,
+ ).to_crs(crs_out)
# Extracting reprojected coordinates
x = df_seismic_reprojected.geometry.x.values
y = df_seismic_reprojected.geometry.y.values
# Assigning new coordinates
- seismic['cdp_x'][:] = x
- seismic['cdp_y'][:] = y
+ seismic["cdp_x"][:] = x
+ seismic["cdp_y"][:] = y
# Optionally setting a new coord_scalar
if coord_scalar:
- seismic.attrs['coord_scalar'] = coord_scalar
+ seismic.attrs["coord_scalar"] = coord_scalar
# Saving reprojected seismic data to file
- segy_writer(seismic,
- path_out,
- trace_header_map=dict(cdp_x=181,
- cdp_y=185))
+ segy_writer(seismic, path_out, trace_header_map=dict(cdp_x=181, cdp_y=185))
- print('Seismic data was successfully reprojected and saved to file')
+ print("Seismic data was successfully reprojected and saved to file")
-def get_cdp_linestring_of_seismic_data(path_in: str,
- crs_in: Union[str, pyproj.crs.crs.CRS],
- cdpx: int = 181,
- cdpy: int = 185,
- vert_domain: str = 'TWT'):
+def get_cdp_linestring_of_seismic_data(
+ path_in: str,
+ crs_in: Union[str, pyproj.crs.crs.CRS],
+ cdpx: int = 181,
+ cdpy: int = 185,
+ vert_domain: str = "TWT",
+):
"""Extracting the path of the seismic data as LineString.
Parameters
@@ -2636,36 +2848,35 @@ def get_cdp_linestring_of_seismic_data(path_in: str,
"""
# Trying to import segysak but returning error if segysak is not installed
try:
- from segysak.segy import segy_loader, segy_writer
+ from segysak.segy import segy_loader
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'segysak package is not installed. Use pip install segysak to install the latest version')
+ "segysak package is not installed. Use pip install segysak to install the latest version"
+ )
# Checking that path_in is of type string
if not isinstance(path_in, str):
- raise TypeError('path_in must be provided as string')
+ raise TypeError("path_in must be provided as string")
# Checking that crs_in is of type string or pyproj CRS
if not isinstance(crs_in, (str, pyproj.crs.crs.CRS)):
- raise TypeError('crs_in must be provided as string or pyproj CRS')
+ raise TypeError("crs_in must be provided as string or pyproj CRS")
# Checking that vert_domain is of type str
if not isinstance(vert_domain, str):
- raise TypeError('vert_domain must be provided as string')
+ raise TypeError("vert_domain must be provided as string")
# Loading seismic data
- seismic = segy_loader(path_in,
- vert_domain=vert_domain,
- cdpx=cdpx,
- cdpy=cdpy)
+ seismic = segy_loader(path_in, vert_domain=vert_domain, cdpx=cdpx, cdpy=cdpy)
# Converting Seismic to DataFrame
df_seismic = seismic.to_dataframe()
# Checking that the CDP coordinates are in the DataFrame
- if not {'cdp_x', 'cdp_y'}.issubset(df_seismic.columns):
+ if not {"cdp_x", "cdp_y"}.issubset(df_seismic.columns):
raise ValueError(
- 'No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored')
+ "No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored"
+ )
# Extracting the length of the samples to reduce computing time
samples = len(df_seismic.index.get_level_values(1).unique())
@@ -2674,23 +2885,27 @@ def get_cdp_linestring_of_seismic_data(path_in: str,
df_seismic_resampled = df_seismic[::samples]
# Creating LineString from coordinates
- linestring = LineString(np.c_[(df_seismic_resampled['cdp_x'].values,
- df_seismic_resampled['cdp_y'].values)])
+ linestring = LineString(
+ np.c_[
+ (df_seismic_resampled["cdp_x"].values, df_seismic_resampled["cdp_y"].values)
+ ]
+ )
# Reprojecting Coordinates
- gdf_seismic = gpd.GeoDataFrame(geometry=[linestring],
- crs=crs_in)
+ gdf_seismic = gpd.GeoDataFrame(geometry=[linestring], crs=crs_in)
return gdf_seismic
-def get_cdp_points_of_seismic_data(path_in: str,
- crs_in: Union[str, pyproj.crs.crs.CRS],
- cdpx: int = 181,
- cdpy: int = 185,
- vert_domain: str = 'TWT',
- filter: int = None,
- n_meter: Union[int, float] = None):
+def get_cdp_points_of_seismic_data(
+ path_in: str,
+ crs_in: Union[str, pyproj.crs.crs.CRS],
+ cdpx: int = 181,
+ cdpy: int = 185,
+ vert_domain: str = "TWT",
+ filter: int = None,
+ n_meter: Union[int, float] = None,
+):
"""Extracting the path of the seismic data as LineString.
Parameters
@@ -2720,36 +2935,35 @@ def get_cdp_points_of_seismic_data(path_in: str,
"""
# Trying to import segysak but returning error if segysak is not installed
try:
- from segysak.segy import segy_loader, segy_writer
+ from segysak.segy import segy_loader
except ModuleNotFoundError:
raise ModuleNotFoundError(
- 'segysak package is not installed. Use pip install segysak to install the latest version')
+ "segysak package is not installed. Use pip install segysak to install the latest version"
+ )
# Checking that path_in is of type string
if not isinstance(path_in, str):
- raise TypeError('path_in must be provided as string')
+ raise TypeError("path_in must be provided as string")
# Checking that crs_in is of type string or pyproj CRS
if not isinstance(crs_in, (str, pyproj.crs.crs.CRS)):
- raise TypeError('crs_in must be provided as string or pyproj CRS')
+ raise TypeError("crs_in must be provided as string or pyproj CRS")
# Checking that vert_domain is of type str
if not isinstance(vert_domain, str):
- raise TypeError('vert_domain must be provided as string')
+ raise TypeError("vert_domain must be provided as string")
# Loading seismic data
- seismic = segy_loader(path_in,
- vert_domain=vert_domain,
- cdpx=cdpx,
- cdpy=cdpy)
+ seismic = segy_loader(path_in, vert_domain=vert_domain, cdpx=cdpx, cdpy=cdpy)
# Converting Seismic to DataFrame
df_seismic = seismic.to_dataframe()
# Checking that the CDP coordinates are in the DataFrame
- if not {'cdp_x', 'cdp_y'}.issubset(df_seismic.columns):
+ if not {"cdp_x", "cdp_y"}.issubset(df_seismic.columns):
raise ValueError(
- 'No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored')
+ "No coordinates found, please provide the byte positions where the X and Y data of the CDPs is stored"
+ )
# Extracting the length of the samples to reduce computing time
samples = len(df_seismic.index.get_level_values(1).unique())
@@ -2760,28 +2974,44 @@ def get_cdp_points_of_seismic_data(path_in: str,
if n_meter:
# Creating LineString from coordinates
- linestring = LineString(np.c_[(df_seismic_resampled['cdp_x'].values,
- df_seismic_resampled['cdp_y'].values)])
+ linestring = LineString(
+ np.c_[
+ (
+ df_seismic_resampled["cdp_x"].values,
+ df_seismic_resampled["cdp_y"].values,
+ )
+ ]
+ )
# Defining number of samples
samples = np.arange(0, round(linestring.length / n_meter) + 1, 1)
# Getting points every n_meter
- points = [shapely.line_interpolate_point(linestring, n_meter * sample) for sample in samples]
+ points = [
+ shapely.line_interpolate_point(linestring, n_meter * sample)
+ for sample in samples
+ ]
# Creating GeoDataFrame from points
- gdf_seismic = gpd.GeoDataFrame(geometry=points,
- crs=crs_in)
+ gdf_seismic = gpd.GeoDataFrame(geometry=points, crs=crs_in)
# Appending distance
- gdf_seismic['distance'] = samples * n_meter
+ gdf_seismic["distance"] = samples * n_meter
else:
# Creating Points from coordinates
- gdf_seismic = gpd.GeoDataFrame(geometry=gpd.points_from_xy(x=df_seismic_resampled['cdp_x'].values,
- y=df_seismic_resampled['cdp_y'].values),
- data=df_seismic_resampled,
- crs=crs_in).reset_index().drop(['twt', 'data'], axis=1)
+ gdf_seismic = (
+ gpd.GeoDataFrame(
+ geometry=gpd.points_from_xy(
+ x=df_seismic_resampled["cdp_x"].values,
+ y=df_seismic_resampled["cdp_y"].values,
+ ),
+ data=df_seismic_resampled,
+ crs=crs_in,
+ )
+ .reset_index()
+ .drop(["twt", "data"], axis=1)
+ )
# Returning only every nth point
if filter:
diff --git a/gemgis/vector.py b/gemgis/vector.py
index e421aec2..a45a731b 100644
--- a/gemgis/vector.py
+++ b/gemgis/vector.py
@@ -28,7 +28,6 @@
import geopandas as gpd
from gemgis.raster import sample_from_array, sample_from_rasterio
from typing import Union, List, Tuple, Optional, Sequence, Collection
-import fiona
import pyvista as pv
__all__ = [geometry]
@@ -36,61 +35,93 @@
try:
import rasterio
except ModuleNotFoundError:
- raise ModuleNotFoundError('No valid rasterio installation found')
+ raise ModuleNotFoundError("No valid rasterio installation found")
-pd.set_option('display.float_format', lambda x: '%.2f' % x)
+pd.set_option("display.float_format", lambda x: "%.2f" % x)
# Extracting X and Y coordinates from Vector Data
#################################################
-def extract_xy_points(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_id: bool = True,
- drop_index: bool = True,
- overwrite_xy: bool = False,
- target_crs: Union[str, pyproj.crs.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (Points) and returning a GeoDataFrame with X and Y
- coordinates as additional columns
+def extract_xy_points(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_id: bool = True,
+ drop_index: bool = True,
+ overwrite_xy: bool = False,
+ target_crs: Union[str, pyproj.crs.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (Points) and returning a GeoDataFrame with X and Y
+ coordinates as additional columns.
Parameters
----------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type Point
-
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ GeoDataFrame created from vector data containing exclusively elements of `geom_type` `'Point'`.
+
+ +----+------+-----------+------------------------+
+ | ID | id | formation | geometry |
+ +----+------+-----------+------------------------+
+ | 0 | None | Ton | POINT (19.150 293.313) |
+ +----+------+-----------+------------------------+
+ | 1 | None | Ton | POINT (61.934 381.459) |
+ +----+------+-----------+------------------------+
+ | 2 | None | Ton | POINT (109.358 480.946)|
+ +----+------+-----------+------------------------+
+ | 3 | None | Ton | POINT (157.812 615.999)|
+ +----+------+-----------+------------------------+
+ | 4 | None | Ton | POINT (191.318 719.094)|
+ +----+------+-----------+------------------------+
+
+ reset_index : bool, default: ``True``
+ Variable to reset the index of the resulting GeoDataFrame.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
- Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_id : bool, default: ``True``
+ Variable to drop the id column.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column.
+ Options include: ``True`` or ``False``, default set to ``True``.
- overwrite_xy : bool
- Variable to overwrite existing X and Y values.
- Options include: ``True`` or ``False``, default set to ``False``
+ overwrite_xy : bool, default: ``False``
+ Variable to overwrite existing X and Y values.
+ Options include: ``True`` or ``False``, default set to ``False``.
target_crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : list
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
Returns
-------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame with appended X and Y coordinates as new columns and optional columns
+ GeoDataFrame with appended X and Y coordinates as new columns and optional columns.
+
+ +----+-----------+-------------------------+-----------+-----------+
+ | ID | formation | geometry | X | Y |
+ +====+===========+=========================+===========+===========+
+ | 0 | Ton | POINT (19.150 293.313) | 19.150 | 293.313 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.934 | 381.459 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 2 | Ton | POINT (109.358 480.946) | 109.358 | 480.946 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 3 | Ton | POINT (157.812 615.999) | 157.812 | 615.999 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 4 | Ton | POINT (191.318 719.094) | 191.318 | 719.094 |
+ +----+-----------+-------------------------+-----------+-----------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -99,90 +130,109 @@ def extract_xy_points(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Ton POINT (19.150 293.313)
- 1 None Ton POINT (61.934 381.459)
- 2 None Ton POINT (109.358 480.946)
- 3 None Ton POINT (157.812 615.999)
- 4 None Ton POINT (191.318 719.094)
-
- >>> # Extracting X and Y Coordinates from Point Objects
+
+ +----+------+-----------+------------------------+
+ | ID | id | formation | geometry |
+ +----+------+-----------+------------------------+
+ | 0 | None | Ton | POINT (19.150 293.313) |
+ +----+------+-----------+------------------------+
+ | 1 | None | Ton | POINT (61.934 381.459) |
+ +----+------+-----------+------------------------+
+ | 2 | None | Ton | POINT (109.358 480.946)|
+ +----+------+-----------+------------------------+
+ | 3 | None | Ton | POINT (157.812 615.999)|
+ +----+------+-----------+------------------------+
+ | 4 | None | Ton | POINT (191.318 719.094)|
+ +----+------+-----------+------------------------+
+
+
+ >>> # Extracting X and Y Coordinates from Point GeoDataFrame
>>> gdf_xy = gg.vector.extract_xy_points(gdf=gdf, reset_index=False)
>>> gdf_xy
- formation geometry X Y
- 0 Ton POINT (19.150 293.313) 19.15 293.31
- 1 Ton POINT (61.934 381.459) 61.93 381.46
- 2 Ton POINT (109.358 480.946) 109.36 480.95
- 3 Ton POINT (157.812 615.999) 157.81 616.00
- 4 Ton POINT (191.318 719.094) 191.32 719.09
+
+ +----+-----------+-------------------------+-----------+-----------+
+ | ID | formation | geometry | X | Y |
+ +====+===========+=========================+===========+===========+
+ | 0 | Ton | POINT (19.150 293.313) | 19.150 | 293.313 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.934 | 381.459 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 2 | Ton | POINT (109.358 480.946) | 109.358 | 480.946 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 3 | Ton | POINT (157.812 615.999) | 157.812 | 615.999 |
+ +----+-----------+-------------------------+-----------+-----------+
+ | 4 | Ton | POINT (191.318 719.094) | 191.318 | 719.094 |
+ +----+-----------+-------------------------+-----------+-----------+
See Also
________
- extract_xy_linestring : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
+ extract_xy : Extract X and Y coordinates from Vector Data
+ extract_xy_linestring : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
saving the X and Y coordinates as lists for each LineString
- extract_xy_linestrings : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
- extract_xy : Extracting X and Y coordinates from Vector Data
-
- """
+ extract_xy_linestrings : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
+ """
# Checking that gdf is of type GepDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Check that all entries of the gdf are of type Point
if not all(shapely.get_type_id(gdf.geometry) == 0):
- raise TypeError('All GeoDataFrame entries must be of geom_type Point')
+ raise TypeError("All GeoDataFrame entries must be of geom_type Point")
# Checking that the bbox is of type None or list
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that none of the points have a Z component
if any(shapely.has_z(gdf.geometry)):
raise ValueError(
- 'One or more Shapely objects contain a Z component. Use gg.vector.extract_xyz(...) to obtain all coordinates.')
+ "One or more Shapely objects contain a Z component. Use gg.vector.extract_xyz(...) to obtain all coordinates."
+ )
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that the target_crs is of type string
if not isinstance(target_crs, (str, type(None), pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Checking that overwrite_xy is of type bool
if not isinstance(overwrite_xy, bool):
- raise TypeError('Overwrite_xy argument must be of type bool')
+ raise TypeError("Overwrite_xy argument must be of type bool")
# Checking that X and Y are not in the GeoDataFrame
- if not overwrite_xy and {'X', 'Y'}.issubset(gdf.columns):
- raise ValueError('X and Y columns must not be present in GeoDataFrame before the extraction of coordinates')
+ if not overwrite_xy and {"X", "Y"}.issubset(gdf.columns):
+ raise ValueError(
+ "X and Y columns must not be present in GeoDataFrame before the extraction of coordinates"
+ )
# Copying GeoDataFrame
gdf = gdf.copy(deep=True)
@@ -192,56 +242,83 @@ def extract_xy_points(gdf: gpd.geodataframe.GeoDataFrame,
gdf = gdf.to_crs(crs=target_crs)
# Extracting x,y coordinates from point vector data
- gdf['X'] = shapely.get_x(gdf.geometry)
- gdf['Y'] = shapely.get_y(gdf.geometry)
+ gdf["X"] = shapely.get_x(gdf.geometry)
+ gdf["Y"] = shapely.get_y(gdf.geometry)
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
return gdf
-def extract_xy_linestring(gdf: gpd.geodataframe.GeoDataFrame,
- target_crs: Union[str, pyproj.crs.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None) -> gpd.geodataframe.GeoDataFrame:
- """Extracting the coordinates of Shapely LineStrings within a GeoDataFrame
- and storing the X and Y coordinates in lists per LineString
+def extract_xy_linestring(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ target_crs: Union[str, pyproj.crs.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract the coordinates of Shapely LineStrings within a GeoDataFrame
+ and storing the X and Y coordinates in lists per LineString.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type LineString
+ GeoDataFrame created from vector data containing elements of geom_type LineString.
+
+ +----+-----------+-----------+----------------------------------------------------+
+ | | id | formation | geometry |
+ +----+-----------+-----------+----------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... |
+ +----+-----------+----------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... |
+ +----+-----------+----------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... |
+ +----+-----------+----------------------------------------------------------------+
target_crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
-
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : Optional[Sequence[float]]
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing the additional X and Y columns with lists of X and Y coordinates
+ GeoDataFrame containing the additional X and Y columns with lists of X and Y coordinates.
+
+ +----+-----------+-----------+----------------------------------------------------+-----------------------------------------------------+-------------------------------------------------------------+
+ | | id | formation | geometry | X | Y |
+ +----+-----------+-----------+----------------------------------------------------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... | [0.256327195431048, 10.59346813871597, 17.1349...] | [264.86214748436396, 276.73370778641777, 289.0...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... | [0.1881868620686138, 8.840672956663411, 41.092...] | [495.787213546976, 504.1418419288791, 546.4230...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... | [970.6766251230017, 959.3724321757514, 941.291...] | [833.052616499831, 800.0232029873156, 754.8012...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -250,132 +327,181 @@ def extract_xy_linestring(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Sand1 LINESTRING (0.256 264.862, 10.593 276.734, 17....
- 1 None Ton LINESTRING (0.188 495.787, 8.841 504.142, 41.0...
- 2 None Ton LINESTRING (970.677 833.053, 959.372 800.023, ...
+
+ +----+-----------+-----------+----------------------------------------------------+
+ | | id | formation | geometry |
+ +----+-----------+-----------+----------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... |
+ +----+-----------+----------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... |
+ +----+-----------+----------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... |
+ +----+-----------+----------------------------------------------------------------+
>>> # Extracting X and Y Coordinates from LineString Objects
>>> gdf_xy = gg.vector.extract_xy_linestring(gdf=gdf)
>>> gdf_xy
- id formation geometry X Y
- 0 None Sand1 LINESTRING (0.256 264.862, 10.593 276.734, 17.... [0.256327195431048, 10.59346813871597, 17.1349... [264.86214748436396, 276.73370778641777, 289.0...
- 1 None Ton LINESTRING (0.188 495.787, 8.841 504.142, 41.0... [0.1881868620686138, 8.840672956663411, 41.092... [495.787213546976, 504.1418419288791, 546.4230...
- 2 None Ton LINESTRING (970.677 833.053, 959.372 800.023, ... [970.6766251230017, 959.3724321757514, 941.291... [833.052616499831, 800.0232029873156, 754.8012...
+
+ +----+-----------+-----------+----------------------------------------------------+-----------------------------------------------------+-------------------------------------------------------------+
+ | | id | formation | geometry | X | Y |
+ +----+-----------+-----------+----------------------------------------------------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... | [0.256327195431048, 10.59346813871597, 17.1349...] | [264.86214748436396, 276.73370778641777, 289.0...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... | [0.1881868620686138, 8.840672956663411, 41.092...] | [495.787213546976, 504.1418419288791, 546.4230...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... | [970.6766251230017, 959.3724321757514, 941.291...] | [833.052616499831, 800.0232029873156, 754.8012...] |
+ +----+-----------+-----------+-------------------------------------------+--------+-----------------------------------------------------+-------------------------------------------------------------+
See Also
________
- extract_xy_linestrings : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
- extract_xy_points : Extracting X and Y coordinates from a GeoDataFrame containing Shapely Points
- extract_xy : Extracting X and Y coordinates from Vector Data
+ extract_xy : Extract X and Y coordinates from Vector Data
+ extract_xy_points : Extract X and Y coordinates from a GeoDataFrame containing Shapely Points
+ extract_xy_linestrings : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
"""
-
# Checking that gdf is of type GepDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Check that all entries of the gdf are of type LineString
if not all(shapely.get_type_id(gdf.geometry) == 1):
- raise TypeError('All GeoDataFrame entries must be of geom_type linestrings')
+ raise TypeError("All GeoDataFrame entries must be of geom_type linestrings")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that none of the points have a Z component
if any(shapely.has_z(gdf.geometry)):
- raise ValueError('One or more Shapely objects contain a Z component')
+ raise ValueError("One or more Shapely objects contain a Z component")
# Checking that the bbox is of type None or list
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that the target_crs is of type string
if target_crs is not None and not isinstance(target_crs, (str, pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Reprojecting coordinates to provided the target_crs
if target_crs is not None:
gdf = gdf.to_crs(crs=target_crs)
# Extracting X coordinates
- gdf['X'] = [list(shapely.get_coordinates(gdf.geometry[i])[:, 0]) for i in range(len(gdf))]
+ gdf["X"] = [
+ list(shapely.get_coordinates(gdf.geometry[i])[:, 0]) for i in range(len(gdf))
+ ]
# Extracting Y coordinates
- gdf['Y'] = [list(shapely.get_coordinates(gdf.geometry[i])[:, 1]) for i in range(len(gdf))]
+ gdf["Y"] = [
+ list(shapely.get_coordinates(gdf.geometry[i])[:, 1]) for i in range(len(gdf))
+ ]
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
return gdf
-def extract_xy_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_id: bool = True,
- drop_index: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- overwrite_xy: bool = False,
- target_crs: Union[str, pyproj.crs.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (LineStrings) and returning a GeoDataFrame with X and Y
- coordinates as additional columns
+def extract_xy_linestrings(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_id: bool = True,
+ drop_index: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ overwrite_xy: bool = False,
+ target_crs: Union[str, pyproj.crs.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (LineStrings) and returning a GeoDataFrame with X and Y
+ coordinates as additional columns.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type LineString
- reset_index : bool
+ GeoDataFrame created from vector data containing elements of geom_type LineString.
+
+ +----+-----------+-----------+----------------------------------------------------+
+ | | id | formation | geometry |
+ +----+-----------+-----------+----------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... |
+ +----+-----------+----------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... |
+ +----+-----------+----------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... |
+ +----+-----------+----------------------------------------------------------------+
+
+ reset_index : bool, default: ``True``
Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
- drop_id : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ drop_id : bool, default: ``True``
Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
- drop_index : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ drop_index : bool, default: ``True``
Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
- drop_points : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ drop_points : bool, default: ``True``
Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
- drop_level0 : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ drop_level0 : bool, default: ``True``
Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
- drop_level1 : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ drop_level1 : bool, default: ``True``
Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
- overwrite_xy : bool
+ Options include: ``True`` or ``False``, default set to ``True``.
+ overwrite_xy : bool, default: ``False``
Variable to overwrite existing X and Y values.
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
target_crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : Optional[Sequence[float]]
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
Returns
-------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame with appended X and Y coordinates as additional columns and optional columns
+ GeoDataFrame with appended X and Y coordinates as additional columns and optional columns.
+
+ +----+-----------+------------------------+-------+--------+
+ | | formation | geometry | X | Y |
+ +----+-----------+------------------------+-------+--------+
+ | 0 | Sand1 | POINT (0.256 264.862) | 0.26 | 264.86 |
+ +----+-----------+------------------------+-------+--------+
+ | 1 | Sand1 | POINT (10.593 276.734) | 10.59 | 276.73 |
+ +----+-----------+------------------------+-------+--------+
+ | 2 | Sand1 | POINT (17.135 289.090) | 17.13 | 289.09 |
+ +----+-----------+------------------------+-------+--------+
+ | 3 | Sand1 | POINT (19.150 293.313) | 19.15 | 293.31 |
+ +----+-----------+------------------------+-------+--------+
+ | 4 | Sand1 | POINT (27.795 310.572) | 27.80 | 310.57 |
+ +----+-----------+------------------------+-------+--------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
>>> # Loading Libraries and File
@@ -383,27 +509,43 @@ def extract_xy_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Sand1 LINESTRING (0.256 264.862, 10.593 276.734, 17....
- 1 None Ton LINESTRING (0.188 495.787, 8.841 504.142, 41.0...
- 2 None Ton LINESTRING (970.677 833.053, 959.372 800.023, ...
+
+ +----+-----------+-----------+----------------------------------------------------+
+ | | id | formation | geometry |
+ +----+-----------+-----------+----------------------------------------------------+
+ | 0 | None | Sand1 | LINESTRING (0.256 264.862, 10.593 276.734, 17.... |
+ +----+-----------+----------------------------------------------------------------+
+ | 1 | None | Ton | LINESTRING (0.188 495.787, 8.841 504.142, 41.0... |
+ +----+-----------+----------------------------------------------------------------+
+ | 2 | None | Ton | LINESTRING (970.677 833.053, 959.372 800.023, ... |
+ +----+-----------+----------------------------------------------------------------+
>>> # Extracting X and Y Coordinates from LineString Objects
>>> gdf_xy = gg.vector.extract_xy_linestrings(gdf=gdf, reset_index=False)
>>> gdf_xy
- formation geometry X Y
- 0 Sand1 POINT (0.256 264.862) 0.26 264.86
- 1 Sand1 POINT (10.593 276.734) 10.59 276.73
- 2 Sand1 POINT (17.135 289.090) 17.13 289.09
- 3 Sand1 POINT (19.150 293.313) 19.15 293.31
- 4 Sand1 POINT (27.795 310.572) 27.80 310.57
+
+ +----+-----------+------------------------+-------+--------+
+ | | formation | geometry | X | Y |
+ +----+-----------+------------------------+-------+--------+
+ | 0 | Sand1 | POINT (0.256 264.862) | 0.26 | 264.86 |
+ +----+-----------+------------------------+-------+--------+
+ | 1 | Sand1 | POINT (10.593 276.734) | 10.59 | 276.73 |
+ +----+-----------+------------------------+-------+--------+
+ | 2 | Sand1 | POINT (17.135 289.090) | 17.13 | 289.09 |
+ +----+-----------+------------------------+-------+--------+
+ | 3 | Sand1 | POINT (19.150 293.313) | 19.15 | 293.31 |
+ +----+-----------+------------------------+-------+--------+
+ | 4 | Sand1 | POINT (27.795 310.572) | 27.80 | 310.57 |
+ +----+-----------+------------------------+-------+--------+
See Also
________
- extract_xy_points : Extracting X and Y coordinates from a GeoDataFrame containing Shapely Points
- extract_xy_linestring : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
+
+ extract_xy : Extract X and Y coordinates from Vector Data
+ extract_xy_points : Extract X and Y coordinates from a GeoDataFrame containing Shapely Points
+ extract_xy_linestring : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
saving the X and Y coordinates as lists for each LineString
- extract_xy : Extracting X and Y coordinates from Vector Data
+
Note
____
@@ -413,68 +555,70 @@ def extract_xy_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
# Checking that gdf is of type GepDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Check that all entries of the gdf are of type LineString
if not all(shapely.get_type_id(gdf.geometry) == 1):
- raise TypeError('All GeoDataFrame entries must be of geom_type linestrings')
+ raise TypeError("All GeoDataFrame entries must be of geom_type linestrings")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that the bbox is of type None or list
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that the target_crs is of type string
if target_crs is not None and not isinstance(target_crs, (str, pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Checking that overwrite_xy is of type bool
if not isinstance(overwrite_xy, bool):
- raise TypeError('Overwrite_xy argument must be of type bool')
+ raise TypeError("Overwrite_xy argument must be of type bool")
# Checking if overwrite_xy is False and if X and Y coordinates are already present in the GeoDataFrame
- if not overwrite_xy and {'X', 'Y'}.issubset(gdf.columns):
- raise ValueError('X and Y columns must not be present in GeoDataFrame before the extraction of coordinates')
+ if not overwrite_xy and {"X", "Y"}.issubset(gdf.columns):
+ raise ValueError(
+ "X and Y columns must not be present in GeoDataFrame before the extraction of coordinates"
+ )
# Copying GeoDataFrame
gdf = gdf.copy(deep=True)
@@ -488,79 +632,81 @@ def extract_xy_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
# Extracting x,y coordinates from line vector data
if all(shapely.has_z(gdf.geometry)):
- gdf['points'] = [shapely.get_coordinates(geometry=gdf.geometry[i],
- include_z=True) for i in range(len(gdf))]
+ gdf["points"] = [
+ shapely.get_coordinates(geometry=gdf.geometry[i], include_z=True)
+ for i in range(len(gdf))
+ ]
else:
- gdf['points'] = [shapely.get_coordinates(geometry=gdf.geometry[i],
- include_z=False) for i in range(len(gdf))]
+ gdf["points"] = [
+ shapely.get_coordinates(geometry=gdf.geometry[i], include_z=False)
+ for i in range(len(gdf))
+ ]
# Creating DataFrame from exploded columns
- df = pd.DataFrame(data=gdf).explode('points')
+ df = pd.DataFrame(data=gdf).explode("points")
# Try creating the DataFrame for planar LineStrings
if not all(shapely.has_z(gdf.geometry)):
- df[['X', 'Y']] = pd.DataFrame(data=df['points'].tolist(),
- index=df.index)
+ df[["X", "Y"]] = pd.DataFrame(data=df["points"].tolist(), index=df.index)
# If LineStrings also contain Z value, then also append a Z column
else:
- df[['X', 'Y', 'Z']] = pd.DataFrame(data=df['points'].tolist(),
- index=df.index)
+ df[["X", "Y", "Z"]] = pd.DataFrame(data=df["points"].tolist(), index=df.index)
# Resetting index
if reset_index:
df = df.reset_index()
# Creating new GeoDataFrame
- gdf = gpd.GeoDataFrame(data=df,
- geometry=gpd.points_from_xy(df.X, df.Y),
- crs=crs)
+ gdf = gpd.GeoDataFrame(data=df, geometry=gpd.points_from_xy(df.X, df.Y), crs=crs)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
return gdf
-def extract_xy(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- overwrite_xy: bool = True,
- target_crs: Union[str, pyproj.crs.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None,
- remove_total_bounds: bool = False,
- threshold_bounds: Union[float, int] = 0.1) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings, Polygons, Geometry
+def extract_xy(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ overwrite_xy: bool = True,
+ target_crs: Union[str, pyproj.crs.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+ remove_total_bounds: bool = False,
+ threshold_bounds: Union[float, int] = 0.1,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings, Polygons, Geometry
Collections) and returning a GeoDataFrame with X and Y coordinates as additional columns
Parameters
@@ -568,62 +714,89 @@ def extract_xy(gdf: gpd.geodataframe.GeoDataFrame,
gdf : gpd.geodataframe.GeoDataFrame
GeoDataFrame created from vector data such as Shapely Points, LineStrings, MultiLineStrings or Polygons or
- data loaded from disc with GeoPandas (i.e. Shape File)
-
- reset_index : bool
+ data loaded from disc with GeoPandas (i.e. Shape File).
+
+ +----+-----------+------------------------+
+ | id | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | None | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | None | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | None | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | None | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | None | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
+
+
+ reset_index : bool, default: ``True``
Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
+ drop_level0 : bool, default: ``True``
Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
+ drop_level1 : bool, default: ``True``
Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
+ drop_index : bool, default: ``True``
Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
+ drop_id : bool, default: ``True``
Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
+ drop_points : bool, default: ``True``
Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- overwrite_xy : bool
+ overwrite_xy : bool, default: ``False``
Variable to overwrite existing X and Y values.
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
target_crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : list
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
- remove_total_bounds: bool
+ remove_total_bounds: bool, default: ``False``
Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
- threshold_bounds : Union[float, int]
+ threshold_bounds : Union[float, int], default: ``0.1``
Variable to set the distance to the total bound from where vertices are being removed,
- e.g. ``threshold_bounds=10``, default set to ``0.1``
+ e.g. ``threshold_bounds=10``, default set to ``0.1``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame with appended x, y columns and Point geometry features
+ GeoDataFrame with appended x, y columns and Point geometry features.
+
+ +----+-----------+------------------------+--------+--------+
+ | ID | formation | geometry | X | Y |
+ +----+-----------+------------------------+--------+--------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31 |
+ +----+-----------+------------------------+--------+--------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46 |
+ +----+-----------+------------------------+--------+--------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36 | 480.95 |
+ +----+-----------+------------------------+--------+--------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81 | 616.00 |
+ +----+-----------+------------------------+--------+--------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32 | 719.09 |
+ +----+-----------+------------------------+--------+--------+
.. versionadded:: 1.0.x
- .. versionchanged:: 1.1
- If a GeoDataFrame contains LineStrings and MultiLineStrings, the index of the exploded GeoDataFrame will now
- be reset. Not resetting the index will cause index errors later on.
+ .. versionchanged:: 1.2
Example
_______
@@ -633,108 +806,128 @@ def extract_xy(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Ton POINT (19.150 293.313)
- 1 None Ton POINT (61.934 381.459)
- 2 None Ton POINT (109.358 480.946)
- 3 None Ton POINT (157.812 615.999)
- 4 None Ton POINT (191.318 719.094)
+
+ +----+-----------+------------------------+
+ | id | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | None | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | None | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | None | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | None | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | None | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
+
>>> # Extracting X and Y Coordinates from Shapely Base Geometries
>>> gdf_xy = gg.vector.extract_xy(gdf=gdf, reset_index=False)
>>> gdf_xy
- formation geometry X Y
- 0 Ton POINT (19.150 293.313) 19.15 293.31
- 1 Ton POINT (61.934 381.459) 61.93 381.46
- 2 Ton POINT (109.358 480.946) 109.36 480.95
- 3 Ton POINT (157.812 615.999) 157.81 616.00
- 4 Ton POINT (191.318 719.094) 191.32 719.09
+
+ +----+-----------+------------------------+--------+--------+
+ | ID | formation | geometry | X | Y |
+ +----+-----------+------------------------+--------+--------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31 |
+ +----+-----------+------------------------+--------+--------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46 |
+ +----+-----------+------------------------+--------+--------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36 | 480.95 |
+ +----+-----------+------------------------+--------+--------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81 | 616.00 |
+ +----+-----------+------------------------+--------+--------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32 | 719.09 |
+ +----+-----------+------------------------+--------+--------+
+
See Also
________
- extract_xy_points : Extracting X and Y coordinates from a GeoDataFrame containing Shapely Points
- extract_xy_linestring : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
+ extract_xy_points : Extract X and Y coordinates from a GeoDataFrame containing Shapely Points
+ extract_xy_linestring : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings and
saving the X and Y coordinates as lists for each LineString
- extract_xy_linestrings : Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
-
+ extract_xy_linestrings : Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings
Note
____
GeoDataFrames that contain multiple types of geometries are currently not supported. Please use
- ``gdf = gdf.explode().reset_index(drop=True)`` to create a GeoDataFrame with only one type of geometries
-
- """
+ ``gdf = gdf.explode().reset_index(drop=True)`` to create a GeoDataFrame with only one type of geometries.
+ """
# Input object must be a GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that overwrite_xy is of type bool
if not isinstance(overwrite_xy, bool):
- raise TypeError('Overwrite_xy argument must be of type bool')
+ raise TypeError("Overwrite_xy argument must be of type bool")
# Checking that X and Y columns are not in the GeoDataFrame
- if not overwrite_xy and {'X', 'Y'}.issubset(gdf.columns):
- raise ValueError('X and Y columns must not be present in GeoDataFrame before the extraction of coordinates')
+ if not overwrite_xy and {"X", "Y"}.issubset(gdf.columns):
+ raise ValueError(
+ "X and Y columns must not be present in GeoDataFrame before the extraction of coordinates"
+ )
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that the bbox fulfills all criteria
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that the target_crs is of type string
if not isinstance(target_crs, (str, type(None), pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Checking that remove_total_bounds is of type bool
if not isinstance(remove_total_bounds, bool):
- raise TypeError('Remove_total_bounds argument must be of type bool')
+ raise TypeError("Remove_total_bounds argument must be of type bool")
# Checking that threshold_bounds is of type float or int
if not isinstance(threshold_bounds, (float, int)):
- raise TypeError('The value for the threshold for removing the total bounds must be of type float or int')
+ raise TypeError(
+ "The value for the threshold for removing the total bounds must be of type float or int"
+ )
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Copying GeoDataFrame
gdf = gdf.copy(deep=True)
@@ -747,88 +940,95 @@ def extract_xy(gdf: gpd.geodataframe.GeoDataFrame,
crs = gdf.crs
# Exploding polygons to collection and saving total bounds
- if all(gdf.geom_type == 'Polygon'):
+ if all(gdf.geom_type == "Polygon"):
total_bounds = gdf.total_bounds
gdf = explode_polygons(gdf=gdf)
else:
total_bounds = None
# Exploding GeometryCollections to single geometry objects
- if any(gdf.geom_type == 'GeometryCollection'):
- gdf = explode_geometry_collections(gdf=gdf,
- reset_index=True,
- drop_level0=True,
- drop_level1=True,
- remove_points=True)
+ if any(gdf.geom_type == "GeometryCollection"):
+ gdf = explode_geometry_collections(
+ gdf=gdf,
+ reset_index=True,
+ drop_level0=True,
+ drop_level1=True,
+ remove_points=True,
+ )
# Converting MultiLineString to LineString for further processing
- if gdf.geom_type.isin(('MultiLineString', 'LineString')).all():
- gdf = explode_multilinestrings(gdf=gdf,
- reset_index=True,
- drop_level0=False,
- drop_level1=False)
+ if gdf.geom_type.isin(("MultiLineString", "LineString")).all():
+ gdf = explode_multilinestrings(
+ gdf=gdf, reset_index=True, drop_level0=False, drop_level1=False
+ )
# Extracting x,y coordinates from line vector data
if all(gdf.geom_type == "LineString"):
- gdf = extract_xy_linestrings(gdf=gdf,
- reset_index=False,
- drop_id=False,
- drop_index=False,
- drop_points=False,
- overwrite_xy=overwrite_xy,
- target_crs=crs,
- bbox=bbox)
+ gdf = extract_xy_linestrings(
+ gdf=gdf,
+ reset_index=False,
+ drop_id=False,
+ drop_index=False,
+ drop_points=False,
+ overwrite_xy=overwrite_xy,
+ target_crs=crs,
+ bbox=bbox,
+ )
# Extracting x,y coordinates from point vector data
elif all(gdf.geom_type == "Point"):
- gdf = extract_xy_points(gdf=gdf,
- reset_index=False,
- drop_id=False,
- overwrite_xy=overwrite_xy,
- target_crs=crs,
- bbox=bbox)
+ gdf = extract_xy_points(
+ gdf=gdf,
+ reset_index=False,
+ drop_id=False,
+ overwrite_xy=overwrite_xy,
+ target_crs=crs,
+ bbox=bbox,
+ )
else:
- raise TypeError('Input Geometry Type not supported')
+ raise TypeError("Input Geometry Type not supported")
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
# Removing the total bounds from the gdf
if remove_total_bounds and total_bounds is not None:
- gdf = gdf[~(gdf['X'] <= total_bounds[0] + threshold_bounds) &
- ~(gdf['X'] >= total_bounds[2] - threshold_bounds) &
- ~(gdf['Y'] <= total_bounds[1] + threshold_bounds) &
- ~(gdf['Y'] >= total_bounds[3] - threshold_bounds)]
+ gdf = gdf[
+ ~(gdf["X"] <= total_bounds[0] + threshold_bounds)
+ & ~(gdf["X"] >= total_bounds[2] - threshold_bounds)
+ & ~(gdf["Y"] <= total_bounds[1] + threshold_bounds)
+ & ~(gdf["Y"] >= total_bounds[3] - threshold_bounds)
+ ]
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
# Checking and setting the dtypes of the GeoDataFrame
gdf = set_dtype(gdf=gdf)
@@ -840,23 +1040,43 @@ def extract_xy(gdf: gpd.geodataframe.GeoDataFrame,
###############################################################
-def extract_xyz_points(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X, Y, and Z coordinates from a GeoDataFrame containing Shapely Points with Z components
+def extract_xyz_points(
+ gdf: gpd.geodataframe.GeoDataFrame,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X, Y, and Z coordinates from a GeoDataFrame containing Shapely Points with Z components.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely Points with X, Y, and Z components
+ GeoDataFrame containing Shapely Points with X, Y, and Z components.
+
+ +----+-----------------------------------+
+ | | geometry |
+ +----+-----------------------------------+
+ | 0 | POINT Z (1.00000 2.00000 4.00000) |
+ +----+-----------------------------------+
+ | 1 | POINT Z (1.00000 2.00000 4.00000) |
+ +----+-----------------------------------+
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely Points with appended X, Y, and Z columns
+ GeoDataFrame containing Shapely Points with appended X, Y, and Z columns.
+
+ +----+-----------------------------------+-------+-------+-------+
+ | ID | geometry | X | Y | Z |
+ +----+-----------------------------------+-------+-------+-------+
+ | 0 | POINT Z (1.00000 2.00000 4.00000) | 1.00 | 2.00 | 4.00 |
+ +----+-----------------------------------+-------+-------+-------+
+ | 1 | POINT Z (1.00000 2.00000 4.00000) | 1.00 | 2.00 | 4.00 |
+ +----+-----------------------------------+-------+-------+-------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -866,88 +1086,121 @@ def extract_xyz_points(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.G
>>> import geopandas as gpd
>>> point = Point(1,2,4)
>>> point.wkt
- 'POINT Z (0 0 0)'
+ 'POINT Z (1 2 4)'
>>> # Creating GeoDataFrame from Point
>>> gdf = gpd.GeoDataFrame(geometry=[point, point])
>>> gdf
- geometry
- 0 POINT Z (0.00000 0.00000 0.00000)
- 1 POINT Z (0.00000 0.00000 0.00000)
+
+ +----+-----------------------------------+
+ | | geometry |
+ +----+-----------------------------------+
+ | 0 | POINT Z (1.00000 2.00000 4.00000) |
+ +----+-----------------------------------+
+ | 1 | POINT Z (1.00000 2.00000 4.00000) |
+ +----+-----------------------------------+
>>> # Extracting X, Y, and Z Coordinates from Point Objects
>>> gdf = gg.vector.extract_xyz_points(gdf=gdf)
>>> gdf
- geometry X Y Z
- 0 POINT Z (1.00000 2.00000 3.00000) 1.00 2.00 3.00
- 1 POINT Z (1.00000 2.00000 3.00000) 1.00 2.00 3.00
+
+ +----+-----------------------------------+-------+-------+-------+
+ | ID | geometry | X | Y | Z |
+ +----+-----------------------------------+-------+-------+-------+
+ | 0 | POINT Z (1.00000 2.00000 4.00000) | 1.00 | 2.00 | 4.00 |
+ +----+-----------------------------------+-------+-------+-------+
+ | 1 | POINT Z (1.00000 2.00000 4.00000) | 1.00 | 2.00 | 4.00 |
+ +----+-----------------------------------+-------+-------+-------+
See Also
________
- extract_xyz_linestrings: Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings with
- Z components
- extract_xyz_polygons: Extracting X and Y coordinates from a GeoDataFrame containing Shapely Polygons with Z
- component
+ extract_xyz_linestrings: Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings with
+ Z components.
+ extract_xyz_polygons: Extract X and Y coordinates from a GeoDataFrame containing Shapely Polygons with Z
+ component.
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that all geometry objects are points
- if not all(gdf.geom_type == 'Point'):
- raise TypeError('All geometry objects must be Shapely Points')
+ if not all(gdf.geom_type == "Point"):
+ raise TypeError("All geometry objects must be Shapely Points")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that all points have a z component
if not all(shapely.has_z(gdf.geometry)):
- raise TypeError('Not all Shapely Objects have a z component')
+ raise TypeError("Not all Shapely Objects have a z component")
# Appending coordinates
- gdf['X'] = shapely.get_x(gdf.geometry)
- gdf['Y'] = shapely.get_y(gdf.geometry)
- gdf['Z'] = shapely.get_z(gdf.geometry)
+ gdf["X"] = shapely.get_x(gdf.geometry)
+ gdf["Y"] = shapely.get_y(gdf.geometry)
+ gdf["Z"] = shapely.get_z(gdf.geometry)
return gdf
-def extract_xyz_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_index: bool = True) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X, Y, and Z coordinates from a GeoDataFrame containing Shapely LineStrings with Z components
+def extract_xyz_linestrings(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_index: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X, Y, and Z coordinates from a GeoDataFrame containing Shapely LineStrings with Z components.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely LineStrings with X, Y, and Z components
+ GeoDataFrame containing Shapely LineStrings with X, Y, and Z components.
+
+ +----+-----------------------------------------------------+
+ | | geometry |
+ +----+-----------------------------------------------------+
+ | 0 | LINESTRING Z (1.00000 2.00000 3.00000, 4.00000 ...) |
+ +----+-----------------------------------------------------+
+ | 1 | LINESTRING Z (1.00000 2.00000 3.00000, 4.00000 ...) |
+ +----+-----------------------------------------------------+
- reset_index : bool
+ reset_index : bool, default: ``True``
Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
+ drop_index : bool, default: ``True``
Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely Points with appended X, Y, and Z columns
+ GeoDataFrame containing Shapely Points with appended X, Y, and Z columns.
+
+ +----+------------------------+----------------+-------+-------+-------+
+ | | geometry | points | X | Y | Z |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 0 | POINT (1.00000 2.00000)| (1.0, 2.0, 3.0)| 1.00 | 2.00 | 3.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 1 | POINT (4.00000 5.00000)| (4.0, 5.0, 6.0)| 4.00 | 5.00 | 6.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 2 | POINT (1.00000 2.00000)| (1.0, 2.0, 3.0)| 1.00 | 2.00 | 3.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 3 | POINT (4.00000 5.00000)| (4.0, 5.0, 6.0)| 4.00 | 5.00 | 6.00 |
+ +----+------------------------+----------------+-------+-------+-------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -962,108 +1215,147 @@ def extract_xyz_linestrings(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Creating GeoDataFrame from LineString
>>> gdf = gpd.GeoDataFrame(geometry=[linestring, linestring])
>>> gdf
- geometry
- 0 LINESTRING Z (1.00000 2.00000 3.00000, 4.00000...
- 1 LINESTRING Z (1.00000 2.00000 3.00000, 4.00000...
+
+ +----+-----------------------------------------------------+
+ | | geometry |
+ +----+-----------------------------------------------------+
+ | 0 | LINESTRING Z (1.00000 2.00000 3.00000, 4.00000 ...) |
+ +----+-----------------------------------------------------+
+ | 1 | LINESTRING Z (1.00000 2.00000 3.00000, 4.00000 ...) |
+ +----+-----------------------------------------------------+
+
>>> # Extracting X, Y, and Z Coordinates from Point Objects
>>> gdf = gg.vector.extract_xyz_linestrings(gdf=gdf)
>>> gdf
- geometry points X Y Z
- 0 POINT (1.00000 2.00000) (1.0, 2.0, 3.0) 1.00 2.00 3.00
- 1 POINT (4.00000 5.00000) (4.0, 5.0, 6.0) 4.00 5.00 6.00
- 2 POINT (1.00000 2.00000) (1.0, 2.0, 3.0) 1.00 2.00 3.00
- 3 POINT (4.00000 5.00000) (4.0, 5.0, 6.0) 4.00 5.00 6.00
+
+ +----+------------------------+----------------+-------+-------+-------+
+ | | geometry | points | X | Y | Z |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 0 | POINT (1.00000 2.00000)| (1.0, 2.0, 3.0)| 1.00 | 2.00 | 3.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 1 | POINT (4.00000 5.00000)| (4.0, 5.0, 6.0)| 4.00 | 5.00 | 6.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 2 | POINT (1.00000 2.00000)| (1.0, 2.0, 3.0)| 1.00 | 2.00 | 3.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 3 | POINT (4.00000 5.00000)| (4.0, 5.0, 6.0)| 4.00 | 5.00 | 6.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+
See Also
________
- extract_xyz_points: Extracting X and Y coordinates from a GeoDataFrame containing Shapely Points with
+ extract_xyz_points: Extract X and Y coordinates from a GeoDataFrame containing Shapely Points with
Z components
- extract_xyz_polygons: Extracting X and Y coordinates from a GeoDataFrame containing Shapely Polygons with Z
+ extract_xyz_polygons: Extract X and Y coordinates from a GeoDataFrame containing Shapely Polygons with Z
component
"""
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that all geometry objects are points
if not all(shapely.get_type_id(gdf.geometry) == 1):
- raise TypeError('All geometry objects must be Shapely LineStrings')
+ raise TypeError("All geometry objects must be Shapely LineStrings")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that all points have a z component
if not all(shapely.has_z(gdf.geometry)):
- raise TypeError('Not all Shapely Objects have a z component')
+ raise TypeError("Not all Shapely Objects have a z component")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Extracting x,y coordinates from line vector data
- gdf['points'] = [shapely.get_coordinates(gdf.geometry[i], include_z=True) for i in range(len(gdf))]
- df = pd.DataFrame(data=gdf).explode('points')
+ gdf["points"] = [
+ shapely.get_coordinates(gdf.geometry[i], include_z=True)
+ for i in range(len(gdf))
+ ]
+ df = pd.DataFrame(data=gdf).explode("points")
# Appending Column to DataFrame
- df[['X', 'Y', 'Z']] = pd.DataFrame(data=df['points'].tolist(),
- index=df.index)
+ df[["X", "Y", "Z"]] = pd.DataFrame(data=df["points"].tolist(), index=df.index)
# Resetting index
if reset_index:
df = df.reset_index()
# Creating new GeoDataFrame
- gdf = gpd.GeoDataFrame(data=df,
- geometry=gpd.points_from_xy(df.X, df.Y),
- crs=gdf.crs)
+ gdf = gpd.GeoDataFrame(
+ data=df, geometry=gpd.points_from_xy(df.X, df.Y), crs=gdf.crs
+ )
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
return gdf
-def extract_xyz_polygons(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_index: bool = True) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X, Y, and Z coordinates from a GeoDataFrame containing Shapely Polygons with Z components
+def extract_xyz_polygons(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_index: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X, Y, and Z coordinates from a GeoDataFrame containing Shapely Polygons with Z components.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely Polygons with X, Y, and Z components
+ GeoDataFrame containing Shapely Polygons with X, Y, and Z components.
+
+ +----+--------------------------------------------------+
+ | | geometry |
+ +----+--------------------------------------------------+
+ | 0 | POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 ... |
+ +----+--------------------------------------------------+
+ | 1 | POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 ... |
+ +----+--------------------------------------------------+
- reset_index : bool
+ reset_index : bool, default: ``True``
Variable to reset the index of the resulting GeoDataFrame.
Options include: ``True`` or ``False``, default set to ``True``
- drop_index : bool
+ drop_index : bool, default: ``True``
Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing Shapely Points with appended X, Y, and Z columns
+ GeoDataFrame containing Shapely Points with appended X, Y, and Z columns.
+
+ +----+------------------------+----------------+-------+-------+-------+
+ | ID | geometry | points | X | Y | Z |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 0 | POINT (0.00000 0.00000)| [0.0, 0.0, 1.0]| 0.00 | 0.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 1 | POINT (1.00000 0.00000)| [1.0, 0.0, 1.0]| 1.00 | 0.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 2 | POINT (1.00000 1.00000)| [1.0, 1.0, 1.0]| 1.00 | 1.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 3 | POINT (0.00000 1.00000)| [0.0, 1.0, 1.0]| 0.00 | 1.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -1078,152 +1370,183 @@ def extract_xyz_polygons(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Creating GeoDataFrame from LineString
>>> gdf = gpd.GeoDataFrame(geometry=[polygon, polygon])
>>> gdf
- geometry
- 0 POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 0...
- 1 POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 0...
+
+ +----+--------------------------------------------------+
+ | | geometry |
+ +----+--------------------------------------------------+
+ | 0 | POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 ... |
+ +----+--------------------------------------------------+
+ | 1 | POLYGON Z ((0.00000 0.00000 1.00000, 1.00000 ... |
+ +----+--------------------------------------------------+
+
>>> # Extracting X, Y, and Z Coordinates from Point Objects
>>> gdf = gg.vector.extract_xyz_polygons(gdf=gdf)
>>> gdf
- geometry points X Y Z
- 0 POINT (0.00000 0.00000) [0.0, 0.0, 1.0] 0.00 0.00 1.00
- 1 POINT (1.00000 0.00000) [1.0, 0.0, 1.0] 1.00 0.00 1.00
- 2 POINT (1.00000 1.00000) [1.0, 1.0, 1.0] 1.00 1.00 1.00
- 3 POINT (0.00000 1.00000) [0.0, 1.0, 1.0] 0.00 1.00 1.00
+
+ +----+------------------------+----------------+-------+-------+-------+
+ | ID | geometry | points | X | Y | Z |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 0 | POINT (0.00000 0.00000)| [0.0, 0.0, 1.0]| 0.00 | 0.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 1 | POINT (1.00000 0.00000)| [1.0, 0.0, 1.0]| 1.00 | 0.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 2 | POINT (1.00000 1.00000)| [1.0, 1.0, 1.0]| 1.00 | 1.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+ | 3 | POINT (0.00000 1.00000)| [0.0, 1.0, 1.0]| 0.00 | 1.00 | 1.00 |
+ +----+------------------------+----------------+-------+-------+-------+
+
See Also
________
- extract_xyz_points: Extracting X and Y coordinates from a GeoDataFrame containing Shapely Points with Z
+ extract_xyz_points: Extract X and Y coordinates from a GeoDataFrame containing Shapely Points with Z
component
- extract_xyz_linestrings: Extracting X and Y coordinates from a GeoDataFrame containing Shapely LineStrings with
+ extract_xyz_linestrings: Extract X and Y coordinates from a GeoDataFrame containing Shapely LineStrings with
Z components
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that all geometry objects are points
if not all(shapely.get_type_id(gdf.geometry) == 3):
- raise TypeError('All geometry objects must be Shapely Polygons')
+ raise TypeError("All geometry objects must be Shapely Polygons")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that all points have a z component
if not all(shapely.has_z(gdf.geometry)):
- raise TypeError('Not all Shapely Objects have a z component')
+ raise TypeError("Not all Shapely Objects have a z component")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Extracting x,y coordinates from line vector data
- gdf['points'] = [shapely.get_coordinates(gdf.geometry[i], include_z=True) for i in range(len(gdf))]
- df = pd.DataFrame(data=gdf).explode('points')
+ gdf["points"] = [
+ shapely.get_coordinates(gdf.geometry[i], include_z=True)
+ for i in range(len(gdf))
+ ]
+ df = pd.DataFrame(data=gdf).explode("points")
# Appending Column to DataFrame
- df[['X', 'Y', 'Z']] = pd.DataFrame(data=df['points'].tolist(),
- index=df.index)
+ df[["X", "Y", "Z"]] = pd.DataFrame(data=df["points"].tolist(), index=df.index)
# Resetting index
if reset_index:
df = df.reset_index()
# Creating new GeoDataFrame
- gdf = gpd.GeoDataFrame(data=df,
- geometry=gpd.points_from_xy(df.X, df.Y),
- crs=gdf.crs)
+ gdf = gpd.GeoDataFrame(
+ data=df, geometry=gpd.points_from_xy(df.X, df.Y), crs=gdf.crs
+ )
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
return gdf
-def extract_xyz_rasterio(gdf: gpd.geodataframe.GeoDataFrame,
- dem: rasterio.io.DatasetReader,
- minz: float = None,
- maxz: float = None,
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- target_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None,
- remove_total_bounds: bool = False,
- threshold_bounds: Union[float, int] = 0.1
- ) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and z values
- from a rasterio object and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns
+def extract_xyz_rasterio(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ dem: rasterio.io.DatasetReader,
+ minz: float = None,
+ maxz: float = None,
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ target_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+ remove_total_bounds: bool = False,
+ threshold_bounds: Union[float, int] = 0.1,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and z values
+ from a rasterio object and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing Shapely Points, LineStrings, MultiLineStrings or Polygons
+ GeoDataFrame created from vector data containing Shapely Points, LineStrings, MultiLineStrings or Polygons.
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
dem : rasterio.io.DatasetReader
- Rasterio object containing the height values
+ Rasterio object containing the height values.
- minz : float
- Value defining the minimum elevation the data needs to be returned, e.g. ``minz=50``, default ``None``
+ minz : float, default: ``None``
+ Value defining the minimum elevation the data needs to be returned, e.g. ``minz=50``, default ``None``.
- maxz : float
- Value defining the maximum elevation the data needs to be returned, e.g. ``maxz=500``, default ``None``
+ maxz : float, default: ``None``
+ Value defining the maximum elevation the data needs to be returned, e.g. ``maxz=500``, default ``None```.
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame, default ``True``
+ reset_index : bool, default: ``True``
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level1=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column, e.g. ``drop_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
+ drop_id : bool, default: ``True``
Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
- Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_points : bool, default: ``True``
+ Variable to drop the points column, e.g. ``drop_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- target_crs : Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ target_crs : Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS], default: ``None``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
- bbox : list
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ bbox : list, default: ``None``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
- remove_total_bounds: bool
- Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons
- Options include: ``True`` or ``False``, default set to ``False``
+ remove_total_bounds: bool, default: ``False``
+ Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons,
+ e.g. ``remove_total_bounds=False``.
+ Options include: ``True`` or ``False``, default set to ``False``.
- threshold_bounds : Union[float, int]
- Variable to set the distance to the total bound from where vertices are being removed,
- e.g. ``threshold_bounds=10``, default set to ``0.1``
+ threshold_bounds : Union[float, int], default: ``0.1``
+ Variable to set the distance to the total bounds from where vertices are being removed,
+ e.g. ``threshold_bounds=10``, default set to ``0.1``.
Returns
_______
@@ -1242,12 +1565,21 @@ def extract_xyz_rasterio(gdf: gpd.geodataframe.GeoDataFrame,
>>> import rasterio
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Ton POINT (19.150 293.313)
- 1 None Ton POINT (61.934 381.459)
- 2 None Ton POINT (109.358 480.946)
- 3 None Ton POINT (157.812 615.999)
- 4 None Ton POINT (191.318 719.094)
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
+
>>> # Loading raster file
>>> dem = rasterio.open(fp='dem.tif')
@@ -1257,203 +1589,224 @@ def extract_xyz_rasterio(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Extracting X, Y, and Z Coordinates from Shapely Base Geometries and raster
>>> gdf_xyz = gg.vector.extract_xyz_rasterio(gdf=gdf, dem=dem, reset_index=reset_index)
>>> gdf_xyz
- formation geometry X Y Z
- 0 Ton POINT (19.150 293.313) 19.15 293.31 364.99
- 1 Ton POINT (61.934 381.459) 61.93 381.46 400.34
- 2 Ton POINT (109.358 480.946) 109.36 480.95 459.55
- 3 Ton POINT (157.812 615.999) 157.81 616.00 525.69
- 4 Ton POINT (191.318 719.094) 191.32 719.09 597.63
+
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | formation | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
+
See Also
________
- extract_xyz_array : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model as array
- extract_xyz : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
+ extract_xyz : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
+ extract_xyz_array : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model as array
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that the dem is a rasterio object
if not isinstance(dem, rasterio.io.DatasetReader):
- raise TypeError('DEM must be a rasterio object')
+ raise TypeError("DEM must be a rasterio object")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('MultiLineString', 'LineString', 'Point', 'Polygon', 'GeometryCollection')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported')
+ if not gdf.geom_type.isin(
+ ("MultiLineString", "LineString", "Point", "Polygon", "GeometryCollection")
+ ).all():
+ raise TypeError("Geometry type within GeoDataFrame not supported")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
# Checking that remove_total_bounds is of type bool
if not isinstance(remove_total_bounds, bool):
- raise TypeError('Remove_total_bounds argument must be of type bool')
+ raise TypeError("Remove_total_bounds argument must be of type bool")
# Checking that threshold_bounds is of type float or int
if not isinstance(threshold_bounds, (float, int)):
- raise TypeError('The value for the threshold for removing the total bounds must be of type float or int')
+ raise TypeError(
+ "The value for the threshold for removing the total bounds must be of type float or int"
+ )
# Checking the GeoDataFrame does not contain a Z value
- if 'Z' in gdf:
- raise ValueError('Data already contains Z-values')
+ if "Z" in gdf:
+ raise ValueError("Data already contains Z-values")
# Checking that the bbox fulfills all criteria
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that the target_crs is of type string
- if not isinstance(target_crs, (str, type(None), pyproj.crs.crs.CRS, rasterio.crs.CRS)):
- raise TypeError('target_crs must be of type string, pyproj CRS or rasterio CRS')
+ if not isinstance(
+ target_crs, (str, type(None), pyproj.crs.crs.CRS, rasterio.crs.CRS)
+ ):
+ raise TypeError("target_crs must be of type string, pyproj CRS or rasterio CRS")
# Checking that the minz value is of type float
if not isinstance(minz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that the max value is of type float
if not isinstance(maxz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that minz is smaller than maxz
if minz is not None and maxz is not None and minz >= maxz:
- raise ValueError('minz must be smaller than maxz')
+ raise ValueError("minz must be smaller than maxz")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Create deep copy of gdf
gdf = gdf.copy(deep=True)
# Extracting X and Y coordinates if they are not present in the GeoDataFrame
- if not {'X', 'Y'}.issubset(gdf.columns):
- gdf = extract_xy(gdf=gdf,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=False,
- target_crs=None,
- bbox=None,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
+ if not {"X", "Y"}.issubset(gdf.columns):
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=False,
+ target_crs=None,
+ bbox=None,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
# If the CRS of the gdf and the dem are identical, just extract the heights using the rasterio sample method
# NB: for points outside the bounds of the raster, nodata values will be returned
if gdf.crs == dem.crs:
- gdf['Z'] = sample_from_rasterio(raster=dem,
- point_x=gdf['X'].tolist(),
- point_y=gdf['Y'].tolist())
+ gdf["Z"] = sample_from_rasterio(
+ raster=dem, point_x=gdf["X"].tolist(), point_y=gdf["Y"].tolist()
+ )
# If the CRS of the gdf and the dem are not identical, the coordinates of the gdf will be reprojected and the
# z values will be appended to the original gdf
else:
gdf_reprojected = gdf.to_crs(crs=dem.crs)
- gdf_reprojected = extract_xy(gdf=gdf_reprojected,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=True,
- target_crs=None,
- bbox=None,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds
- )
-
- gdf['Z'] = sample_from_rasterio(raster=dem,
- point_x=gdf_reprojected['X'].tolist(),
- point_y=gdf_reprojected['Y'].tolist())
+ gdf_reprojected = extract_xy(
+ gdf=gdf_reprojected,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=True,
+ target_crs=None,
+ bbox=None,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
+
+ gdf["Z"] = sample_from_rasterio(
+ raster=dem,
+ point_x=gdf_reprojected["X"].tolist(),
+ point_y=gdf_reprojected["Y"].tolist(),
+ )
# Reprojecting coordinates to provided target_crs
if target_crs is not None:
gdf = gdf.to_crs(crs=target_crs)
# Extracting the X and Y coordinates of the reprojected gdf
- gdf = extract_xy(gdf,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=True,
- target_crs=None,
- bbox=None,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=True,
+ target_crs=None,
+ bbox=None,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
# Limiting the data to specified elevations
if minz is not None:
- gdf = gdf[gdf['Z'] >= minz]
+ gdf = gdf[gdf["Z"] >= minz]
if maxz is not None:
- gdf = gdf[gdf['Z'] <= maxz]
+ gdf = gdf[gdf["Z"] <= maxz]
# Resetting the index
if reset_index:
@@ -1465,79 +1818,94 @@ def extract_xyz_rasterio(gdf: gpd.geodataframe.GeoDataFrame,
return gdf
-def extract_xyz_array(gdf: gpd.geodataframe.GeoDataFrame,
- dem: np.ndarray,
- extent: List[float],
- minz: float = None,
- maxz: float = None,
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- target_crs: Union[str, pyproj.crs.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None,
- remove_total_bounds: bool = False,
- threshold_bounds: Union[float, int] = 0.1
- ) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and Z values from
- a NumPy nd.array and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns
+def extract_xyz_array(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ dem: np.ndarray,
+ extent: List[float],
+ minz: float = None,
+ maxz: float = None,
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ target_crs: Union[str, pyproj.crs.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+ remove_total_bounds: bool = False,
+ threshold_bounds: Union[float, int] = 0.1,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and Z values from
+ a NumPy nd.array and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing Shapely Points, LineStrings, MultiLineStrings or Polygons
+ GeoDataFrame created from vector data containing Shapely Points, LineStrings, MultiLineStrings or Polygons.
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
dem : np.ndarray
- NumPy ndarray containing the height values
+ NumPy ndarray containing the height values.
extent : list
List containing the extent of the np.ndarray,
- must be provided in the same CRS as the gdf, e.g. ``extent=[0, 972, 0, 1069]``
+ must be provided in the same CRS as the gdf, e.g. ``extent=[0, 972, 0, 1069]``.
- minz : float
- Value defining the minimum elevation the data needs to be returned, e.g. ``minz=50``, default ``None``
+ minz : float, default: ``None``
+ Value defining the minimum elevation the data needs to be returned, e.g. ``minz=50``, default ``None``.
- maxz : float
- Value defining the maximum elevation the data needs to be returned, e.g. ``maxz=500``, default ``None``
+ maxz : float, default: ``None``
+ Value defining the maximum elevation the data needs to be returned, e.g. ``maxz=500``, default ``None``.
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ reset_index : bool, default: ``None``
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level1=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column, e.g. ``drop_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
- Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_id : bool, default: ``True``
+ Variable to drop the id column, e.g. ``drop_id=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
- Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_points : bool, default: ``True``
+ Variable to drop the points column, e.g. ``drop_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
target_crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : list
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
- remove_total_bounds: bool
- Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons
- Options include: ``True`` or ``False``, default set to ``False``
+ remove_total_bounds: bool, default: ``False``
+ Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons.
+ Options include: ``True`` or ``False``, default set to ``False``.
- threshold_bounds : Union[float, int]
+ threshold_bounds : Union[float, int], default: ``0.1``
Variable to set the distance to the total bound from where vertices are being removed,
e.g. ``threshold_bounds=10``, default set to ``0.1``
@@ -1547,8 +1915,24 @@ def extract_xyz_array(gdf: gpd.geodataframe.GeoDataFrame,
gdf : gpd.geodataframe.GeoDataFrame
GeoDataFrame containing the X, Y, and Z coordinates
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | formation | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -1558,12 +1942,20 @@ def extract_xyz_array(gdf: gpd.geodataframe.GeoDataFrame,
>>> import rasterio
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Ton POINT (19.150 293.313)
- 1 None Ton POINT (61.934 381.459)
- 2 None Ton POINT (109.358 480.946)
- 3 None Ton POINT (157.812 615.999)
- 4 None Ton POINT (191.318 719.094)
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
>>> # Loading raster file
>>> dem = rasterio.open(fp='dem.tif')
@@ -1576,201 +1968,215 @@ def extract_xyz_array(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Extracting X, Y, and Z Coordinates from Shapely Base Geometries and array
>>> gdf_xyz = gg.vector.extract_xyz_array(gdf=gdf, dem=dem.read(1), extent=extent, reset_index=reset_index)
>>> gdf_xyz
- formation geometry X Y Z
- 0 Ton POINT (19.150 293.313) 19.15 293.31 364.99
- 1 Ton POINT (61.934 381.459) 61.93 381.46 400.34
- 2 Ton POINT (109.358 480.946) 109.36 480.95 459.55
- 3 Ton POINT (157.812 615.999) 157.81 616.00 525.69
- 4 Ton POINT (191.318 719.094) 191.32 719.09 597.63
+
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | formation | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
See Also
________
- extract_xyz_rasterio : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
+ extract_xyz : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
+ extract_xyz_rasterio : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
as rasterio object
- extract_xyz : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that the dem is a np.ndarray
if not isinstance(dem, np.ndarray):
- raise TypeError('DEM must be a numpy.ndarray')
+ raise TypeError("DEM must be a numpy.ndarray")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('MultiLineString', 'LineString', 'Point', 'Polygon')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported')
+ if not gdf.geom_type.isin(
+ ("MultiLineString", "LineString", "Point", "Polygon")
+ ).all():
+ raise TypeError("Geometry type within GeoDataFrame not supported")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
- # Checking that drop_id is of type bool
+ # Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that the extent is of type list
if not isinstance(extent, list):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that all elements of the extent are of type int or float
if not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ raise TypeError("Extent values must be of type int or float")
# Checking that remove_total_bounds is of type bool
if not isinstance(remove_total_bounds, bool):
- raise TypeError('Remove_total_bounds argument must be of type bool')
+ raise TypeError("Remove_total_bounds argument must be of type bool")
# Checking that threshold_bounds is of type float or int
if not isinstance(threshold_bounds, (float, int)):
- raise TypeError('The value for the threshold for removing the total bounds must be of type float or int')
+ raise TypeError(
+ "The value for the threshold for removing the total bounds must be of type float or int"
+ )
# Checking that the length of the list is either four or six
if extent is not None:
if not len(extent) == 4:
if not len(extent) == 6:
- raise ValueError('The extent must include only four or six values')
+ raise ValueError("The extent must include only four or six values")
# Checking that the bbox fulfills all criteria
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking that the target_crs is of type string
if not isinstance(target_crs, (str, type(None), pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Selecting x and y bounds if bbox contains values for all three directions x, y, z
extent = extent[:4]
# Checking that the minz value is of type float
if not isinstance(minz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that the max value is of type float
if not isinstance(maxz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that minz is smaller than maxz
if minz is not None and maxz is not None and minz >= maxz:
- raise ValueError('minz must be smaller than maxz')
+ raise ValueError("minz must be smaller than maxz")
# Checking that the GeoDataFrame does not contain a Z value
- if 'Z' in gdf:
- raise ValueError('Data already contains Z-values')
+ if "Z" in gdf:
+ raise ValueError("Data already contains Z-values")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Extracting X and Y coordinates if they are not present in the GeoDataFrame
- if not {'X', 'Y'}.issubset(gdf.columns):
- gdf = extract_xy(gdf=gdf,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=False,
- target_crs=None,
- bbox=None,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
-
- gdf['Z'] = sample_from_array(array=dem,
- extent=extent,
- point_x=gdf['X'].values,
- point_y=gdf['Y'].values)
+ if not {"X", "Y"}.issubset(gdf.columns):
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=False,
+ target_crs=None,
+ bbox=None,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
+
+ gdf["Z"] = sample_from_array(
+ array=dem, extent=extent, point_x=gdf["X"].values, point_y=gdf["Y"].values
+ )
# Reprojecting coordinates to provided target_crs
if target_crs is not None:
gdf = gdf.to_crs(crs=target_crs)
# Extracting the X and Y coordinates of the reprojected gdf
- gdf = extract_xy(gdf=gdf,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=True,
- target_crs=None,
- bbox=None,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=True,
+ target_crs=None,
+ bbox=None,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
# Limiting the data to specified elevations
if minz is not None:
- gdf = gdf[gdf['Z'] >= minz]
+ gdf = gdf[gdf["Z"] >= minz]
if maxz is not None:
- gdf = gdf[gdf['Z'] <= maxz]
+ gdf = gdf[gdf["Z"] <= maxz]
# Checking and setting the dtypes of the GeoDataFrame
gdf = set_dtype(gdf=gdf)
@@ -1778,24 +2184,25 @@ def extract_xyz_array(gdf: gpd.geodataframe.GeoDataFrame,
return gdf
-def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
- dem: Union[np.ndarray, rasterio.io.DatasetReader] = None,
- minz: float = None,
- maxz: float = None,
- extent: List[Union[float, int]] = None,
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- target_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
- bbox: Optional[Sequence[float]] = None,
- remove_total_bounds: bool = False,
- threshold_bounds: Union[float, int] = 0.1
- ) -> gpd.geodataframe.GeoDataFrame:
- """Extracting X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and Z values from
- a NumPy nd.array or a Rasterio object and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns
+def extract_xyz(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ dem: Union[np.ndarray, rasterio.io.DatasetReader] = None,
+ minz: float = None,
+ maxz: float = None,
+ extent: List[Union[float, int]] = None,
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ target_crs: Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS] = None,
+ bbox: Optional[Sequence[float]] = None,
+ remove_total_bounds: bool = False,
+ threshold_bounds: Union[float, int] = 0.1,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Extract X and Y coordinates from a GeoDataFrame (Points, LineStrings, MultiLineStrings Polygons) and Z values from
+ a NumPy nd.array or a Rasterio object and returning a GeoDataFrame with X, Y, and Z coordinates as additional columns.
Parameters
__________
@@ -1805,55 +2212,69 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
dem : Union[np.ndarray, rasterio.io.DatasetReader]
NumPy ndarray or Rasterio object containing the height values, default value is None in case geometries
- contain Z values
-
- minz : float
- Value defining the minimum elevation of the data that needs to be returned, e.g. ``minz=50``, default ``None``
-
- maxz : float
- Value defining the maximum elevation of the data that needs to be returned, e.g. ``maxz=500``, default ``None``
+ contain Z values.
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
+
+ minz : float, default: ``None``
+ Value defining the minimum elevation of the data that needs to be returned, e.g. ``minz=50``, default ``None``.
+
+ maxz : float, default: ``None``
+ Value defining the maximum elevation of the data that needs to be returned, e.g. ``maxz=500``, default ``None``.
extent : List[Union[float,int]]
List containing the extent of the np.ndarray,
- must be provided in the same CRS as the gdf, e.g. ``extent=[0, 972, 0, 1069]``
+ must be provided in the same CRS as the gdf, e.g. ``extent=[0, 972, 0, 1069]``.
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ reset_index : bool, default: ``True``
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level1=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column, e.g. ``drop_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
- Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_id : bool, default: ``True``
+ Variable to drop the id column, e.g. ``drop_id=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
- Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_points : bool, default: ``True``
+ Variable to drop the points column, e.g. ``drop_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
target_crs : Union[str, pyproj.crs.crs.CRS, rasterio.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``target_crs='EPSG:4647'``.
bbox : list
- Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``
+ Values (minx, maxx, miny, maxy) to limit the extent of the data, e.g. ``bbox=[0, 972, 0, 1069]``.
- remove_total_bounds: bool
- Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons
- Options include: ``True`` or ``False``, default set to ``False``
+ remove_total_bounds: bool, default: ``False``
+ Variable to remove the vertices representing the total bounds of a GeoDataFrame consisting of Polygons.
+ Options include: ``True`` or ``False``, default set to ``False``.
- threshold_bounds : Union[float, int]
+ threshold_bounds : Union[float, int], default: ``0.1``
Variable to set the distance to the total bound from where vertices are being removed,
- e.g. ``threshold_bounds=10``, default set to ``0.1``
+ e.g. ``threshold_bounds=10``, default set to ``0.1``.
Returns
_______
@@ -1861,8 +2282,24 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
gdf : gpd.geodataframe.GeoDataFrame
GeoDataFrame containing the X, Y, and Z coordinates as additional columns
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | formation | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
+
.. versionadded:: 1.0.x
+ .. versionchanged.: 1.2
+
Example
_______
@@ -1872,12 +2309,20 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
>>> import rasterio
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id formation geometry
- 0 None Ton POINT (19.150 293.313)
- 1 None Ton POINT (61.934 381.459)
- 2 None Ton POINT (109.358 480.946)
- 3 None Ton POINT (157.812 615.999)
- 4 None Ton POINT (191.318 719.094)
+
+ +----+-----------+------------------------+
+ | | formation | geometry |
+ +----+-----------+------------------------+
+ | 0 | Ton | POINT (19.150 293.313) |
+ +----+-----------+------------------------+
+ | 1 | Ton | POINT (61.934 381.459) |
+ +----+-----------+------------------------+
+ | 2 | Ton | POINT (109.358 480.946)|
+ +----+-----------+------------------------+
+ | 3 | Ton | POINT (157.812 615.999)|
+ +----+-----------+------------------------+
+ | 4 | Ton | POINT (191.318 719.094)|
+ +----+-----------+------------------------+
>>> # Loading raster file
>>> dem = rasterio.open(fp='dem.tif')
@@ -1887,74 +2332,87 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Extracting X, Y, and Z Coordinates from Shapely Base Geometries and DEM
>>> gdf_xyz = gg.vector.extract_xyz(gdf=gdf, dem=dem, reset_index=reset_index)
>>> gdf_xyz
- formation geometry X Y Z
- 0 Ton POINT (19.150 293.313) 19.15 293.31 364.99
- 1 Ton POINT (61.934 381.459) 61.93 381.46 400.34
- 2 Ton POINT (109.358 480.946) 109.36 480.95 459.55
- 3 Ton POINT (157.812 615.999) 157.81 616.00 525.69
- 4 Ton POINT (191.318 719.094) 191.32 719.09 597.63
+
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | formation | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | Ton | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | Ton | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | Ton | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | Ton | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | Ton | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
See Also
________
- extract_xyz_array : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model as array
- extract_xyz_rasterio : Extracting X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation
+ extract_xyz_array : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation Model as array
+ extract_xyz_rasterio : Extract X, Y, and Z coordinates from a GeoDataFrame and Digital Elevation
as rasterio object
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that the dem is a np.ndarray or rasterio object
if not isinstance(dem, (np.ndarray, rasterio.io.DatasetReader, type(None))):
- raise TypeError('DEM must be a numpy.ndarray or rasterio object')
+ raise TypeError("DEM must be a numpy.ndarray or rasterio object")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('MultiLineString', 'LineString', 'Point', 'Polygon', 'GeometryCollection')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported')
+ if not gdf.geom_type.isin(
+ ("MultiLineString", "LineString", "Point", "Polygon", "GeometryCollection")
+ ).all():
+ raise TypeError("Geometry type within GeoDataFrame not supported")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that the target_crs is of type string
- if not isinstance(target_crs, (str, type(None), pyproj.crs.crs.CRS, rasterio.crs.CRS)):
- raise TypeError('target_crs must be of type string, pyproj CRS or rasterio CRS')
+ if not isinstance(
+ target_crs, (str, type(None), pyproj.crs.crs.CRS, rasterio.crs.CRS)
+ ):
+ raise TypeError("target_crs must be of type string, pyproj CRS or rasterio CRS")
# Checking that the extent is of type list
if isinstance(dem, np.ndarray) and not isinstance(extent, list):
- raise TypeError('Extent must be of type list')
+ raise TypeError("Extent must be of type list")
# Checking that all elements of the extent are of type int or float
- if isinstance(dem, np.ndarray) and not all(isinstance(n, (int, float)) for n in extent):
- raise TypeError('Extent values must be of type int or float')
+ if isinstance(dem, np.ndarray) and not all(
+ isinstance(n, (int, float)) for n in extent
+ ):
+ raise TypeError("Extent values must be of type int or float")
# Checking that the length of the list is either four or six
if extent is not None:
if len(extent) not in (4, 6):
- raise ValueError('The extent must include only four or six values')
+ raise ValueError("The extent must include only four or six values")
# Selecting x and y bounds if bbox contains values for all three directions x, y, z
if isinstance(dem, np.ndarray) and len(extent) == 6:
@@ -1962,41 +2420,43 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
# Checking that the minz value is of type float
if not isinstance(minz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that the max value is of type float
if not isinstance(maxz, (float, int, type(None))):
- raise TypeError('minz value must be of type float or int')
+ raise TypeError("minz value must be of type float or int")
# Checking that minz is smaller than maxz
if minz is not None and maxz is not None and minz >= maxz:
- raise ValueError('minz must be smaller than maxz')
+ raise ValueError("minz must be smaller than maxz")
# Checking that the bbox fulfills all criteria
if bbox is not None:
if not isinstance(bbox, Sequence):
- raise TypeError('The bbox values must be provided as a sequence')
+ raise TypeError("The bbox values must be provided as a sequence")
# Checking that the bbox list only has four elements
if len(bbox) != 4:
- raise ValueError('Provide minx, maxx, miny and maxy values for the bbox')
+ raise ValueError("Provide minx, maxx, miny and maxy values for the bbox")
# Checking that all elements of the list are of type int or float
if not all(isinstance(bound, (int, float)) for bound in bbox):
- raise TypeError('Bbox values must be of type float or int')
+ raise TypeError("Bbox values must be of type float or int")
# Checking the GeoDataFrame does not contain a Z value
- if 'Z' in gdf and dem is not None:
- raise ValueError('Data already contains Z-values. Please use dem=None to indicate that no DEM is needed or '
- 'remove Z values.')
+ if "Z" in gdf and dem is not None:
+ raise ValueError(
+ "Data already contains Z-values. Please use dem=None to indicate that no DEM is needed or "
+ "remove Z values."
+ )
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Reprojecting coordinates to provided target_crs
if target_crs is not None:
@@ -2004,84 +2464,92 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
# Extracting xyz
if isinstance(dem, rasterio.io.DatasetReader):
- gdf = extract_xyz_rasterio(gdf=gdf,
- dem=dem,
- reset_index=False,
- drop_id=False,
- drop_index=False,
- drop_level0=False,
- drop_level1=False,
- drop_points=False,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
+ gdf = extract_xyz_rasterio(
+ gdf=gdf,
+ dem=dem,
+ reset_index=False,
+ drop_id=False,
+ drop_index=False,
+ drop_level0=False,
+ drop_level1=False,
+ drop_points=False,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
elif isinstance(dem, np.ndarray):
- gdf = extract_xyz_array(gdf=gdf,
- dem=dem,
- extent=extent,
- reset_index=False,
- drop_id=False,
- drop_index=False,
- drop_level0=False,
- drop_level1=False,
- drop_points=False,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds)
+ gdf = extract_xyz_array(
+ gdf=gdf,
+ dem=dem,
+ extent=extent,
+ reset_index=False,
+ drop_id=False,
+ drop_index=False,
+ drop_level0=False,
+ drop_level1=False,
+ drop_points=False,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
# Extracting XYZ from point consisting of a Z value
- elif all(shapely.has_z(gdf.geometry)) and all(shapely.get_type_id(gdf.geometry) == 0):
+ elif all(shapely.has_z(gdf.geometry)) and all(
+ shapely.get_type_id(gdf.geometry) == 0
+ ):
gdf = extract_xyz_points(gdf=gdf)
else:
- gdf = extract_xy(gdf=gdf,
- reset_index=False,
- drop_id=False,
- drop_index=False,
- drop_level0=False,
- drop_level1=False,
- drop_points=False,
- remove_total_bounds=remove_total_bounds,
- threshold_bounds=threshold_bounds
- )
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_id=False,
+ drop_index=False,
+ drop_level0=False,
+ drop_level1=False,
+ drop_points=False,
+ remove_total_bounds=remove_total_bounds,
+ threshold_bounds=threshold_bounds,
+ )
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points', axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
# Limiting the extent of the data
if bbox is not None:
- gdf = gdf[(gdf.X > bbox[0]) & (gdf.X < bbox[1]) & (gdf.Y > bbox[2]) & (gdf.Y < bbox[3])]
+ gdf = gdf[
+ (gdf.X > bbox[0])
+ & (gdf.X < bbox[1])
+ & (gdf.Y > bbox[2])
+ & (gdf.Y < bbox[3])
+ ]
# Limiting the data to specified elevations
if minz is not None:
- gdf = gdf[gdf['Z'] >= minz]
+ gdf = gdf[gdf["Z"] >= minz]
if maxz is not None:
- gdf = gdf[gdf['Z'] <= maxz]
+ gdf = gdf[gdf["Z"] <= maxz]
# Checking and setting the dtypes of the GeoDataFrame
gdf = set_dtype(gdf=gdf)
@@ -2092,24 +2560,29 @@ def extract_xyz(gdf: gpd.geodataframe.GeoDataFrame,
# Exploding Geometries
###############################################################
-def explode_linestring(linestring: shapely.geometry.linestring.LineString) -> List[shapely.geometry.point.Point]:
- """Exploding a LineString to its vertices, also works for LineStrings with Z components
+
+def explode_linestring(
+ linestring: shapely.geometry.linestring.LineString,
+) -> List[shapely.geometry.point.Point]:
+ """Explode a LineString to its vertices, also works for LineStrings with Z components.
Parameters
__________
linestring : shapely.geometry.linestring.LineString
Shapely LineString from which vertices are extracted,
- e.g. ``linestring = LineString([(0, 0), (10, 10), (20, 20)])``
+ e.g. ``linestring = LineString([(0, 0), (10, 10), (20, 20)])``.
Returns
_______
points_list : List[shapely.geometry.point.Point]
- List of extracted Shapely Points
+ List of extracted Shapely Points.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2142,21 +2615,20 @@ def explode_linestring(linestring: shapely.geometry.linestring.LineString) -> Li
See Also
________
- explode_linestring_to_elements : Exploding a LineString with more than two vertices into single LineStrings
+ explode_linestring_to_elements : Explode a LineString with more than two vertices into single LineStrings
"""
-
# Checking that the input geometry is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapely LineString')
+ raise TypeError("Input geometry must be a Shapely LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Extracting Points of LineString
points_list = [geometry.Point(i) for i in list(linestring.coords)]
@@ -2164,26 +2636,29 @@ def explode_linestring(linestring: shapely.geometry.linestring.LineString) -> Li
return points_list
-def explode_linestring_to_elements(linestring: shapely.geometry.linestring.LineString) -> \
- List[shapely.geometry.linestring.LineString]:
- """Separating a LineString into its single elements and returning a list of LineStrings representing these elements,
- also works for LineStrings with Z components
+def explode_linestring_to_elements(
+ linestring: shapely.geometry.linestring.LineString,
+) -> List[shapely.geometry.linestring.LineString]:
+ """Separate a LineString into its single elements and returning a list of LineStrings representing these elements,
+ also works for LineStrings with Z components.
Parameters
__________
- linestring : linestring: shapely.geometry.linestring.LineString
+ linestring : shapely.geometry.linestring.LineString
Shapely LineString containing more than two vertices,
- e.g. ``linestring = LineString([(0, 0), (10, 10), (20, 20)])``
+ e.g. ``linestring = LineString([(0, 0), (10, 10), (20, 20)])``.
Returns
_______
splitted_linestrings : List[shapely.geometry.linestring.LineString]
- List containing the separate elements of the original LineString stored as LineStrings
+ List containing the separate elements of the original LineString stored as LineStrings.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2211,52 +2686,58 @@ def explode_linestring_to_elements(linestring: shapely.geometry.linestring.LineS
See Also
________
- explode_linestring : Exploding a LineString into its single vertices
+ explode_linestring : Explode a LineString into its single vertices
"""
-
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapely LineString')
+ raise TypeError("Input geometry must be a Shapely LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) < 2:
- raise ValueError('LineString must contain at least two vertices')
+ raise ValueError("LineString must contain at least two vertices")
# Splitting the LineString into single elements and returning a list of LineStrings
splitted_linestrings = list(
- map(shapely.geometry.linestring.LineString, zip(linestring.coords[:-1], linestring.coords[1:])))
+ map(
+ shapely.geometry.linestring.LineString,
+ zip(linestring.coords[:-1], linestring.coords[1:]),
+ )
+ )
return splitted_linestrings
-def explode_multilinestring(multilinestring: shapely.geometry.multilinestring.MultiLineString) \
- -> List[shapely.geometry.linestring.LineString]:
- """Exploding a MultiLineString into a list of LineStrings
+def explode_multilinestring(
+ multilinestring: shapely.geometry.multilinestring.MultiLineString,
+) -> List[shapely.geometry.linestring.LineString]:
+ """Explode a MultiLineString into a list of LineStrings.
Parameters
__________
multilinestring : shapely.geometry.multilinestring.MultiLineString
Shapely MultiLineString consisting of multiple LineStrings,
- e.g. ``multilinestring = MultiLineString([((0, 0), (1, 1)), ((-1, 0), (1, 0))])``
+ e.g. ``multilinestring = MultiLineString([((0, 0), (1, 1)), ((-1, 0), (1, 0))])``.
Returns
_______
splitted_multilinestring : List[shapely.geometry.linestring.LineString]
- List of Shapely LineStrings
+ List of Shapely LineStrings.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2284,26 +2765,27 @@ def explode_multilinestring(multilinestring: shapely.geometry.multilinestring.Mu
See Also
________
- explode_multilinestrings : Exploding a GeoDataFrame containing MultiLineStrings into a GeoDataFrame containing
+ explode_multilinestrings : Explode a GeoDataFrame containing MultiLineStrings into a GeoDataFrame containing
LineStrings only
"""
-
# Checking that the MultiLineString is a Shapely MultiLineString
- if not isinstance(multilinestring, shapely.geometry.multilinestring.MultiLineString):
- raise TypeError('MultiLineString must be a Shapely MultiLineString')
+ if not isinstance(
+ multilinestring, shapely.geometry.multilinestring.MultiLineString
+ ):
+ raise TypeError("MultiLineString must be a Shapely MultiLineString")
# Checking that the MultiLineString is valid
if not multilinestring.is_valid:
- raise ValueError('MultiLineString is not a valid object')
+ raise ValueError("MultiLineString is not a valid object")
# Checking that the MultiLineString is not empty
if multilinestring.is_empty:
- raise ValueError('MultiLineString is an empty object')
+ raise ValueError("MultiLineString is an empty object")
# Checking that there is at least one LineString in the MultiLineString
if len(list(multilinestring.geoms)) < 1:
- raise ValueError('MultiLineString must at least contain one LineString')
+ raise ValueError("MultiLineString must at least contain one LineString")
# Creating a list of single LineStrings from MultiLineString
splitted_multilinestring = list(multilinestring.geoms)
@@ -2311,39 +2793,62 @@ def explode_multilinestring(multilinestring: shapely.geometry.multilinestring.Mu
return splitted_multilinestring
-def explode_multilinestrings(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- ) -> gpd.geodataframe.GeoDataFrame:
- """Exploding Shapely MultiLineStrings stored in a GeoDataFrame to Shapely LineStrings
+def explode_multilinestrings(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Explode Shapely MultiLineStrings stored in a GeoDataFrame to Shapely LineStrings.
Parameters
----------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type MultiLineString
+ GeoDataFrame created from vector data containing elements of ``geom_type`` MultiLineString.
+
+ +----+----------------------------------------+
+ | | geometry |
+ +----+----------------------------------------+
+ | 0 | MULTILINESTRING ((0.0 0.0, 1.0 1.0)) |
+ +----+----------------------------------------+
+ | 1 | MULTILINESTRING ((0.0 0.0, 1.0 1.0)) |
+ +----+----------------------------------------+
- reset_index : bool
+ reset_index : bool, default: ``True``
Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
+ drop_level0 : bool, default: ``True``
Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
+ drop_level1 : bool, default: ``True``
Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
-------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing LineStrings
+ GeoDataFrame containing LineStrings.
+
+ +----+------------------------------+
+ | ID | geometry |
+ +----+------------------------------+
+ | 0 | LINESTRING (0.0 0.0, 1.0 1.0)|
+ +----+------------------------------+
+ | 1 | LINESTRING (-1.0 0.0, 1.0 0.0)|
+ +----+------------------------------+
+ | 2 | LINESTRING (0.0 0.0, 1.0 1.0)|
+ +----+------------------------------+
+ | 3 | LINESTRING (-1.0 0.0, 1.0 0.0)|
+ +----+------------------------------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2352,53 +2857,68 @@ def explode_multilinestrings(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- geometry
- 0 MULTILINESTRING ((0.0 0.0, 1.0 1.0))
- 1 MULTILINESTRING ((0.0 0.0, 1.0 1.0))
+
+ +----+----------------------------------------+
+ | | geometry |
+ +----+----------------------------------------+
+ | 0 | MULTILINESTRING ((0.0 0.0, 1.0 1.0)) |
+ +----+----------------------------------------+
+ | 1 | MULTILINESTRING ((0.0 0.0, 1.0 1.0)) |
+ +----+----------------------------------------+
+
>>> # Exploding MultiLineStrings into single LineStrings
>>> gdf_linestrings = gg.vector.explode_multilinestrings(gdf=gdf, reset_index=True)
>>> gdf_linestrings
- geometry
- 0 LINESTRING (0.0 0.0, 1.0 1.0)
- 1 LINESTRING (-1.0 0.0, 1.0 0.0)
- 2 LINESTRING (0.0 0.0, 1.0 1.0)
- 3 LINESTRING (-1.0 0.0, 1.0 0.0)
+
+ +----+------------------------------+
+ | ID | geometry |
+ +----+------------------------------+
+ | 0 | LINESTRING (0.0 0.0, 1.0 1.0)|
+ +----+------------------------------+
+ | 1 | LINESTRING (-1.0 0.0, 1.0 0.0)|
+ +----+------------------------------+
+ | 2 | LINESTRING (0.0 0.0, 1.0 1.0)|
+ +----+------------------------------+
+ | 3 | LINESTRING (-1.0 0.0, 1.0 0.0)|
+ +----+------------------------------+
+
See Also
________
- explode_multilinestring : Exploding a MultiLineString into a list of single LineStrings
+ explode_multilinestring : Explode a MultiLineString into a list of single LineStrings
"""
-
# Checking that gdf is of type GepDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Check that all entries of the gdf are of type MultiLineString or LineString
- if not all(gdf.geom_type.isin(['MultiLineString', 'LineString'])):
- raise TypeError('All GeoDataFrame entries must be of geom_type MultiLineString or LineString')
+ if not all(gdf.geom_type.isin(["MultiLineString", "LineString"])):
+ raise TypeError(
+ "All GeoDataFrame entries must be of geom_type MultiLineString or LineString"
+ )
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Exploding MultiLineStrings
gdf = gdf.explode(index_parts=True)
@@ -2409,34 +2929,36 @@ def explode_multilinestrings(gdf: gpd.geodataframe.GeoDataFrame,
# Dropping level_0 column
if reset_index and drop_level0:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
if reset_index and drop_level1:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ gdf = gdf.drop(columns="level_1", axis=1)
return gdf
-def explode_polygon(polygon: shapely.geometry.polygon.Polygon) -> List[shapely.geometry.point.Point]:
- """Exploding Shapely Polygon to list of Points
+def explode_polygon(
+ polygon: shapely.geometry.polygon.Polygon,
+) -> List[shapely.geometry.point.Point]:
+ """Explode Shapely Polygon to list of Points.
Parameters
__________
polygon : shapely.geometry.polygon.Polygon
- Shapely Polygon from which vertices are extracted, e.g. ``polygon = Polygon([(0, 0), (1, 1), (1, 0)])``
+ Shapely Polygon from which vertices are extracted, e.g. ``polygon = Polygon([(0, 0), (1, 1), (1, 0)])``.
Returns
_______
point_list : List[shapely.geometry.point.Point]
- List containing the vertices of a polygon as Shapely Points
+ List containing the vertices of a polygon as Shapely Points.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2466,44 +2988,63 @@ def explode_polygon(polygon: shapely.geometry.polygon.Polygon) -> List[shapely.g
See Also
________
- explode_polygons : Exploding a GeoDataFrame containing Polygons into a GeoDataFrame containing LineStrings
+ explode_polygons : Explode a GeoDataFrame containing Polygons into a GeoDataFrame containing LineStrings
"""
-
# Checking that the input polygon is a Shapely object
if not isinstance(polygon, shapely.geometry.polygon.Polygon):
- raise TypeError('Polygon must be a Shapely Polygon')
+ raise TypeError("Polygon must be a Shapely Polygon")
# Checking that all Shapely Objects are valid
if not polygon.is_valid:
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if polygon.is_empty:
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
points_list = [geometry.Point(point) for point in list(polygon.exterior.coords)]
return points_list
-def explode_polygons(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.GeoDataFrame:
- """Converting a GeoDataFrame containing elements of geom_type Polygons to a GeoDataFrame with LineStrings
+def explode_polygons(
+ gdf: gpd.geodataframe.GeoDataFrame,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Convert a GeoDataFrame containing elements of ``geom_type`` Polygon to a GeoDataFrame with LineStrings.
Parameters
___________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type Polygon
+ GeoDataFrame created from vector data containing elements of ``geom_type`` Polygon.
+
+ +----+------------------------------------------------+
+ | | geometry |
+ +----+------------------------------------------------+
+ | 0 | POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)) |
+ +----+------------------------------------------------+
+ | 1 | POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)) |
+ +----+------------------------------------------------+
Returns
_______
gdf_linestrings : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing elements of type MultiLineString and LineString
+ GeoDataFrame containing elements of type MultiLineString and LineString.
+
+ +----+-------------------------------------------------+
+ | | geometry |
+ +----+-------------------------------------------------+
+ | 0 | LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0) |
+ +----+-------------------------------------------------+
+ | 1 | LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0) |
+ +----+-------------------------------------------------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2512,68 +3053,79 @@ def explode_polygons(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.Geo
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- geometry
- 0 POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0))
- 1 POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0))
+
+ +----+------------------------------------------------+
+ | | geometry |
+ +----+------------------------------------------------+
+ | 0 | POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)) |
+ +----+------------------------------------------------+
+ | 1 | POLYGON ((0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)) |
+ +----+------------------------------------------------+
+
>>> # Exploding Polygons into LineStrings
>>> gdf_exploded = gg.vector.explode_polygons(gdf=gdf)
>>> gdf_exploded
- geometry
- 0 LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)
- 1 LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0)
+ +----+-------------------------------------------------+
+ | | geometry |
+ +----+-------------------------------------------------+
+ | 0 | LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0) |
+ +----+-------------------------------------------------+
+ | 1 | LINESTRING (0.0 0.0, 1.0 1.0, 1.0 0.0, 0.0 0.0) |
+ +----+-------------------------------------------------+
See Also
________
- explode_polygon : Exploding a Polygon into single Points
+ explode_polygon : Explod a Polygon into single Points
"""
-
# Checking that the input is a GeoDataFrame:
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be a GeoDataFrame')
+ raise TypeError("gdf must be a GeoDataFrame")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('Polygon', 'MultiPolygon')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported')
+ if not gdf.geom_type.isin(("Polygon", "MultiPolygon")).all():
+ raise TypeError("Geometry type within GeoDataFrame not supported")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Creating GeoDataFrame containing only LineStrings and appending remaining columns as Pandas DataFrame
- gdf_linestrings = gpd.GeoDataFrame(data=gdf.drop(columns='geometry',
- axis=1),
- geometry=gdf.boundary,
- crs=gdf.crs)
+ gdf_linestrings = gpd.GeoDataFrame(
+ data=gdf.drop(columns="geometry", axis=1), geometry=gdf.boundary, crs=gdf.crs
+ )
return gdf_linestrings
-def explode_geometry_collection(collection: shapely.geometry.collection.GeometryCollection) \
- -> List[shapely.geometry.base.BaseGeometry]:
- """Exploding a Shapely Geometry Collection to a List of Base Geometries
+def explode_geometry_collection(
+ collection: shapely.geometry.collection.GeometryCollection,
+) -> List[shapely.geometry.base.BaseGeometry]:
+ """Explode a Shapely Geometry Collection to a List of Base Geometries.
Parameters
__________
collection : shapely.geometry.collection.GeometryCollection
- Shapely Geometry Collection consisting of different Base Geometries
+ Shapely Geometry Collection consisting of different Base Geometries.
Returns
_______
collection_exploded : List[shapely.geometry.base.BaseGeometry]
- List of Base Geometries from the original Geometry Collection
+ List of Base Geometries from the original Geometry Collection.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2603,21 +3155,20 @@ def explode_geometry_collection(collection: shapely.geometry.collection.Geometry
See Also
________
- explode_geometry_collections : Exploding a GeoDataFrame containing different Base Geometries
+ explode_geometry_collections : Explode a GeoDataFrame containing different Base Geometries
"""
-
# Checking that the Geometry Collection is a Shapely Geometry Collection
if not isinstance(collection, shapely.geometry.collection.GeometryCollection):
- raise TypeError('Geometry Collection must be a Shapely Geometry Collection')
+ raise TypeError("Geometry Collection must be a Shapely Geometry Collection")
# Checking that the Geometry Collection is valid
if not collection.is_valid:
- raise ValueError('Geometry Collection is not a valid object')
+ raise ValueError("Geometry Collection is not a valid object")
# Checking that the Geometry Collection is not empty
if collection.is_empty:
- raise ValueError('Geometry Collection is an empty object')
+ raise ValueError("Geometry Collection is an empty object")
# Creating list of Base Geometries
collection_exploded = list(collection.geoms)
@@ -2625,44 +3176,71 @@ def explode_geometry_collection(collection: shapely.geometry.collection.Geometry
return collection_exploded
-def explode_geometry_collections(gdf: gpd.geodataframe.GeoDataFrame,
- reset_index: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True,
- remove_points: bool = True,
- ) -> gpd.geodataframe.GeoDataFrame:
- """Exploding Shapely Geometry Collections stored in GeoDataFrames to different Shapely Base Geometries
+def explode_geometry_collections(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ reset_index: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+ remove_points: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Explode Shapely Geometry Collections stored in a GeoDataFrame to different Shapely Base Geometries.
Parameters
----------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame created from vector data containing elements of geom_type GeometryCollection
-
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
-
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
-
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
-
- remove_points : bool
- Variable to remove points from exploded GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ GeoDataFrame created from vector data containing elements of geom_type GeometryCollection.
+
+ +----+--------------------------------------------------------------+
+ | | geometry |
+ +----+--------------------------------------------------------------+
+ | 0 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+--------------------------------------------------------------+
+ | 1 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+--------------------------------------------------------------+
+ | 2 | GEOMETRYCOLLECTION (POINT (2.00000 2.00000), LINESTRING ...) |
+ +----+--------------------------------------------------------------+
+ | 3 | POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1...) |
+ +----+--------------------------------------------------------------+
+
+ reset_index : bool, default: ``True``>
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
+
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
+
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level1=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
+
+ remove_points : bool, default: ``True``
+ Variable to remove points from exploded GeoDataFrame, e.g. ``remove_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
-------
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing different geometry types
+ GeoDataFrame containing different geometry types.
+
+ +----+----------------------------------------------------+
+ | | geometry |
+ +----+----------------------------------------------------+
+ | 0 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+----------------------------------------------------+
+ | 1 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+----------------------------------------------------+
+ | 2 | LINESTRING (0.00000 0.00000, 1.00000 1.00000) |
+ +----+----------------------------------------------------+
+ | 3 | POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1...) |
+ +----+----------------------------------------------------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -2678,62 +3256,76 @@ def explode_geometry_collections(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Creating GeoDataFrame from Base Geometries
>>> gdf = gpd.GeoDataFrame(geometry=[a, b, collection, polygon])
>>> gdf
- geometry
- 0 LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...
- 1 LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...
- 2 GEOMETRYCOLLECTION (POINT (2.00000 2.00000), L...
- 3 POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1..
+
+ +----+--------------------------------------------------------------+
+ | | geometry |
+ +----+--------------------------------------------------------------+
+ | 0 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+--------------------------------------------------------------+
+ | 1 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+--------------------------------------------------------------+
+ | 2 | GEOMETRYCOLLECTION (POINT (2.00000 2.00000), LINESTRING ...) |
+ +----+--------------------------------------------------------------+
+ | 3 | POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1...) |
+ +----+--------------------------------------------------------------+
+
>>> # Explode Geometry Collection into single Base Geometries
>>> gdf_exploded = gg.vector.explode_geometry_collections(gdf=gdf)
>>> gdf_exploded
- geometry
- 0 LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...
- 1 LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...
- 2 LINESTRING (0.00000 0.00000, 1.00000 1.00000)
- 3 POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1...
+
+ +----+----------------------------------------------------+
+ | | geometry |
+ +----+----------------------------------------------------+
+ | 0 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+----------------------------------------------------+
+ | 1 | LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...) |
+ +----+----------------------------------------------------+
+ | 2 | LINESTRING (0.00000 0.00000, 1.00000 1.00000) |
+ +----+----------------------------------------------------+
+ | 3 | POLYGON ((0.00000 0.00000, 10.00000 0.00000, 1...) |
+ +----+----------------------------------------------------+
See Also
________
- explode_geometry_collection : Exploding a Shapely Geometry Collection Object into a list of Base Geometries
+ explode_geometry_collection : Explod a Shapely Geometry Collection Object into a list of Base Geometries
"""
-
# Checking that gdf is of type GepDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Check that all entries of the gdf are of type MultiLineString or LineString
if not any(gdf.geom_type == "GeometryCollection"):
- raise TypeError('At least one geometry entry must be GeometryCollection')
+ raise TypeError("At least one geometry entry must be GeometryCollection")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Exploding MultiLineStrings
gdf = gdf.explode(index_parts=True)
# Remove Point geometries
if remove_points:
- gdf = gdf[np.invert(gdf.geom_type == 'Point')]
+ gdf = gdf[np.invert(gdf.geom_type == "Point")]
# Resetting the index
if reset_index:
@@ -2741,13 +3333,11 @@ def explode_geometry_collections(gdf: gpd.geodataframe.GeoDataFrame,
# Dropping level_0 column
if reset_index and drop_level0:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
if reset_index and drop_level1:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ gdf = gdf.drop(columns="level_1", axis=1)
return gdf
@@ -2755,28 +3345,43 @@ def explode_geometry_collections(gdf: gpd.geodataframe.GeoDataFrame,
# Creating LineStrings with Z components from points
####################################################
-def create_linestring_from_xyz_points(points: Union[np.ndarray, gpd.geodataframe.GeoDataFrame],
- nodata: Union[int, float] = 9999.0,
- xcol: str = 'X',
- ycol: str = 'Y',
- zcol: str = 'Z',
- drop_nan: bool = True) -> shapely.geometry.linestring.LineString:
- """
- Create LineString from an array or GeoDataFrame containing X, Y, and Z coordinates of points.
+
+def create_linestring_from_xyz_points(
+ points: Union[np.ndarray, gpd.geodataframe.GeoDataFrame],
+ nodata: Union[int, float] = 9999.0,
+ xcol: str = "X",
+ ycol: str = "Y",
+ zcol: str = "Z",
+ drop_nan: bool = True,
+) -> shapely.geometry.linestring.LineString:
+ """Create LineString from an array or GeoDataFrame containing X, Y, and Z coordinates of points.
Parameters
__________
points : Union[np.ndarray, gpd.geodataframe.GeoDataFrame]
NumPy Array or GeoDataFrame containing XYZ points.
- nodata : Union[int, float])
+
+ +----+-------+-------+-------+
+ | | X | Y | Z |
+ +----+-------+-------+-------+
+ | 0 | 3.23 | 5.69 | 2.03 |
+ +----+-------+-------+-------+
+ | 1 | 3.24 | 5.68 | 2.02 |
+ +----+-------+-------+-------+
+ | 2 | 3.25 | 5.67 | 1.97 |
+ +----+-------+-------+-------+
+ | 3 | 3.26 | 5.66 | 1.95 |
+ +----+-------+-------+-------+
+
+ nodata : Union[int, float]), default: ``9999.0``
Nodata value to filter out points outside a designated area, e.g. ``nodata=9999.0``, default is ``9999.0``.
- xcol : str
+ xcol : str, default: ``'X'``
Name of the X column in the dataset, e.g. ``xcol='X'``, default is ``'X'``.
- ycol : str
+ ycol : str, default: ``'Y'``
Name of the Y column in the dataset, e.g. ``ycol='Y'``, default is ``'Y'``.
- zcol : str
+ zcol : str, default: ``'Z'``
Name of the Z column in the dataset, e.g. ``zcol='Z'``, default is ``'Z'``.
- drop_nan : bool
+ drop_nan : bool, default: ``True``
Boolean argument to drop points that contain a ``nan`` value as Z value. Options include ``True`` and
``False``, default is ``True``.
@@ -2784,12 +3389,11 @@ def create_linestring_from_xyz_points(points: Union[np.ndarray, gpd.geodataframe
_______
line : shapely.geometry.linestring.LineString
- LineString Z constructed from provided point values
+ LineString Z constructed from provided point values.
.. versionadded:: 1.0.x
- .. versionchanged:: 1.1
- Adding argument `drop_nan` and code to drop coordinates that contain ``nan`` values as Z coordinates.
+ .. versionchanged:: 1.2
Example
_______
@@ -2798,34 +3402,56 @@ def create_linestring_from_xyz_points(points: Union[np.ndarray, gpd.geodataframe
>>> import gemgis as gg
>>> import numpy as np
>>> points = np.array([[3.23, 5.69, 2.03],[3.24, 5.68, 2.02],[3.25, 5.67, 1.97],[3.26, 5.66, 1.95]])
+ >>> points
+
+ +----+-------+-------+-------+
+ | | X | Y | Z |
+ +----+-------+-------+-------+
+ | 0 | 3.23 | 5.69 | 2.03 |
+ +----+-------+-------+-------+
+ | 1 | 3.24 | 5.68 | 2.02 |
+ +----+-------+-------+-------+
+ | 2 | 3.25 | 5.67 | 1.97 |
+ +----+-------+-------+-------+
+ | 3 | 3.26 | 5.66 | 1.95 |
+ +----+-------+-------+-------+
+
>>> # Creating LineStrings from points
>>> linestring = gg.vector.create_linestring_from_xyz_points(points=points)
>>> linestring.wkt
'LINESTRING Z (3.23 5.69 2.03, 3.24 5.68 2.02, 3.25 5.67 1.97, 3.26 5.66 1.95)'
+
+ See Also
+ ________
+
+ create_linestrings_from_xyz_points : Create LineStrings from a GeoDataFrame containing X, Y, and Z coordinates of vertices of multiple LineStrings
+
"""
# Checking that the points are of type GeoDataFrame or a NumPy array
if not isinstance(points, (np.ndarray, gpd.geodataframe.GeoDataFrame)):
- raise TypeError('Input points must either be provided as GeoDataFrame or NumPy array')
+ raise TypeError(
+ "Input points must either be provided as GeoDataFrame or NumPy array"
+ )
# Checking of geometry objects are valid and converting GeoDataFrame to array
if isinstance(points, gpd.geodataframe.GeoDataFrame):
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(points.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(points.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that all geometry objects are of type point
if not all(shapely.get_type_id(points.geometry) == 0):
- raise TypeError('All geometry objects must be of geom type Point')
+ raise TypeError("All geometry objects must be of geom type Point")
# Checking that the Z column are present in GeoDataFrame
if zcol not in points:
- raise ValueError('Z values could not be found')
+ raise ValueError("Z values could not be found")
# Extract X and Y coordinates from GeoDataFrame
if not {xcol, ycol}.issubset(points.columns):
@@ -2840,7 +3466,7 @@ def create_linestring_from_xyz_points(points: Union[np.ndarray, gpd.geodataframe
# Checking that the NumPy array has the right dimensions
if points.shape[1] != 3:
- raise ValueError('Array must contain 3 values, X, Y, and Z values')
+ raise ValueError("Array must contain 3 values, X, Y, and Z values")
# Getting indices where nodata values are present
indices_nodata = np.where(points == nodata)[0]
@@ -2857,55 +3483,71 @@ def create_linestring_from_xyz_points(points: Union[np.ndarray, gpd.geodataframe
return linestring
-def create_linestrings_from_xyz_points(gdf: gpd.geodataframe.GeoDataFrame,
- groupby: str,
- nodata: Union[int, float] = 9999.0,
- xcol: str = 'X',
- ycol: str = 'Y',
- zcol: str = 'Z',
- dem: Union[np.ndarray, rasterio.io.DatasetReader] = None,
- extent: List[Union[float, int]] = None,
- return_gdf: bool = True,
- drop_nan: bool = True) -> Union[List[shapely.geometry.linestring.LineString],
- gpd.geodataframe.GeoDataFrame]:
- """Creating LineStrings from a GeoDataFrame containing X, Y, and Z coordinates of vertices of multiple LineStrings
+def create_linestrings_from_xyz_points(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ groupby: str,
+ nodata: Union[int, float] = 9999.0,
+ xcol: str = "X",
+ ycol: str = "Y",
+ zcol: str = "Z",
+ dem: Union[np.ndarray, rasterio.io.DatasetReader] = None,
+ extent: List[Union[float, int]] = None,
+ return_gdf: bool = True,
+ drop_nan: bool = True,
+) -> Union[List[shapely.geometry.linestring.LineString], gpd.geodataframe.GeoDataFrame]:
+ """Create LineStrings from a GeoDataFrame containing X, Y, and Z coordinates of vertices of multiple LineStrings.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing extracted X, Y, and Z coordinates of LineStrings
+ GeoDataFrame containing extracted X, Y, and Z coordinates of LineStrings.
+
+ +----+-----------+------------------------+-------+-------+-------+
+ | ID | Object_ID | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | 1 | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | 1 | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | 1 | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | 2 | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | 2 | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
+
groupby : str
- Name of a unique identifier the LineStrings can be separated from each other, e.g. ``groupby='Object_ID'``
+ Name of a unique identifier the LineStrings can be separated from each other, e.g. ``groupby='Object_ID'``.
- nodata : Union[int, float])
- Nodata value to filter out points outside a designated area, e.g. ``nodata=9999.0``, default is ``9999.0``
+ nodata : Union[int, float]), default: ``9999.0``
+ Nodata value to filter out points outside a designated area, e.g. ``nodata=9999.0``, default is ``9999.0``.
- xcol : str
- Name of the X column in the dataset, e.g. ``xcol='X'``, default is ``'X'``
+ xcol : str, default: ``'X'``
+ Name of the X column in the dataset, e.g. ``xcol='X'``, default is ``'X'``.
- ycol : str
- Name of the Y column in the dataset, e.g. ``ycol='Y'``, default is ``'Y'``
+ ycol : str, default: ``'Y'``
+ Name of the Y column in the dataset, e.g. ``ycol='Y'``, default is ``'Y'``.
- zcol : str
- Name of the Z column in the dataset, e.g. ``zcol='Z'``, default is ``'Z'``
+ zcol : str, default: ``'Z'``
+ Name of the Z column in the dataset, e.g. ``zcol='Z'``, default is ``'Z'``.
- dem : Union[np.ndarray, rasterio.io.DatasetReader]
+ dem : Union[np.ndarray, rasterio.io.DatasetReader], default: ``None``
NumPy ndarray or rasterio object containing the height values, default value is ``None`` in case geometries
- contain Z values
+ contain Z values.
- extent : List[Union[float, int]]
+ extent : List[Union[float, int]], default: ``None``
Values for minx, maxx, miny and maxy values to define the boundaries of the raster,
- e.g. ``extent=[0, 972, 0, 1069]``
+ e.g. ``extent=[0, 972, 0, 1069]``, default is ``None``.
- return_gdf : bool
- Variable to either return the data as GeoDataFrame or as list of LineStrings.
- Options include: ``True`` or ``False``, default set to ``True``
+ return_gdf : bool, default: ``True``
+ Variable to either return the data as GeoDataFrame or as list of LineStrings, e.g. ``return_gdf=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_nan : bool
- Boolean argument to drop points that contain a ``nan`` value as Z value. Options include ``True`` and
- ``False``, default is ``True``
+ drop_nan : bool, default: ``True``
+ Boolean argument to drop points that contain a ``nan`` value as Z value, e.g. ``drop_nan=True``
+ Options include ``True`` and ``False``, default is ``True``.
Returns
_______
@@ -2915,9 +3557,7 @@ def create_linestrings_from_xyz_points(gdf: gpd.geodataframe.GeoDataFrame,
.. versionadded:: 1.0.x
- .. versionchanged:: 1.1
- Removed manual dropping of additional columns. Now automatically drops unnecessary coloumns.
- Adding argument `drop_nan` and code to drop coordinates that contain ``nan`` values as Z coordinates.
+ .. versionchanged:: 1.2
Example
_______
@@ -2928,57 +3568,86 @@ def create_linestrings_from_xyz_points(gdf: gpd.geodataframe.GeoDataFrame,
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
+ +----+-----------+------------------------+-------+-------+-------+
+ | | Object_ID | geometry | X | Y | Z |
+ +----+-----------+------------------------+-------+-------+-------+
+ | 0 | 1 | POINT (19.150 293.313) | 19.15 | 293.31| 364.99|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 1 | 1 | POINT (61.934 381.459) | 61.93 | 381.46| 400.34|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 2 | 1 | POINT (109.358 480.946)| 109.36| 480.95| 459.55|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 3 | 2 | POINT (157.812 615.999)| 157.81| 616.00| 525.69|
+ +----+-----------+------------------------+-------+-------+-------+
+ | 4 | 2 | POINT (191.318 719.094)| 191.32| 719.09| 597.63|
+ +----+-----------+------------------------+-------+-------+-------+
+
>>> # Creating LineStrings with Z component from gdf
>>> gdf_linestring = gg.vector.create_linestrings_from_xyz_points(gdf=gdf, groupby='ABS')
>>> gdf_linestring
+ +----+-----------+----------------------------------------------------------------------+
+ | | formation | geometry |
+ +----+-----------+----------------------------------------------------------------------+
+ | 0 | 1 | LINESTRING Z (19.150 293.310 364.990, 61.930 381.459 400.340, ...) |
+ +----+-----------+----------------------------------------------------------------------+
+ | 1 | 2 | LINESTRING Z (157.810 616.000 525.690, 191.320 719.094 597.630, ...) |
+ +----+-----------+----------------------------------------------------------------------+
- """
+ See Also
+ ________
+ create_linestring_from_xyz_points : Create LineString from an array or GeoDataFrame containing X, Y, and Z coordinates of points.
+ """
# Checking that the input is a GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Input must be provided as GeoDataFrame')
+ raise TypeError("Input must be provided as GeoDataFrame")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('LineString', 'Point')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported, only Point or LineString allowed')
+ if not gdf.geom_type.isin(("LineString", "Point")).all():
+ raise TypeError(
+ "Geometry type within GeoDataFrame not supported, only Point or LineString allowed"
+ )
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that return gdfs is of type bool
if not isinstance(return_gdf, bool):
- raise TypeError('Return_gdf argument must be of type bool')
+ raise TypeError("Return_gdf argument must be of type bool")
# Checking that the GeoDataFrame contains Z values
if zcol not in gdf:
# Checking that the provided DEM is not of type None
if not isinstance(dem, (np.ndarray, rasterio.io.DatasetReader)):
- raise TypeError('Provide DEM as array or rasterio object to extract coordinates')
+ raise TypeError(
+ "Provide DEM as array or rasterio object to extract coordinates"
+ )
# Extracting Z values from dem
- gdf = extract_xyz(gdf=gdf,
- dem=dem,
- extent=extent)
+ gdf = extract_xyz(gdf=gdf, dem=dem, extent=extent)
# Checking if X and Y are in GeoDataFrame
- if not {'X', 'Y'}.issubset(gdf.columns):
- gdf = extract_xy(gdf=gdf,
- reset_index=True)
+ if not {"X", "Y"}.issubset(gdf.columns):
+ gdf = extract_xy(gdf=gdf, reset_index=True)
# Creating list of GeoDataFrames for the creating of LineStrings
- list_gdfs = [gdf.groupby(by=groupby).get_group(group) for group in gdf[groupby].unique()]
+ list_gdfs = [
+ gdf.groupby(by=groupby).get_group(group) for group in gdf[groupby].unique()
+ ]
# Creating LineString for each GeoDataFrame in list_gdfs
- list_linestrings = [create_linestring_from_xyz_points(points=geodf,
- drop_nan=drop_nan) for geodf in list_gdfs]
+ list_linestrings = [
+ create_linestring_from_xyz_points(points=geodf, drop_nan=drop_nan)
+ for geodf in list_gdfs
+ ]
# Creating boolean list of empty geometries
bool_empty_lines = [i.is_empty for i in list_linestrings]
@@ -2987,48 +3656,95 @@ def create_linestrings_from_xyz_points(gdf: gpd.geodataframe.GeoDataFrame,
indices_empty_lines = np.where(bool_empty_lines)[0].tolist()
# Removing emtpy LineStrings from list of LineStrings by index
- list_linestrings_new = [i for j, i in enumerate(list_linestrings) if j not in indices_empty_lines]
+ list_linestrings_new = [
+ i for j, i in enumerate(list_linestrings) if j not in indices_empty_lines
+ ]
# Removing GeoDataFrames at the indices of empty LineStrings
list_gdfs_new = [i for j, i in enumerate(list_gdfs) if j not in indices_empty_lines]
# Returning list of LineStrings as GeoDataFrame
if return_gdf:
- list_lines = [gpd.GeoDataFrame(
- data=pd.DataFrame(data=list_gdfs_new[i].tail(1).drop(['geometry', xcol, ycol, zcol], axis=1)),
- geometry=[list_linestrings_new[i]]) for i in range(len(list_linestrings_new))]
+ list_lines = [
+ gpd.GeoDataFrame(
+ data=pd.DataFrame(
+ data=list_gdfs_new[i]
+ .tail(1)
+ .drop(["geometry", xcol, ycol, zcol], axis=1)
+ ),
+ geometry=[list_linestrings_new[i]],
+ )
+ for i in range(len(list_linestrings_new))
+ ]
list_linestrings = pd.concat(list_lines).reset_index(drop=True)
return list_linestrings
-def create_linestrings_from_contours(contours: pv.core.pointset.PolyData,
- return_gdf: bool = True,
- crs: Union[str, pyproj.crs.crs.CRS] = None) \
- -> Union[List[shapely.geometry.linestring.LineString], gpd.geodataframe.GeoDataFrame]:
- """Creating LineStrings from PyVista Contour Lines and save them as list or GeoDataFrame
+def create_linestrings_from_contours(
+ contours: pv.core.pointset.PolyData,
+ return_gdf: bool = True,
+ crs: Union[str, pyproj.crs.crs.CRS] = None,
+) -> Union[List[shapely.geometry.linestring.LineString], gpd.geodataframe.GeoDataFrame]:
+ """Create LineStrings from PyVista Contour Lines and save them as list or GeoDataFrame.
Parameters
__________
contours : pv.core.pointset.PolyData
- PyVista PolyData dataset containing contour lines extracted from a mesh
-
- return_gdf : bool
- Variable to create GeoDataFrame of the created list of Shapely Objects.
- Options include: ``True`` or ``False``, default set to ``True``
-
- crs : Union[str, pyproj.crs.crs.CRS]
- Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``crs='EPSG:4647'``
+ PyVista PolyData dataset containing contour lines extracted from a mesh.
+
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Header | | Data Array | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | PolyData | Information | Name | Field | Type | N Comp | Min | Max |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Cells | 580 | Depth [m] | Points | float64 | 1 | -1.710e+03 | 3.000e+02 |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Points | 586 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Strips | 0 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | X Bounds | 2.952e+05, 3.016e+05 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Y Bounds | 5.619e+06, 5.627e+06 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Z Bounds | -1.710e+03, 3.000e+02 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Arrays | 1 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+
+ return_gdf : bool, default: ``True``
+ Variable to create GeoDataFrame of the created list of Shapely Objects, e.g. ``return_gdf=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
+
+ crs : Union[str, pyproj.crs.crs.CRS], default: ``None``
+ Name of the CRS provided to reproject coordinates of the GeoDataFrame, e.g. ``crs='EPSG:4647'``.
Returns
_______
linestrings : Union[List[shapely.geometry.linestring.LineString], gpd.geodataframe.GeoDataFrame]
- List of LineStrings or GeoDataFrame containing the contours that were converted
+ List of LineStrings or GeoDataFrame containing the contours that were converted.
+
+ +----+----------------------------------------------------+---------+
+ | | geometry | Z |
+ +----+----------------------------------------------------+---------+
+ | 0 | LINESTRING Z (32409587.930 5780538.824 -2350.0...) | -2350.00|
+ +----+----------------------------------------------------+---------+
+ | 1 | LINESTRING Z (32407304.336 5777048.086 -2050.0...) | -2050.00|
+ +----+----------------------------------------------------+---------+
+ | 2 | LINESTRING Z (32408748.977 5778005.047 -2200.0...) | -2200.00|
+ +----+----------------------------------------------------+---------+
+ | 3 | LINESTRING Z (32403693.547 5786613.994 -2400.0...) | -2400.00|
+ +----+----------------------------------------------------+---------+
+ | 4 | LINESTRING Z (32404738.664 5782672.480 -2350.0...) | -2350.00|
+ +----+----------------------------------------------------+---------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3037,49 +3753,66 @@ def create_linestrings_from_contours(contours: pv.core.pointset.PolyData,
>>> import pyvista as pv
>>> contours = pv.read('file.vtk')
>>> contours
- Header
- PolyData Information
- N Cells 36337
- N Points 36178
- X Bounds 3.233e+07, 3.250e+07
- Y Bounds 5.704e+06, 5.798e+06
- Z Bounds -2.400e+03, 3.500e+02
- N Arrays 1
- Data Arrays
- Name Field Type N Comp Min Max
- Depth [m] Points float64 1 -2.400e+03 3.500e+02
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Header | | Data Array | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | PolyData | Information | Name | Field | Type | N Comp | Min | Max |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Cells | 580 | Depth [m] | Points | float64 | 1 | -1.710e+03 | 3.000e+02 |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Points | 586 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Strips | 0 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | X Bounds | 2.952e+05, 3.016e+05 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Y Bounds | 5.619e+06, 5.627e+06 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | Z Bounds | -1.710e+03, 3.000e+02 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
+ | N Arrays | 1 | | | | | | |
+ +--------------+-----------------------+-------------+---------+---------+--------+------------+-----------+
>>> # Extracting LineStrings from contours
>>> gdf = gg.vector.create_linestrings_from_contours(contours=contours)
>>> gdf
- geometry Z
- 0 LINESTRING Z (32409587.930 5780538.824 -2350.0... -2350.00
- 1 LINESTRING Z (32407304.336 5777048.086 -2050.0... -2050.00
- 2 LINESTRING Z (32408748.977 5778005.047 -2200.0... -2200.00
- 3 LINESTRING Z (32403693.547 5786613.994 -2400.0... -2400.00
- 4 LINESTRING Z (32404738.664 5782672.480 -2350.0... -2350.00
+ +----+----------------------------------------------------+---------+
+ | | geometry | Z |
+ +----+----------------------------------------------------+---------+
+ | 0 | LINESTRING Z (32409587.930 5780538.824 -2350.0...) | -2350.00|
+ +----+----------------------------------------------------+---------+
+ | 1 | LINESTRING Z (32407304.336 5777048.086 -2050.0...) | -2050.00|
+ +----+----------------------------------------------------+---------+
+ | 2 | LINESTRING Z (32408748.977 5778005.047 -2200.0...) | -2200.00|
+ +----+----------------------------------------------------+---------+
+ | 3 | LINESTRING Z (32403693.547 5786613.994 -2400.0...) | -2400.00|
+ +----+----------------------------------------------------+---------+
+ | 4 | LINESTRING Z (32404738.664 5782672.480 -2350.0...) | -2350.00|
+ +----+----------------------------------------------------+---------+
- """
+ """
# Checking that the input data is a PyVista PolyData dataset
if not isinstance(contours, pv.core.pointset.PolyData):
- raise TypeError('Input data must be a PyVista PolyData dataset')
+ raise TypeError("Input data must be a PyVista PolyData dataset")
# Checking that the PolyData dataset does not contain any faces
if contours.faces.size != 0:
- raise TypeError('PolyData must not contain faces, only line, use mesh.contour() to extract contours')
+ raise TypeError(
+ "PolyData must not contain faces, only line, use mesh.contour() to extract contours"
+ )
# Checking that the PolyData dataset does contain lines
if contours.lines.size == 0:
- raise ValueError('Contours must contain lines')
+ raise ValueError("Contours must contain lines")
# Checking that return gdfs is of type bool
if not isinstance(return_gdf, bool):
- raise TypeError('Return_gdf argument must be of type bool')
+ raise TypeError("Return_gdf argument must be of type bool")
# Checking that the target_crs is of type string
if not isinstance(crs, (str, type(None), pyproj.crs.crs.CRS)):
- raise TypeError('target_crs must be of type string or a pyproj object')
+ raise TypeError("target_crs must be of type string or a pyproj object")
# Defining empty list for LineStrings
linestrings = []
@@ -3097,7 +3830,10 @@ def create_linestrings_from_contours(contours: pv.core.pointset.PolyData,
number_of_points_of_line = contours.lines[index_to_find_length_of_line]
# Getting the index values to look up points in contours.points
- index_values = [contours.lines[index_to_find_length_of_line + i + 1] for i in range(number_of_points_of_line)]
+ index_values = [
+ contours.lines[index_to_find_length_of_line + i + 1]
+ for i in range(number_of_points_of_line)
+ ]
# Creating list of vertices belonging to one LineString
vertices = [contours.points[value] for value in index_values]
@@ -3114,7 +3850,10 @@ def create_linestrings_from_contours(contours: pv.core.pointset.PolyData,
linestrings = gpd.GeoDataFrame(geometry=linestrings, crs=crs)
# Adding a Z column containing the altitude of the LineString for better plotting
- linestrings['Z'] = [list(linestrings.loc[i].geometry.coords)[0][2] for i in range(len(linestrings))]
+ linestrings["Z"] = [
+ list(linestrings.loc[i].geometry.coords)[0][2]
+ for i in range(len(linestrings))
+ ]
return linestrings
@@ -3123,53 +3862,71 @@ def create_linestrings_from_contours(contours: pv.core.pointset.PolyData,
#################################################
-def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
- value: str = 'Z',
- method: str = 'nearest',
- n: int = None,
- res: int = 1,
- extent: List[Union[float, int]] = None,
- seed: int = None,
- **kwargs) -> np.ndarray:
- """Interpolating a raster/digital elevation model from point or line Shape file
+def interpolate_raster(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ value: str = "Z",
+ method: str = "nearest",
+ n: int = None,
+ res: int = 1,
+ extent: List[Union[float, int]] = None,
+ seed: int = None,
+ **kwargs,
+) -> np.ndarray:
+ """Interpolate a raster/digital elevation model from Point or LineString Shape file.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing vector data of geom_type Point or Line containing the Z values of an area
-
- value : str
- Value to be interpolated, e.g. ``value='Z'``, default is ``'Z'``
-
- method : string
- Method used to interpolate the raster.
- Options include: ``'nearest', 'linear', 'cubic', 'rbf'``
-
- res : int
- Resolution of the raster in X and Y direction, e.g. ``res=50``
-
- seed : int
- Seed for the drawing of random numbers, e.g. ``seed=1``
-
- n : int
- Number of samples used for the interpolation, e.g. ``n=100``
+ GeoDataFrame containing vector data of geom_type Point or Line containing the Z values of an area.
+
+ +----+------+---------------------------------------------------------+
+ | ID | Z | geometry |
+ +----+------+---------------------------------------------------------+
+ | 0 | None | 400 | LINESTRING (0.741 475.441, 35.629 429.247, 77.... |
+ +----+------+---------------------------------------------------------+
+ | 1 | None | 300 | LINESTRING (645.965 0.525, 685.141 61.866, 724... |
+ +----+------+---------------------------------------------------------+
+ | 2 | None | 400 | LINESTRING (490.292 0.525, 505.756 40.732, 519... |
+ +----+------+---------------------------------------------------------+
+ | 3 | None | 600 | LINESTRING (911.433 1068.585, 908.856 1026.831... |
+ +----+------+---------------------------------------------------------+
+ | 4 | None | 700 | LINESTRING (228.432 1068.585, 239.772 1017.037... |
+ +----+------+---------------------------------------------------------+
+
+ value : str, default: ``'Z'``
+ Value to be interpolated, e.g. ``value='Z'``, default is ``'Z'``.
+
+ method : string, default: ``'nearest'``
+ Method used to interpolate the raster, e.g. ``method='nearest'``.
+ Options include: ``'nearest', 'linear', 'cubic', 'rbf'``.
+
+ n : int, default: ``None``
+ Number of samples used for the interpolation, e.g. ``n=100``, default is None.
+
+ res : int, default: ``1``
+ Resolution of the raster in X and Y direction, e.g. ``res=50``, default is ``'1'``.
extent : List[Union[float, int]]
Values for minx, maxx, miny and maxy values to define the boundaries of the raster,
- e.g. ``extent=[0, 972, 0, 1069]``
+ e.g. ``extent=[0, 972, 0, 1069]``.
+
+ seed : int, default: ``None``
+ Seed for the drawing of random numbers, e.g. ``seed=1``, default is None.
**kwargs : optional keyword arguments
- For kwargs for rbf and griddata see: https://docs.scipy.org/doc/scipy/reference/interpolate.html
+ For kwargs for rbf and griddata see: https://docs.scipy.org/doc/scipy/reference/interpolate.html.
Returns
_______
array : np.ndarray
- Array representing the interpolated raster/digital elevation model
+ Array representing the interpolated raster/digital elevation model.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3178,12 +3935,21 @@ def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id Z geometry
- 0 None 400 LINESTRING (0.741 475.441, 35.629 429.247, 77....
- 1 None 300 LINESTRING (645.965 0.525, 685.141 61.866, 724...
- 2 None 400 LINESTRING (490.292 0.525, 505.756 40.732, 519...
- 3 None 600 LINESTRING (911.433 1068.585, 908.856 1026.831...
- 4 None 700 LINESTRING (228.432 1068.585, 239.772 1017.037...
+
+ +----+------+---------------------------------------------------------+
+ | ID | Z | geometry |
+ +----+------+---------------------------------------------------------+
+ | 0 | None | 400 | LINESTRING (0.741 475.441, 35.629 429.247, 77.... |
+ +----+------+---------------------------------------------------------+
+ | 1 | None | 300 | LINESTRING (645.965 0.525, 685.141 61.866, 724... |
+ +----+------+---------------------------------------------------------+
+ | 2 | None | 400 | LINESTRING (490.292 0.525, 505.756 40.732, 519... |
+ +----+------+---------------------------------------------------------+
+ | 3 | None | 600 | LINESTRING (911.433 1068.585, 908.856 1026.831... |
+ +----+------+---------------------------------------------------------+
+ | 4 | None | 700 | LINESTRING (228.432 1068.585, 239.772 1017.037... |
+ +----+------+---------------------------------------------------------+
+
>>> # Interpolating vector data
>>> raster = gg.vector.interpolate_raster(gdf=gdf, method='rbf')
@@ -3194,42 +3960,45 @@ def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
398.16690286, 400.12027997]])
"""
-
# Trying to import scipy but returning error if scipy is not installed
try:
from scipy.interpolate import griddata, Rbf
except ModuleNotFoundError:
- raise ModuleNotFoundError('SciPy package is not installed. Use pip install scipy to install the latest version')
+ raise ModuleNotFoundError(
+ "SciPy package is not installed. Use pip install scipy to install the latest version"
+ )
# Checking if the gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf mus be of type GeoDataFrame')
+ raise TypeError("gdf mus be of type GeoDataFrame")
# Checking that interpolation value is provided as string
if not isinstance(value, str):
- raise TypeError('Interpolation value must be provided as column name/string')
+ raise TypeError("Interpolation value must be provided as column name/string")
# Checking if interpolation values are in the gdf
if value not in gdf:
- raise ValueError('Interpolation values not defined')
+ raise ValueError("Interpolation values not defined")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking if XY values are in the gdf
- if not {'X', 'Y'}.issubset(gdf.columns):
- gdf = extract_xy(gdf=gdf,
- reset_index=True,
- drop_index=False,
- drop_level1=False,
- drop_level0=False,
- drop_id=False,
- drop_points=True)
+ if not {"X", "Y"}.issubset(gdf.columns):
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=True,
+ drop_index=False,
+ drop_level1=False,
+ drop_level0=False,
+ drop_id=False,
+ drop_points=True,
+ )
# Getting sample number n
if n is None:
@@ -3237,11 +4006,11 @@ def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
# Checking that number of samples is of type int
if not isinstance(n, int):
- raise TypeError('Number of samples must be of type int')
+ raise TypeError("Number of samples must be of type int")
# Checking that seed is of type int
if not isinstance(seed, (int, type(None))):
- raise TypeError('Seed must be of type int')
+ raise TypeError("Seed must be of type int")
# Sampling gdf
if n:
@@ -3249,19 +4018,21 @@ def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
if n <= len(gdf):
gdf = gdf.sample(n=n)
else:
- raise ValueError('n must be smaller than the total number of points in the provided GeoDataFrame')
+ raise ValueError(
+ "n must be smaller than the total number of points in the provided GeoDataFrame"
+ )
# Checking that the method provided is of type string
if not isinstance(method, str):
- raise TypeError('Method must be of type string')
+ raise TypeError("Method must be of type string")
# Checking that the resolution provided is of type int
if not isinstance(res, int):
- raise TypeError('Resolution must be of type int')
+ raise TypeError("Resolution must be of type int")
# Checking that the extent provided is of type list or None
if not isinstance(extent, (list, type(None))):
- raise TypeError('Extent must be provided as list of corner values')
+ raise TypeError("Extent must be provided as list of corner values")
# Creating a meshgrid based on the gdf bounds or a provided extent
if extent:
@@ -3277,70 +4048,105 @@ def interpolate_raster(gdf: gpd.geodataframe.GeoDataFrame,
try:
# Interpolating the raster
if method in ["nearest", "linear", "cubic"]:
- array = griddata((gdf['X'], gdf['Y']), gdf[value], (xx, yy), method=method, **kwargs)
- elif method == 'rbf':
- rbf = Rbf(gdf['X'], gdf['Y'], gdf[value], **kwargs)
+ array = griddata(
+ (gdf["X"], gdf["Y"]), gdf[value], (xx, yy), method=method, **kwargs
+ )
+ elif method == "rbf":
+ rbf = Rbf(gdf["X"], gdf["Y"], gdf[value], **kwargs)
array = rbf(xx, yy)
else:
- raise ValueError('No valid method defined')
+ raise ValueError("No valid method defined")
except np.linalg.LinAlgError:
- raise ValueError('LinAlgError: reduce the number of points by setting a value for n or check for duplicates')
+ raise ValueError(
+ "LinAlgError: reduce the number of points by setting a value for n or check for duplicates"
+ )
return array
-def clip_by_bbox(gdf: gpd.geodataframe.GeoDataFrame,
- bbox: List[Union[float, int]],
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True
- ) -> gpd.geodataframe.GeoDataFrame:
- """Clipping vector data contained in a GeoDataFrame to a provided bounding box/extent
+def clip_by_bbox(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ bbox: List[Union[float, int]],
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Clip vector data contained in a GeoDataFrame to a provided bounding box/extent.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing vector data that will be clipped to a provided bounding box/extent
+ GeoDataFrame containing vector data that will be clipped to a provided bounding box/extent.
+
+ +----+------------------------------------------------+
+ | | geometry |
+ +----+------------------------------------------------+
+ | 0 | POINT (281.526 902.087) |
+ +----+------------------------------------------------+
+ | 1 | POINT (925.867 618.577) |
+ +----+------------------------------------------------+
+ | 2 | POINT (718.131 342.799) |
+ +----+------------------------------------------------+
+ | 3 | POINT (331.011 255.684) |
+ +----+------------------------------------------------+
+ | 4 | POINT (300.083 600.535) |
+ +----+------------------------------------------------+
bbox : List[Union[float, int]]
- Bounding box of minx, maxx, miny, maxy values to clip the GeoDataFrame, , e.g. ``bbox=[0, 972, 0, 1069]``
+ Bounding box of minx, maxx, miny, maxy values to clip the GeoDataFrame, , e.g. ``bbox=[0, 972, 0, 1069]``.
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ reset_index : bool, default: ``True``
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column, e.g. ``drop_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
- Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_id : bool, default: ``True``
+ Variable to drop the id column, e.g. ``drop_id=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
- Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_points : bool, default: ``True``
+ Variable to drop the points column, e.g. ``drop_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing vector data clipped by a bounding box
+ GeoDataFrame containing vector data clipped by a bounding box.
+
+ +----+-----------------------------+---------+---------+
+ | ID | geometry | X | Y |
+ +----+-----------------------------+---------+---------+
+ | 0 | POINT (281.526 902.087) | 281.53 | 902.09 |
+ +----+-----------------------------+---------+---------+
+ | 1 | POINT (925.867 618.577) | 925.87 | 618.58 |
+ +----+-----------------------------+---------+---------+
+ | 2 | POINT (718.131 342.799) | 718.13 | 342.80 |
+ +----+-----------------------------+---------+---------+
+ | 3 | POINT (331.011 255.684) | 331.01 | 255.68 |
+ +----+-----------------------------+---------+---------+
+ | 4 | POINT (300.083 600.535) | 300.08 | 600.54 |
+ +----+-----------------------------+---------+---------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3349,12 +4155,21 @@ def clip_by_bbox(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id geometry
- 0 None POINT (281.526 902.087)
- 1 None POINT (925.867 618.577)
- 2 None POINT (718.131 342.799)
- 3 None POINT (331.011 255.684)
- 4 None POINT (300.083 600.535)
+
+ +----+------------------------------------------------+
+ | | geometry |
+ +----+------------------------------------------------+
+ | 0 | POINT (281.526 902.087) |
+ +----+------------------------------------------------+
+ | 1 | POINT (925.867 618.577) |
+ +----+------------------------------------------------+
+ | 2 | POINT (718.131 342.799) |
+ +----+------------------------------------------------+
+ | 3 | POINT (331.011 255.684) |
+ +----+------------------------------------------------+
+ | 4 | POINT (300.083 600.535) |
+ +----+------------------------------------------------+
+
>>> # Returning the length of the original gdf
>>> len(gdf)
@@ -3366,12 +4181,20 @@ def clip_by_bbox(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Clipping data by bounding box
>>> gdf_clipped = gg.vector.clip_by_bbox(gdf=gdf, bbox=bbox)
>>> gdf_clipped
- geometry X Y
- 0 POINT (281.526 902.087) 281.53 902.09
- 1 POINT (925.867 618.577) 925.87 618.58
- 2 POINT (718.131 342.799) 718.13 342.80
- 3 POINT (331.011 255.684) 331.01 255.68
- 4 POINT (300.083 600.535) 300.08 600.54
+
+ +----+-----------------------------+---------+---------+
+ | ID | geometry | X | Y |
+ +----+-----------------------------+---------+---------+
+ | 0 | POINT (281.526 902.087) | 281.53 | 902.09 |
+ +----+-----------------------------+---------+---------+
+ | 1 | POINT (925.867 618.577) | 925.87 | 618.58 |
+ +----+-----------------------------+---------+---------+
+ | 2 | POINT (718.131 342.799) | 718.13 | 342.80 |
+ +----+-----------------------------+---------+---------+
+ | 3 | POINT (331.011 255.684) | 331.01 | 255.68 |
+ +----+-----------------------------+---------+---------+
+ | 4 | POINT (300.083 600.535) | 300.08 | 600.54 |
+ +----+-----------------------------+---------+---------+
>>> # Returning the length of the clipped gdf
>>> len(gdf_clipped)
@@ -3380,175 +4203,210 @@ def clip_by_bbox(gdf: gpd.geodataframe.GeoDataFrame,
See Also
________
- clip_by_polygon : Clipping vector data with a Shapely Polygon
+ clip_by_polygon : Clip vector data with a Shapely Polygon
"""
-
# Checking that the input data is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Loaded object is not a GeoDataFrame')
+ raise TypeError("Loaded object is not a GeoDataFrame")
# Checking that the bounding box is a list
if not isinstance(bbox, list):
- raise TypeError('Bounding box must be of type list')
+ raise TypeError("Bounding box must be of type list")
# Checking that all values are either ints or floats
if not all(isinstance(n, (int, float)) for n in bbox):
- raise TypeError('All bounding values must be of type int or float')
+ raise TypeError("All bounding values must be of type int or float")
# Checking that the geometry types of the GeoDataFrame are the supported types
- if not gdf.geom_type.isin(('MultiLineString', 'LineString', 'Point', 'Polygon')).all():
- raise TypeError('Geometry type within GeoDataFrame not supported')
+ if not gdf.geom_type.isin(
+ ("MultiLineString", "LineString", "Point", "Polygon")
+ ).all():
+ raise TypeError("Geometry type within GeoDataFrame not supported")
# Checking that drop_level0 is of type bool
if not isinstance(drop_level0, bool):
- raise TypeError('Drop_index_level0 argument must be of type bool')
+ raise TypeError("Drop_index_level0 argument must be of type bool")
# Checking that drop_level1 is of type bool
if not isinstance(drop_level1, bool):
- raise TypeError('Drop_index_level1 argument must be of type bool')
+ raise TypeError("Drop_index_level1 argument must be of type bool")
# Checking that reset_index is of type bool
if not isinstance(reset_index, bool):
- raise TypeError('Reset_index argument must be of type bool')
+ raise TypeError("Reset_index argument must be of type bool")
# Checking that drop_id is of type bool
if not isinstance(drop_id, bool):
- raise TypeError('Drop_id argument must be of type bool')
+ raise TypeError("Drop_id argument must be of type bool")
# Checking that drop_points is of type bool
if not isinstance(drop_points, bool):
- raise TypeError('Drop_points argument must be of type bool')
+ raise TypeError("Drop_points argument must be of type bool")
# Checking that drop_index is of type bool
if not isinstance(drop_index, bool):
- raise TypeError('Drop_index argument must be of type bool')
+ raise TypeError("Drop_index argument must be of type bool")
# Checking that the length of the list is either four or six
if not len(bbox) == 4 or len(bbox) == 6:
- raise ValueError('The bbox must include only four or six values')
+ raise ValueError("The bbox must include only four or six values")
# Checking that all elements of the extent are of type int or float
if not all(isinstance(n, (int, float)) for n in bbox):
- raise TypeError('Extent values must be of type int or float')
+ raise TypeError("Extent values must be of type int or float")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Selecting x and y bounds if bbox contains values for all three directions x, y, z
if len(bbox) == 6:
bbox = bbox[:4]
# If X and Y are not in the GeoDataFrame, extract them
- if not {'X', 'Y'}.issubset(gdf.columns):
- gdf = extract_xy(gdf=gdf,
- reset_index=False,
- drop_index=False,
- drop_id=False,
- drop_points=False,
- drop_level0=False,
- drop_level1=False,
- overwrite_xy=False,
- target_crs=None,
- bbox=None)
+ if not {"X", "Y"}.issubset(gdf.columns):
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=False,
+ drop_index=False,
+ drop_id=False,
+ drop_points=False,
+ drop_level0=False,
+ drop_level1=False,
+ overwrite_xy=False,
+ target_crs=None,
+ bbox=None,
+ )
# Clipping the data
- gdf = gpd.clip(gdf=gdf,
- mask=geometry.Polygon([(bbox[0], bbox[2]),
- (bbox[1], bbox[2]),
- (bbox[1], bbox[3]),
- (bbox[0], bbox[3])]))
+ gdf = gpd.clip(
+ gdf=gdf,
+ mask=geometry.Polygon(
+ [
+ (bbox[0], bbox[2]),
+ (bbox[1], bbox[2]),
+ (bbox[1], bbox[3]),
+ (bbox[0], bbox[3]),
+ ]
+ ),
+ )
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
return gdf
-def clip_by_polygon(gdf: gpd.geodataframe.GeoDataFrame,
- polygon: shapely.geometry.polygon.Polygon,
- reset_index: bool = True,
- drop_index: bool = True,
- drop_id: bool = True,
- drop_points: bool = True,
- drop_level0: bool = True,
- drop_level1: bool = True
- ) -> gpd.geodataframe.GeoDataFrame:
- """Clipping vector data contained in a GeoDataFrame to a provided bounding box/extent
+def clip_by_polygon(
+ gdf: gpd.geodataframe.GeoDataFrame,
+ polygon: shapely.geometry.polygon.Polygon,
+ reset_index: bool = True,
+ drop_index: bool = True,
+ drop_id: bool = True,
+ drop_points: bool = True,
+ drop_level0: bool = True,
+ drop_level1: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
+ """Clip vector data contained in a GeoDataFrame to a provided bounding box/extent.
Parameters
__________
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing vector data that will be clipped to a provided bounding box/extent
-
- polygon : polygon: shapely.geometry.polygon
+ GeoDataFrame containing vector data that will be clipped to a provided bounding box/extent.
+
+ +----+-----------------------------+
+ | ID | geometry |
+ +----+-----------------------------+
+ | 0 | POINT (281.526 902.087) |
+ +----+-----------------------------+
+ | 1 | POINT (925.867 618.577) |
+ +----+-----------------------------+
+ | 2 | POINT (718.131 342.799) |
+ +----+-----------------------------+
+ | 3 | POINT (331.011 255.684) |
+ +----+-----------------------------+
+ | 4 | POINT (300.083 600.535) |
+ +----+-----------------------------+
+
+ polygon : shapely.geometry.Polygon
Shapely Polygon defining the extent of the data,
- e.g. ``polygon = Polygon([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]])``
+ e.g. ``polygon = Polygon([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]])``.
- reset_index : bool
- Variable to reset the index of the resulting GeoDataFrame.
- Options include: ``True`` or ``False``, default set to ``True``
+ reset_index : bool, default: ``True``
+ Variable to reset the index of the resulting GeoDataFrame, e.g. ``reset_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level0 : bool
- Variable to drop the level_0 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level0 : bool, default: ``True``
+ Variable to drop the level_0 column, e.g. ``drop_level0=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_level1 : bool
- Variable to drop the level_1 column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_level1 : bool, default: ``True``
+ Variable to drop the level_1 column, e.g. ``drop_level1=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_index : bool
- Variable to drop the index column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_index : bool, default: ``True``
+ Variable to drop the index column, e.g. ``drop_index=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_id : bool
- Variable to drop the id column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_id : bool, default: ``True``
+ Variable to drop the id column, e.g. ``drop_id=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
- drop_points : bool
- Variable to drop the points column.
- Options include: ``True`` or ``False``, default set to ``True``
+ drop_points : bool, default: ``True``
+ Variable to drop the points column, e.g. ``drop_points=True``.
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
gdf : gpd.geodataframe.GeoDataFrame
- GeoDataFrame containing vector data clipped by a bounding box
+ GeoDataFrame containing vector data clipped by a bounding box.
+
+ +----+-----------------------------+---------+---------+
+ | | geometry | X | Y |
+ +----+-----------------------------+---------+---------+
+ | 0 | POINT (281.526 902.087) | 281.53 | 902.09 |
+ +----+-----------------------------+---------+---------+
+ | 1 | POINT (925.867 618.577) | 925.87 | 618.58 |
+ +----+-----------------------------+---------+---------+
+ | 2 | POINT (718.131 342.799) | 718.13 | 342.80 |
+ +----+-----------------------------+---------+---------+
+ | 3 | POINT (331.011 255.684) | 331.01 | 255.68 |
+ +----+-----------------------------+---------+---------+
+ | 4 | POINT (300.083 600.535) | 300.08 | 600.54 |
+ +----+-----------------------------+---------+---------+
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3557,12 +4415,21 @@ def clip_by_polygon(gdf: gpd.geodataframe.GeoDataFrame,
>>> import geopandas as gpd
>>> gdf = gpd.read_file(filename='file.shp')
>>> gdf
- id geometry
- 0 None POINT (281.526 902.087)
- 1 None POINT (925.867 618.577)
- 2 None POINT (718.131 342.799)
- 3 None POINT (331.011 255.684)
- 4 None POINT (300.083 600.535)
+
+ +----+-----------------------------+
+ | ID | geometry |
+ +----+-----------------------------+
+ | 0 | POINT (281.526 902.087) |
+ +----+-----------------------------+
+ | 1 | POINT (925.867 618.577) |
+ +----+-----------------------------+
+ | 2 | POINT (718.131 342.799) |
+ +----+-----------------------------+
+ | 3 | POINT (331.011 255.684) |
+ +----+-----------------------------+
+ | 4 | POINT (300.083 600.535) |
+ +----+-----------------------------+
+
>>> # Returning the length of the original gdf
>>> len(gdf)
@@ -3577,12 +4444,20 @@ def clip_by_polygon(gdf: gpd.geodataframe.GeoDataFrame,
>>> # Clipping data by the polygon
>>> gdf_clipped = gg.vector.clip_by_polygon(gdf=gdf, polygon=polygon)
>>> gdf_clipped
- geometry X Y
- 0 POINT (281.526 902.087) 281.53 902.09
- 1 POINT (925.867 618.577) 925.87 618.58
- 2 POINT (718.131 342.799) 718.13 342.80
- 3 POINT (331.011 255.684) 331.01 255.68
- 4 POINT (300.083 600.535) 300.08 600.54
+
+ +----+-----------------------------+---------+---------+
+ | | geometry | X | Y |
+ +----+-----------------------------+---------+---------+
+ | 0 | POINT (281.526 902.087) | 281.53 | 902.09 |
+ +----+-----------------------------+---------+---------+
+ | 1 | POINT (925.867 618.577) | 925.87 | 618.58 |
+ +----+-----------------------------+---------+---------+
+ | 2 | POINT (718.131 342.799) | 718.13 | 342.80 |
+ +----+-----------------------------+---------+---------+
+ | 3 | POINT (331.011 255.684) | 331.01 | 255.68 |
+ +----+-----------------------------+---------+---------+
+ | 4 | POINT (300.083 600.535) | 300.08 | 600.54 |
+ +----+-----------------------------+---------+---------+
>>> # Returning the length of the clipped gdf
>>> len(gdf_clipped)
@@ -3591,61 +4466,54 @@ def clip_by_polygon(gdf: gpd.geodataframe.GeoDataFrame,
See Also
________
- clip_by_bbox : Clipping vector data with a bbox
+ clip_by_bbox : Clip vector data with a bbox
"""
-
# Checking if the gdf is of type GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('gdf must be of type GeoDataFrame')
+ raise TypeError("gdf must be of type GeoDataFrame")
# Checking if the polygon is of type GeoDataFrame
if not isinstance(polygon, shapely.geometry.polygon.Polygon):
- raise TypeError('Polygon must be of Shapely Polygon')
+ raise TypeError("Polygon must be of Shapely Polygon")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Create deep copy of gdf
gdf = gdf.copy(deep=True)
# Clipping the gdf
- gdf = gpd.clip(gdf=gdf,
- mask=polygon)
+ gdf = gpd.clip(gdf=gdf, mask=polygon)
# Resetting the index
if reset_index:
gdf = gdf.reset_index()
# Dropping level_0 column
- if reset_index and drop_level0 and 'level_0' in gdf:
- gdf = gdf.drop(columns='level_0',
- axis=1)
+ if reset_index and drop_level0 and "level_0" in gdf:
+ gdf = gdf.drop(columns="level_0", axis=1)
# Dropping level_1 column
- if reset_index and drop_level1 and 'level_1' in gdf:
- gdf = gdf.drop(columns='level_1',
- axis=1)
+ if reset_index and drop_level1 and "level_1" in gdf:
+ gdf = gdf.drop(columns="level_1", axis=1)
# Dropping id column
- if 'id' in gdf and drop_id:
- gdf = gdf.drop(columns='id',
- axis=1)
+ if "id" in gdf and drop_id:
+ gdf = gdf.drop(columns="id", axis=1)
# Dropping index column
- if 'index' in gdf and drop_index:
- gdf = gdf.drop(columns='index',
- axis=1)
+ if "index" in gdf and drop_index:
+ gdf = gdf.drop(columns="index", axis=1)
# Dropping points column
- if 'points' in gdf and drop_points:
- gdf = gdf.drop(columns='points',
- axis=1)
+ if "points" in gdf and drop_points:
+ gdf = gdf.drop(columns="points", axis=1)
return gdf
@@ -3654,28 +4522,30 @@ def clip_by_polygon(gdf: gpd.geodataframe.GeoDataFrame,
######################################
-def create_buffer(geom_object: shapely.geometry.base.BaseGeometry,
- distance: Union[float,
- int]) -> shapely.geometry.polygon.Polygon:
- """Creating a buffer around a Shapely LineString or a Point
+def create_buffer(
+ geom_object: shapely.geometry.base.BaseGeometry, distance: Union[float, int]
+) -> shapely.geometry.polygon.Polygon:
+ """Create a buffer around a Shapely LineString or a Shapely Point.
Parameters
__________
geom_object : shapely.geometry.base.BaseGeometry
- Shapely LineString or Point, e.g. ``geom_object=Point(0, 0)``
+ Shapely LineString or Point, e.g. ``geom_object=Point(0, 0)``.
distance : float, int
- Distance of the buffer around the geometry object, e.g. ``distance=10``
+ Distance of the buffer around the geometry object, e.g. ``distance=10``.
Returns
_______
polygon : shapely.geometry.polygon.Polygon
- Polygon representing the buffered area around a geometry object
+ Polygon representing the buffered area around a geometry object.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3695,17 +4565,18 @@ def create_buffer(geom_object: shapely.geometry.base.BaseGeometry,
See Also
________
- create_unified_buffer : Creating a unified buffer around Shapely LineStrings or Points
+ create_unified_buffer : Create a unified buffer around Shapely LineStrings or Shapely Points
"""
-
# Checking that the geometry object is a Shapely LineString or Point
if not isinstance(geom_object, shapely.geometry.base.BaseGeometry):
- raise TypeError('Geometry object must either be a Shapely LineString or Point object')
+ raise TypeError(
+ "Geometry object must either be a Shapely LineString or Point object"
+ )
# Checking that the distance is of type float or int
if not isinstance(distance, (float, int)):
- raise TypeError('Radius must be of type float or int')
+ raise TypeError("Radius must be of type float or int")
# Creating buffer around object
polygon = geom_object.buffer(distance=distance)
@@ -3713,29 +4584,33 @@ def create_buffer(geom_object: shapely.geometry.base.BaseGeometry,
return polygon
-def create_unified_buffer(geom_object: Union[gpd.geodataframe.GeoDataFrame,
- List[shapely.geometry.base.BaseGeometry]],
- distance: Union[np.ndarray, List[Union[float, int]], Union[float, int]]) \
- -> shapely.geometry.multipolygon.MultiPolygon:
- """Creating a unified buffer around Shapely LineStrings or Points
+def create_unified_buffer(
+ geom_object: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.base.BaseGeometry]
+ ],
+ distance: Union[np.ndarray, List[Union[float, int]], Union[float, int]],
+) -> shapely.geometry.multipolygon.MultiPolygon:
+ """Create a unified buffer around Shapely LineStrings or Shapely Points.
Parameters
__________
geom_object : Union[gpd.geodataframe.GeoDataFrame, List[shapely.geometry.base.BaseGeometry]]
- GeoDataFrame or List of Shapely objects
+ GeoDataFrame or List of Shapely objects.
distance : Union[np.ndarray, List[Union[float, int]], Union[float, int]]
- Distance of the buffer around the geometry object, e.g. ``distance=10``
+ Distance of the buffer around the geometry object, e.g. ``distance=10``.
Returns
_______
polygon : shapely.geometry.multipolygon.MultiPolygon
- Polygon representing the buffered area around a geometry object
+ Polygon representing the buffered area around a geometry object.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3763,36 +4638,41 @@ def create_unified_buffer(geom_object: Union[gpd.geodataframe.GeoDataFrame,
See Also
________
- create_buffer : Creating a buffer around a Shapely LineString or Point
+ create_buffer : Create a buffer around a Shapely LineString or a Shapely Point
"""
-
# Checking that the geometry object is a Shapely LineString or Point
- if not isinstance(geom_object, (gpd.geodataframe.GeoDataFrame,
- list,
- shapely.geometry.base.BaseGeometry)):
- raise TypeError('Geometry object must either be a Shapely LineString or Point object')
+ if not isinstance(
+ geom_object,
+ (gpd.geodataframe.GeoDataFrame, list, shapely.geometry.base.BaseGeometry),
+ ):
+ raise TypeError(
+ "Geometry object must either be a Shapely LineString or Point object"
+ )
# Checking that the distance is of type float or int
if not isinstance(distance, (float, int)):
- raise TypeError('Radius must be of type float or int')
+ raise TypeError("Radius must be of type float or int")
# Converting GeoDataFrame into list of Shapely objects
if isinstance(geom_object, gpd.geodataframe.GeoDataFrame):
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(geom_object.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(geom_object.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Converting geometry column of GeoDataFrame to list
geom_object = geom_object.geometry.tolist()
# Creating list of polygons
- polygon_list = [create_buffer(geom_object=geomobject, distance=distance) for geomobject in geom_object]
+ polygon_list = [
+ create_buffer(geom_object=geomobject, distance=distance)
+ for geomobject in geom_object
+ ]
# Creating unified polygons
unified_polygons = ops.unary_union(polygon_list)
@@ -3800,30 +4680,33 @@ def create_unified_buffer(geom_object: Union[gpd.geodataframe.GeoDataFrame,
return unified_polygons
-def subtract_geom_objects(geom_object1: shapely.geometry.base.BaseGeometry,
- geom_object2: shapely.geometry.base.BaseGeometry) \
- -> shapely.geometry.base.BaseGeometry:
- """Subtracting Shapely geometry objects from each other and returning the left over object
+def subtract_geom_objects(
+ geom_object1: shapely.geometry.base.BaseGeometry,
+ geom_object2: shapely.geometry.base.BaseGeometry,
+) -> shapely.geometry.base.BaseGeometry:
+ """Subtract Shapely geometry objects from each other and returning the left over object.
Parameters
__________
geom_object1 : shapely.geometry.base.BaseGeometry
Shapely object from which other object will be subtracted,
- e.g. ``geom_object1 = Polygon([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]])``
+ e.g. ``geom_object1 = Polygon([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]])``.
geom_object2 : shapely.geometry.base.BaseGeometry
Shapely object which will be subtracted from other object
- e.g. ``geom_object2 = Polygon([[5, 0], [15, 0], [15, 10], [5, 10], [5, 0]])``
+ e.g. ``geom_object2 = Polygon([[5, 0], [15, 0], [15, 10], [5, 10], [5, 0]])``.
Returns
_______
result : shapely.geometry.base.BaseGeometry
- Shapely object from which the second object was subtracted
+ Shapely object from which the second object was subtracted.
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3845,14 +4728,17 @@ def subtract_geom_objects(geom_object1: shapely.geometry.base.BaseGeometry,
'POLYGON ((5 0, 0 0, 0 10, 5 10, 5 0))'
"""
-
# Checking that the first geometry object is a Shapely Point, LineString or Polygon
if not isinstance(geom_object1, shapely.geometry.base.BaseGeometry):
- raise TypeError('First geometry object must be a Shapely Point, LineString or Polygon')
+ raise TypeError(
+ "First geometry object must be a Shapely Point, LineString or Polygon"
+ )
# Checking that the second geometry object is a Shapely Point, LineString or Polygon
if not isinstance(geom_object2, shapely.geometry.base.BaseGeometry):
- raise TypeError('Second geometry object must be a Shapely Point, LineString or Polygon')
+ raise TypeError(
+ "Second geometry object must be a Shapely Point, LineString or Polygon"
+ )
# Subtracting object 2 from object 1
result = geom_object1 - geom_object2
@@ -3860,43 +4746,44 @@ def subtract_geom_objects(geom_object1: shapely.geometry.base.BaseGeometry,
return result
-def remove_object_within_buffer(buffer_object: shapely.geometry.base.BaseGeometry,
- buffered_object: shapely.geometry.base.BaseGeometry,
- distance: Union[int,
- float] = None,
- buffer: bool = True) \
- -> Tuple[shapely.geometry.base.BaseGeometry,
- shapely.geometry.base.BaseGeometry]:
- """Removing object from a buffered object by providing a distance
+def remove_object_within_buffer(
+ buffer_object: shapely.geometry.base.BaseGeometry,
+ buffered_object: shapely.geometry.base.BaseGeometry,
+ distance: Union[int, float] = None,
+ buffer: bool = True,
+) -> Tuple[shapely.geometry.base.BaseGeometry, shapely.geometry.base.BaseGeometry]:
+ """Remove object from a buffered object by providing a distance.
Parameters
__________
buffer_object : shapely.geometry.base.BaseGeometry
- Shapely object for which a buffer will be created, e.g. ``buffer_object=Point(0, 0)``
+ Shapely object for which a buffer will be created, e.g. ``buffer_object=Point(0, 0)``.
buffered_object: shapely.geometry.base.BaseGeometry
Shapely object that will be removed from the buffer,
- e.g. ``buffered_object=LineString([(0, 0), (10, 10), (20, 20)])``
+ e.g. ``buffered_object=LineString([(0, 0), (10, 10), (20, 20)])``.
- distance : Union[float, int]
- Distance of the buffer around the geometry object, e.g. ``distance=10``, default is ``None``
+ distance : Union[float, int], default: ``None``
+ Distance of the buffer around the geometry object, e.g. ``distance=10``, default is ``None``.
- buffer : bool
+ buffer : bool, default: ``True``
Variable to create a buffer.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
result_out : shapely.geometry.base.BaseGeometry
- Shapely object that remains after the buffering (outside the buffer)
+ Shapely object that remains after the buffering (outside the buffer).
result_in : shapely.geometry.base.BaseGeometry
- Shapely object that was buffered (inside the buffer)
+ Shapely object that was buffered (inside the buffer).
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -3926,42 +4813,41 @@ def remove_object_within_buffer(buffer_object: shapely.geometry.base.BaseGeometr
See Also
________
- remove_objects_within_buffer : Removing several objects from one buffered object
- remove_interfaces_within_fault_buffers : Removing interfaces of layer boundaries within fault line buffers
+ remove_objects_within_buffer : Remove several objects from one buffered object
+ remove_interfaces_within_fault_buffers : Remove interfaces of layer boundaries within fault line buffers
"""
-
# Checking that the buffer object is a Shapely Point or LineString
if not isinstance(buffer_object, shapely.geometry.base.BaseGeometry):
- raise TypeError('Buffer object must be a Shapely Point or LineString')
+ raise TypeError("Buffer object must be a Shapely Point or LineString")
# Checking that the buffered object is a Shapely Point or LineString
if not isinstance(buffered_object, shapely.geometry.base.BaseGeometry):
- raise TypeError('Buffered object must be a Shapely Point or LineString')
+ raise TypeError("Buffered object must be a Shapely Point or LineString")
# Checking that the buffer_object is valid
if not buffer_object.is_valid:
- raise ValueError('Buffer object is not a valid object')
+ raise ValueError("Buffer object is not a valid object")
# Checking that the buffer_object is not empty
if buffer_object.is_empty:
- raise ValueError('Buffer object is an empty object')
+ raise ValueError("Buffer object is an empty object")
# Checking that the buffered_object is valid
if not buffered_object.is_valid:
- raise ValueError('Buffered Object is not a valid object')
+ raise ValueError("Buffered Object is not a valid object")
# Checking that the buffered_object is not empty
if buffered_object.is_empty:
- raise ValueError('Buffered Object is an empty object')
+ raise ValueError("Buffered Object is an empty object")
# Checking that the distance is of type float or int
if not isinstance(distance, (float, int, type(None))):
- raise TypeError('Radius must be of type float or int')
+ raise TypeError("Radius must be of type float or int")
# Checking that create_buffer is of type bool
if not isinstance(buffer, bool):
- raise TypeError('create_buffer must be of type bool')
+ raise TypeError("create_buffer must be of type bool")
# Create buffer object
if buffer and distance is not None:
@@ -3976,59 +4862,64 @@ def remove_object_within_buffer(buffer_object: shapely.geometry.base.BaseGeometr
return result_out, result_in
-def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeometry,
- buffered_objects_gdf: Union[gpd.geodataframe.GeoDataFrame,
- List[shapely.geometry.base.BaseGeometry]],
- distance: Union[int,
- float] = None,
- return_gdfs: bool = False,
- remove_empty_geometries: bool = False,
- extract_coordinates: bool = False,
- buffer: bool = True) \
- -> Tuple[Union[List[shapely.geometry.base.BaseGeometry], gpd.geodataframe.GeoDataFrame],
- Union[List[shapely.geometry.base.BaseGeometry], gpd.geodataframe.GeoDataFrame]]:
- """Removing objects from a buffered object by providing a distance
+def remove_objects_within_buffer(
+ buffer_object: shapely.geometry.base.BaseGeometry,
+ buffered_objects_gdf: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.base.BaseGeometry]
+ ],
+ distance: Union[int, float] = None,
+ return_gdfs: bool = False,
+ remove_empty_geometries: bool = False,
+ extract_coordinates: bool = False,
+ buffer: bool = True,
+) -> Tuple[
+ Union[List[shapely.geometry.base.BaseGeometry], gpd.geodataframe.GeoDataFrame],
+ Union[List[shapely.geometry.base.BaseGeometry], gpd.geodataframe.GeoDataFrame],
+]:
+ """Remove objects from a buffered object by providing a distance.
Parameters
__________
buffer_object : shapely.geometry.base.BaseGeometry
- Shapely object for which a buffer will be created, e.g. ``buffer_object=Point(0, 0)``
+ Shapely object for which a buffer will be created, e.g. ``buffer_object=Point(0, 0)``.
buffered_object_gdf: Union[gpd.geodataframe.GeoDataFrame, List[shapely.geometry.base.BaseGeometry]]
GeoDataFrame or List of Base Geometries containing Shapely objects that will be buffered by the buffer
- object
+ object.
- distance : float, int
- Distance of the buffer around the geometry object, e.g. ``distance=10``
+ distance : float, int, default: ``10``
+ Distance of the buffer around the geometry object, e.g. ``distance=10``.
- return_gdfs : bool
+ return_gdfs : bool, default: ``False``
Variable to create GeoDataFrames of the created list of Shapely Objects.
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
- remove_empty_geometries : bool
+ remove_empty_geometries : bool, default: ``False``
Variable to remove empty geometries.
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
- extract_coordinates : bool
+ extract_coordinates : bool, default: ``False``
Variable to extract X and Y coordinates from resulting Shapely Objects.
- Options include: ``True`` or ``False``, default set to ``False``
+ Options include: ``True`` or ``False``, default set to ``False``.
- buffer : bool
+ buffer : bool, default: ``True``
Variable to create a buffer.
- Options include: ``True`` or ``False``, default set to ``True``
+ Options include: ``True`` or ``False``, default set to ``True``.
Returns
_______
result_out : list, gpd.geodataframe.GeoDataFrame
- List or GeoDataFrame of Shapely objects that remain after the buffering (outside the buffer)
+ List or GeoDataFrame of Shapely objects that remain after the buffering (outside the buffer).
result_in : list, gpd.geodataframe.GeoDataFrame
- List or GeoDataFrame of Shapely objects that was buffered (inside the buffer)
+ List or GeoDataFrame of Shapely objects that was buffered (inside the buffer).
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -4049,7 +4940,7 @@ def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeomet
>>> linestring2.wkt
'LINESTRING (0 0, 10 10, 20 20)'
- >>> # Create list of buffer objects
+ >>> # Creating list of buffer objects
>>> buffer_objects = [linestring1, linestring2]
>>> # Removing objects within buffer
@@ -4068,61 +4959,62 @@ def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeomet
See Also
________
- remove_object_within_buffer : Removing one object from one buffered object
- remove_interfaces_within_fault_buffers : Removing interfaces of layer boundaries within fault line buffers
+ remove_object_within_buffer : Remove one object from one buffered object
+ remove_interfaces_within_fault_buffers : Remove interfaces of layer boundaries within fault line buffers
"""
# Checking that the buffer object is a Shapely Point or LineString
if not isinstance(buffer_object, shapely.geometry.base.BaseGeometry):
- raise TypeError('Buffer object must be a Shapely Point or LineString')
+ raise TypeError("Buffer object must be a Shapely Point or LineString")
# Checking that the buffer_object is valid
if not buffer_object.is_valid:
- raise ValueError('Buffer object is not a valid object')
+ raise ValueError("Buffer object is not a valid object")
# Checking that the buffer_object is not empty
if buffer_object.is_empty:
- raise ValueError('Buffer object is an empty object')
+ raise ValueError("Buffer object is an empty object")
# Checking that the buffered objects are provided within a GeoDataFrame
if not isinstance(buffered_objects_gdf, (gpd.geodataframe.GeoDataFrame, list)):
- raise TypeError('Buffered objects must be stored as GeoSeries within a GeoDataFrame or as element in a list')
+ raise TypeError(
+ "Buffered objects must be stored as GeoSeries within a GeoDataFrame or as element in a list"
+ )
# Checking that the distance is of type float or int
if not isinstance(distance, (float, int, type(None))):
- raise TypeError('Radius must be of type float or int')
+ raise TypeError("Radius must be of type float or int")
# Checking that return gdfs is of type bool
if not isinstance(return_gdfs, bool):
- raise TypeError('Return_gdf argument must be of type bool')
+ raise TypeError("Return_gdf argument must be of type bool")
# Checking that remove empty geometries is of type bool
if not isinstance(remove_empty_geometries, bool):
- raise TypeError('Remove_emtpy_geometries argument must be of type bool')
+ raise TypeError("Remove_emtpy_geometries argument must be of type bool")
# Checking that extract coordinates is of type bool
if not isinstance(extract_coordinates, bool):
- raise TypeError('Extract_coordinates argument must be of type bool')
+ raise TypeError("Extract_coordinates argument must be of type bool")
# Checking that create_buffer is of type bool
if not isinstance(buffer, bool):
- raise TypeError('create_buffer must be of type bool')
+ raise TypeError("create_buffer must be of type bool")
# Creating buffer
if buffer and distance is not None:
- buffer_object = create_buffer(geom_object=buffer_object,
- distance=distance)
+ buffer_object = create_buffer(geom_object=buffer_object, distance=distance)
# Converting the GeoDataFrame to a list
if isinstance(buffered_objects_gdf, gpd.geodataframe.GeoDataFrame):
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(buffered_objects_gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(buffered_objects_gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Converting geometry column of the GeoDataFrame to a list
buffered_objects_list = buffered_objects_gdf.geometry.tolist()
@@ -4133,10 +5025,12 @@ def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeomet
buffered_objects_list = None
# Creating tuples of buffered and non-buffered Shapely objects
- results = [remove_object_within_buffer(buffer_object=buffer_object,
- buffered_object=i,
- distance=None,
- buffer=False) for i in buffered_objects_list]
+ results = [
+ remove_object_within_buffer(
+ buffer_object=buffer_object, buffered_object=i, distance=None, buffer=False
+ )
+ for i in buffered_objects_list
+ ]
# Creating lists of remaining and buffered geometry objects
results_out = [results[i][0] for i in range(len(results))]
@@ -4144,12 +5038,16 @@ def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeomet
# If return gdfs is true, create GeoDataFrames from list
if return_gdfs:
- results_out = gpd.GeoDataFrame(data=buffered_objects_gdf.drop('geometry', axis=1),
- geometry=results_out,
- crs=buffered_objects_gdf.crs)
- results_in = gpd.GeoDataFrame(data=buffered_objects_gdf.drop('geometry', axis=1),
- geometry=results_in,
- crs=buffered_objects_gdf.crs)
+ results_out = gpd.GeoDataFrame(
+ data=buffered_objects_gdf.drop("geometry", axis=1),
+ geometry=results_out,
+ crs=buffered_objects_gdf.crs,
+ )
+ results_in = gpd.GeoDataFrame(
+ data=buffered_objects_gdf.drop("geometry", axis=1),
+ geometry=results_in,
+ crs=buffered_objects_gdf.crs,
+ )
# Remove empty geometries
if remove_empty_geometries:
@@ -4166,13 +5064,13 @@ def remove_objects_within_buffer(buffer_object: shapely.geometry.base.BaseGeomet
return results_out, results_in
-def remove_interfaces_within_fault_buffers(fault_gdf: gpd.geodataframe.GeoDataFrame,
- interfaces_gdf: gpd.geodataframe.GeoDataFrame,
- distance: Union[int,
- float] = None,
- remove_empty_geometries: bool = True,
- extract_coordinates: bool = True) \
- -> Tuple[gpd.geodataframe.GeoDataFrame, gpd.geodataframe.GeoDataFrame]:
+def remove_interfaces_within_fault_buffers(
+ fault_gdf: gpd.geodataframe.GeoDataFrame,
+ interfaces_gdf: gpd.geodataframe.GeoDataFrame,
+ distance: Union[int, float] = None,
+ remove_empty_geometries: bool = True,
+ extract_coordinates: bool = True,
+) -> Tuple[gpd.geodataframe.GeoDataFrame, gpd.geodataframe.GeoDataFrame]:
"""Function to create a buffer around a GeoDataFrame containing fault data and removing interface points
that are located within this buffer
@@ -4270,56 +5168,60 @@ def remove_interfaces_within_fault_buffers(fault_gdf: gpd.geodataframe.GeoDataFr
# Checking that the buffer object is a Shapely Point or LineString
if not isinstance(fault_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Buffer object must be a Shapely Point or LineString')
+ raise TypeError("Buffer object must be a Shapely Point or LineString")
# Checking that the buffered objects are provided within a GeoDataFrame
if not isinstance(interfaces_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Buffered objects must be stored as GeoSeries within a GeoDataFrame')
+ raise TypeError(
+ "Buffered objects must be stored as GeoSeries within a GeoDataFrame"
+ )
# Checking that the distance is of type float or int
if not isinstance(distance, (float, int)):
- raise TypeError('Radius must be of type float or int')
+ raise TypeError("Radius must be of type float or int")
# Checking that remove empty geometries is of type bool
if not isinstance(remove_empty_geometries, bool):
- raise TypeError('Remove_emtpy_geometries argument must be of type bool')
+ raise TypeError("Remove_emtpy_geometries argument must be of type bool")
# Checking that extract coordinates is of type bool
if not isinstance(extract_coordinates, bool):
- raise TypeError('Extract_coordinates argument must be of type bool')
+ raise TypeError("Extract_coordinates argument must be of type bool")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(fault_gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(fault_gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(interfaces_gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(interfaces_gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Creating list of fault lines
faults_list = fault_gdf.geometry.tolist()
# Exploding Polygons
- if all(interfaces_gdf.geom_type == 'Polygon'):
+ if all(interfaces_gdf.geom_type == "Polygon"):
interfaces_gdf = explode_polygons(gdf=interfaces_gdf)
# Creating unified polygons
unified_polygons = ops.unary_union(geoms=faults_list)
- gdf_out, gdf_in = remove_objects_within_buffer(buffer_object=unified_polygons,
- buffered_objects_gdf=interfaces_gdf,
- distance=distance,
- return_gdfs=True,
- remove_empty_geometries=remove_empty_geometries,
- extract_coordinates=extract_coordinates)
+ gdf_out, gdf_in = remove_objects_within_buffer(
+ buffer_object=unified_polygons,
+ buffered_objects_gdf=interfaces_gdf,
+ distance=distance,
+ return_gdfs=True,
+ remove_empty_geometries=remove_empty_geometries,
+ extract_coordinates=extract_coordinates,
+ )
return gdf_out, gdf_in
@@ -4330,6 +5232,7 @@ def remove_interfaces_within_fault_buffers(fault_gdf: gpd.geodataframe.GeoDataFr
# Calculating Angles and Directions
###################################
+
def calculate_angle(linestring: shapely.geometry.linestring.LineString) -> float:
"""Calculating the angle of a LineString to the vertical
@@ -4380,27 +5283,33 @@ def calculate_angle(linestring: shapely.geometry.linestring.LineString) -> float
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Calculating angle
- angle = np.rad2deg(np.arccos((linestring.coords[0][1] - linestring.coords[1][1]) / linestring.length))
+ angle = np.rad2deg(
+ np.arccos(
+ (linestring.coords[0][1] - linestring.coords[1][1]) / linestring.length
+ )
+ )
return angle
-def calculate_strike_direction_straight_linestring(linestring: shapely.geometry.linestring.LineString) -> float:
+def calculate_strike_direction_straight_linestring(
+ linestring: shapely.geometry.linestring.LineString,
+) -> float:
"""Function to calculate the strike direction of a straight Shapely LineString.
The strike will always be calculated from start to end point
@@ -4451,28 +5360,37 @@ def calculate_strike_direction_straight_linestring(linestring: shapely.geometry.
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Calculating strike angle based on order and location of line vertices
- if linestring.coords[0][0] < linestring.coords[1][0] and linestring.coords[0][1] >= linestring.coords[1][1]:
+ if (
+ linestring.coords[0][0] < linestring.coords[1][0]
+ and linestring.coords[0][1] >= linestring.coords[1][1]
+ ):
angle = 180 - calculate_angle(linestring=linestring)
- elif linestring.coords[0][0] > linestring.coords[1][0] and linestring.coords[0][1] < linestring.coords[1][1]:
+ elif (
+ linestring.coords[0][0] > linestring.coords[1][0]
+ and linestring.coords[0][1] < linestring.coords[1][1]
+ ):
angle = 180 + calculate_angle(linestring=linestring)
- elif linestring.coords[0][0] < linestring.coords[1][0] and linestring.coords[0][1] < linestring.coords[1][1]:
+ elif (
+ linestring.coords[0][0] < linestring.coords[1][0]
+ and linestring.coords[0][1] < linestring.coords[1][1]
+ ):
angle = 180 - calculate_angle(linestring=linestring)
else:
angle = 180 + calculate_angle(linestring=linestring)
@@ -4484,7 +5402,9 @@ def calculate_strike_direction_straight_linestring(linestring: shapely.geometry.
return angle
-def calculate_strike_direction_bent_linestring(linestring: shapely.geometry.linestring.LineString) -> List[float]:
+def calculate_strike_direction_bent_linestring(
+ linestring: shapely.geometry.linestring.LineString,
+) -> List[float]:
"""Calculating the strike direction of a LineString with multiple elements
Parameters
@@ -4529,31 +5449,35 @@ def calculate_strike_direction_bent_linestring(linestring: shapely.geometry.line
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) < 2:
- raise ValueError('LineString must contain at least two vertices')
+ raise ValueError("LineString must contain at least two vertices")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Split LineString into list of single LineStrings with two vertices each
splitted_linestrings = explode_linestring_to_elements(linestring=linestring)
# Calculate strike angle for each single LineString element
- angles_splitted_linestrings = [calculate_strike_direction_straight_linestring(linestring=i) for i in
- splitted_linestrings]
+ angles_splitted_linestrings = [
+ calculate_strike_direction_straight_linestring(linestring=i)
+ for i in splitted_linestrings
+ ]
return angles_splitted_linestrings
-def calculate_dipping_angle_linestring(linestring: shapely.geometry.linestring.LineString):
+def calculate_dipping_angle_linestring(
+ linestring: shapely.geometry.linestring.LineString,
+):
"""Calculating the dipping angle of a LineString digitized on a cross section
Parameters
@@ -4603,30 +5527,38 @@ def calculate_dipping_angle_linestring(linestring: shapely.geometry.linestring.L
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Calculating the dip of LineString based on its slope
- dip = np.abs(np.rad2deg(np.arctan((linestring.coords[1][1] - linestring.coords[0][1]) /
- (linestring.coords[1][0] - linestring.coords[0][0]))))
+ dip = np.abs(
+ np.rad2deg(
+ np.arctan(
+ (linestring.coords[1][1] - linestring.coords[0][1])
+ / (linestring.coords[1][0] - linestring.coords[0][0])
+ )
+ )
+ )
return dip
def calculate_dipping_angles_linestrings(
- linestring_list: Union[gpd.geodataframe.GeoDataFrame,
- List[shapely.geometry.linestring.LineString]]):
+ linestring_list: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.linestring.LineString]
+ ]
+):
"""Calculating the dipping angles of LineStrings digitized on a cross section
Parameters
@@ -4678,30 +5610,34 @@ def calculate_dipping_angles_linestrings(
# Checking that the list of LineStrings is either provided as list or within a GeoDataFrame
if not isinstance(linestring_list, (list, gpd.geodataframe.GeoDataFrame)):
- raise TypeError('LineStrings must be provided as list or within a GeoDataFrame')
+ raise TypeError("LineStrings must be provided as list or within a GeoDataFrame")
# Convert LineStrings stored in GeoDataFrame to list
if isinstance(linestring_list, gpd.geodataframe.GeoDataFrame):
linestring_list = linestring_list.geometry.tolist()
# Checking that all elements of the list are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in linestring_list):
- raise TypeError('All list elements must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString) for n in linestring_list
+ ):
+ raise TypeError("All list elements must be Shapely LineStrings")
# Checking that all LineStrings only have two vertices
if not all(len(n.coords) == 2 for n in linestring_list):
- raise ValueError('All LineStrings must only have two vertices')
+ raise ValueError("All LineStrings must only have two vertices")
# Checking that the LineString is valid
if not all(n.is_valid for n in linestring_list):
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if any(n.is_empty for n in linestring_list):
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Calculating dipping angles
- dipping_angles = [calculate_dipping_angle_linestring(linestring=i) for i in linestring_list]
+ dipping_angles = [
+ calculate_dipping_angle_linestring(linestring=i) for i in linestring_list
+ ]
return dipping_angles
@@ -4709,9 +5645,11 @@ def calculate_dipping_angles_linestrings(
# Calculating Coordinates for Vector Data from Cross Sections
############################################################
-def calculate_coordinates_for_point_on_cross_section(linestring: shapely.geometry.linestring.LineString,
- point: Union[shapely.geometry.point.Point,
- Tuple[float, float]]):
+
+def calculate_coordinates_for_point_on_cross_section(
+ linestring: shapely.geometry.linestring.LineString,
+ point: Union[shapely.geometry.point.Point, Tuple[float, float]],
+):
"""Calculating the coordinates for one point digitized on a cross section provided as Shapely LineString
Parameters
@@ -4767,37 +5705,41 @@ def calculate_coordinates_for_point_on_cross_section(linestring: shapely.geometr
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the Point is a Shapely Point or a tuple
if not isinstance(point, (shapely.geometry.point.Point, tuple)):
- raise TypeError('Input geometry must be a Shapley Point or a tuple with X and Y coordinates')
+ raise TypeError(
+ "Input geometry must be a Shapley Point or a tuple with X and Y coordinates"
+ )
# Checking that all elements of the list are floats
if isinstance(point, tuple) and not all(isinstance(n, float) for n in point):
- raise TypeError('All tuple elements must be floats')
+ raise TypeError("All tuple elements must be floats")
# Checking that the tuple only consists of two elements
if isinstance(point, tuple) and len(point) != 2:
- raise ValueError('The point tuple only takes X and Y coordinates')
+ raise ValueError("The point tuple only takes X and Y coordinates")
# Converting the Shapely Point to a tuple
if isinstance(point, shapely.geometry.point.Point):
point = point.coords[0]
# Creating Substrings from cross section LineString
- substr = ops.substring(geom=linestring,
- start_dist=point[0] / linestring.length,
- end_dist=linestring.length,
- normalized=True)
+ substr = ops.substring(
+ geom=linestring,
+ start_dist=point[0] / linestring.length,
+ end_dist=linestring.length,
+ normalized=True,
+ )
# Creating Shapely Point from Substring
point = geometry.Point(substr.coords[0])
@@ -4805,8 +5747,10 @@ def calculate_coordinates_for_point_on_cross_section(linestring: shapely.geometr
return point
-def calculate_coordinates_for_linestring_on_cross_sections(linestring: shapely.geometry.linestring.LineString,
- interfaces: shapely.geometry.linestring.LineString):
+def calculate_coordinates_for_linestring_on_cross_sections(
+ linestring: shapely.geometry.linestring.LineString,
+ interfaces: shapely.geometry.linestring.LineString,
+):
"""Calculating the coordinates of vertices for a LineString on a straight cross section provided as Shapely
LineString
@@ -4872,40 +5816,43 @@ def calculate_coordinates_for_linestring_on_cross_sections(linestring: shapely.g
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is a Shapely LineString
if not isinstance(interfaces, shapely.geometry.linestring.LineString):
- raise TypeError('Input interfaces must be a Shapley LineString')
+ raise TypeError("Input interfaces must be a Shapley LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString is valid
if not interfaces.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if interfaces.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Calculating the real world coordinates of points digitized on a cross section
- points = [calculate_coordinates_for_point_on_cross_section(linestring=linestring,
- point=interfaces.coords[i]) for i in
- range(len(interfaces.coords))]
+ points = [
+ calculate_coordinates_for_point_on_cross_section(
+ linestring=linestring, point=interfaces.coords[i]
+ )
+ for i in range(len(interfaces.coords))
+ ]
return points
-def calculate_coordinates_for_linestrings_on_cross_sections(linestring: shapely.geometry.linestring.LineString,
- linestring_interfaces_list: List[
- shapely.geometry.linestring.LineString]) -> \
- List[shapely.geometry.point.Point]:
+def calculate_coordinates_for_linestrings_on_cross_sections(
+ linestring: shapely.geometry.linestring.LineString,
+ linestring_interfaces_list: List[shapely.geometry.linestring.LineString],
+) -> List[shapely.geometry.point.Point]:
"""Calculating the coordinates of vertices for LineStrings on a straight cross section provided as Shapely
LineString
@@ -4983,28 +5930,34 @@ def calculate_coordinates_for_linestrings_on_cross_sections(linestring: shapely.
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring_interfaces_list, list):
- raise TypeError('Input interfaces must be a list containing Shapley LineString')
+ raise TypeError("Input interfaces must be a list containing Shapley LineString")
# Checking that all elements of the list are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in linestring_interfaces_list):
- raise TypeError('All list elements must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in linestring_interfaces_list
+ ):
+ raise TypeError("All list elements must be Shapely LineStrings")
# Calculating the coordinates for LineStrings on a cross section
- points = [calculate_coordinates_for_linestring_on_cross_sections(linestring=linestring,
- interfaces=i) for i in
- linestring_interfaces_list]
+ points = [
+ calculate_coordinates_for_linestring_on_cross_sections(
+ linestring=linestring, interfaces=i
+ )
+ for i in linestring_interfaces_list
+ ]
# Create list of points from list of lists
points = [points[i][j] for i in range(len(points)) for j in range(len(points[i]))]
@@ -5012,10 +5965,11 @@ def calculate_coordinates_for_linestrings_on_cross_sections(linestring: shapely.
return points
-def extract_interfaces_coordinates_from_cross_section(linestring: shapely.geometry.linestring.LineString,
- interfaces_gdf: gpd.geodataframe.GeoDataFrame,
- extract_coordinates: bool = True) \
- -> gpd.geodataframe.GeoDataFrame:
+def extract_interfaces_coordinates_from_cross_section(
+ linestring: shapely.geometry.linestring.LineString,
+ interfaces_gdf: gpd.geodataframe.GeoDataFrame,
+ extract_coordinates: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
"""Extracting coordinates of interfaces digitized on a cross section
Parameters
@@ -5083,75 +6037,88 @@ def extract_interfaces_coordinates_from_cross_section(linestring: shapely.geomet
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the interfaces_gdf is a GeoDataFrame
if not isinstance(interfaces_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Interfaces must be stored as a GeoDataFrame')
+ raise TypeError("Interfaces must be stored as a GeoDataFrame")
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in interfaces_gdf.geometry.tolist()):
- raise TypeError('All geometry elements must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in interfaces_gdf.geometry.tolist()
+ ):
+ raise TypeError("All geometry elements must be Shapely LineStrings")
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(interfaces_gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(interfaces_gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Calculating coordinates for LineStrings on cross sections
geom_objects = calculate_coordinates_for_linestrings_on_cross_sections(
linestring=linestring,
- linestring_interfaces_list=interfaces_gdf.geometry.tolist())
+ linestring_interfaces_list=interfaces_gdf.geometry.tolist(),
+ )
# Resetting index of GeoDataFrame
interfaces_gdf = interfaces_gdf.reset_index()
# Creating column with lists of coordinates
- interfaces_gdf['list_geoms'] = [list(interfaces_gdf.geometry[i].coords) for i in range(len(interfaces_gdf))]
+ interfaces_gdf["list_geoms"] = [
+ list(interfaces_gdf.geometry[i].coords) for i in range(len(interfaces_gdf))
+ ]
# Creating DataFrame from interfaces_gdf without geometry column and explode column list_geoms
- data_gdf = pd.DataFrame(interfaces_gdf.drop('geometry', axis=1)).explode('list_geoms')
+ data_gdf = pd.DataFrame(interfaces_gdf.drop("geometry", axis=1)).explode(
+ "list_geoms"
+ )
# Creating GeoDataFrame from data_gdf and geom_objects
- gdf = gpd.GeoDataFrame(data=data_gdf,
- geometry=geom_objects)
+ gdf = gpd.GeoDataFrame(data=data_gdf, geometry=geom_objects)
# Extracting X and Y coordinates from Point objects
if extract_coordinates:
- gdf = extract_xy(gdf=gdf,
- reset_index=True,
- drop_index=True,
- drop_id=True,
- drop_points=True,
- drop_level0=True,
- drop_level1=True,
- overwrite_xy=True,
- )
+ gdf = extract_xy(
+ gdf=gdf,
+ reset_index=True,
+ drop_index=True,
+ drop_id=True,
+ drop_points=True,
+ drop_level0=True,
+ drop_level1=True,
+ overwrite_xy=True,
+ )
# Creating Z column from
- gdf['Z'] = [interfaces_gdf.geometry[i].coords[j][1] for i in range(len(interfaces_gdf)) for j in
- range(len(list(interfaces_gdf.geometry[i].coords)))]
+ gdf["Z"] = [
+ interfaces_gdf.geometry[i].coords[j][1]
+ for i in range(len(interfaces_gdf))
+ for j in range(len(list(interfaces_gdf.geometry[i].coords)))
+ ]
# Dropping the column with the geometry lists
- gdf = gdf.drop('list_geoms', axis=1)
+ gdf = gdf.drop("list_geoms", axis=1)
return gdf
-def extract_xyz_from_cross_sections(profile_gdf: gpd.geodataframe.GeoDataFrame,
- interfaces_gdf: gpd.geodataframe.GeoDataFrame,
- profile_name_column: str = 'name') -> gpd.geodataframe.GeoDataFrame:
+def extract_xyz_from_cross_sections(
+ profile_gdf: gpd.geodataframe.GeoDataFrame,
+ interfaces_gdf: gpd.geodataframe.GeoDataFrame,
+ profile_name_column: str = "name",
+) -> gpd.geodataframe.GeoDataFrame:
"""Extracting X, Y, and Z coordinates from cross sections and digitized interfaces
Parameters
@@ -5230,60 +6197,80 @@ def extract_xyz_from_cross_sections(profile_gdf: gpd.geodataframe.GeoDataFrame,
# Checking that the profile traces are provided as a GeoDataFrame
if not isinstance(profile_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Input geometry must be a GeoDataFrame')
+ raise TypeError("Input geometry must be a GeoDataFrame")
# Checking that the column profile name column is present in the GeoDataFrame
if profile_name_column not in profile_gdf:
- raise ValueError('Column with profile names not found, provide profile_name_column')
+ raise ValueError(
+ "Column with profile names not found, provide profile_name_column"
+ )
# Checking that the column profile name column is present in the GeoDataFrame
if profile_name_column not in interfaces_gdf:
- raise ValueError('Column with profile names not found, provide profile_name_column')
+ raise ValueError(
+ "Column with profile names not found, provide profile_name_column"
+ )
# Checking that the interfaces_gdf is a GeoDataFrame
if not isinstance(interfaces_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Interfaces must be stored as a GeoDataFrame')
+ raise TypeError("Interfaces must be stored as a GeoDataFrame")
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in profile_gdf.geometry.tolist()):
- raise TypeError('All geometry elements of the profile_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in profile_gdf.geometry.tolist()
+ ):
+ raise TypeError(
+ "All geometry elements of the profile_gdf must be Shapely LineStrings"
+ )
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in interfaces_gdf.geometry.tolist()):
- raise TypeError('All geometry elements of the interface_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in interfaces_gdf.geometry.tolist()
+ ):
+ raise TypeError(
+ "All geometry elements of the interface_gdf must be Shapely LineStrings"
+ )
# Checking that profile_name_column is in profile_gdf
if profile_name_column not in profile_gdf:
- raise ValueError('Profile Column not found, provide a valid name or add column')
+ raise ValueError("Profile Column not found, provide a valid name or add column")
# Checking that the profile_name_column is in interfaces_gdf
if profile_name_column not in interfaces_gdf:
- raise ValueError('Profile Column not found, provide a valid name or add column')
+ raise ValueError("Profile Column not found, provide a valid name or add column")
# Checking that the profile names are identical
if not sorted(profile_gdf[profile_name_column].unique().tolist()) == sorted(
- interfaces_gdf[profile_name_column].unique().tolist()):
- raise ValueError('Profile names in DataFrames are not identical')
+ interfaces_gdf[profile_name_column].unique().tolist()
+ ):
+ raise ValueError("Profile names in DataFrames are not identical")
# Creating a list of GeoDataFrames containing the X, Y, and Z coordinates of digitized interfaces
- list_gdf = [extract_interfaces_coordinates_from_cross_section(profile_gdf.geometry[i],
- interfaces_gdf[
- interfaces_gdf[profile_name_column] ==
- profile_gdf[profile_name_column][i]])
- for i in range(len(profile_gdf))]
+ list_gdf = [
+ extract_interfaces_coordinates_from_cross_section(
+ profile_gdf.geometry[i],
+ interfaces_gdf[
+ interfaces_gdf[profile_name_column]
+ == profile_gdf[profile_name_column][i]
+ ],
+ )
+ for i in range(len(profile_gdf))
+ ]
# Concat list of GeoDataFrames to one large DataFrame
df = pd.concat(list_gdf).reset_index(drop=True)
# Creating GeoDataFrame
- gdf = gpd.GeoDataFrame(data=df,
- geometry=df['geometry'],
- crs=interfaces_gdf.crs)
+ gdf = gpd.GeoDataFrame(data=df, geometry=df["geometry"], crs=interfaces_gdf.crs)
return gdf
-def calculate_midpoint_linestring(linestring: shapely.geometry.linestring.LineString) -> shapely.geometry.point.Point:
+def calculate_midpoint_linestring(
+ linestring: shapely.geometry.linestring.LineString,
+) -> shapely.geometry.point.Point:
"""Calculating the midpoint of a LineString with two vertices
Parameters
@@ -5330,25 +6317,24 @@ def calculate_midpoint_linestring(linestring: shapely.geometry.linestring.LineSt
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString only consists of two vertices
if len(linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the LineString is valid
if not linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Creating a substring at half the distance of the LineString
- substr = ops.substring(geom=linestring,
- start_dist=0.5,
- end_dist=linestring.length,
- normalized=True)
+ substr = ops.substring(
+ geom=linestring, start_dist=0.5, end_dist=linestring.length, normalized=True
+ )
# Extracting midpoint from substring
point = geometry.Point(substr.coords[0])
@@ -5356,9 +6342,11 @@ def calculate_midpoint_linestring(linestring: shapely.geometry.linestring.LineSt
return point
-def calculate_midpoints_linestrings(linestring_gdf: Union[gpd.geodataframe.GeoDataFrame,
- List[shapely.geometry.linestring.LineString]]) -> \
- List[shapely.geometry.point.Point]:
+def calculate_midpoints_linestrings(
+ linestring_gdf: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.linestring.LineString]
+ ]
+) -> List[shapely.geometry.point.Point]:
"""Calculating the midpoints of LineStrings with two vertices each
Parameters
@@ -5411,33 +6399,39 @@ def calculate_midpoints_linestrings(linestring_gdf: Union[gpd.geodataframe.GeoDa
# Checking that the LineString is a Shapely LineString
if not isinstance(linestring_gdf, (gpd.geodataframe.GeoDataFrame, list)):
- raise TypeError('Input geometry must be a GeoDataFrame or a List containing LineStrings')
+ raise TypeError(
+ "Input geometry must be a GeoDataFrame or a List containing LineStrings"
+ )
# Converting LineStrings in GeoDataFrame to list of LineStrings
if isinstance(linestring_gdf, gpd.geodataframe.GeoDataFrame):
# Checking that all Shapely Objects are valid
if not all(shapely.is_valid(linestring_gdf.geometry)):
- raise ValueError('Not all Shapely Objects are valid objects')
+ raise ValueError("Not all Shapely Objects are valid objects")
# Checking that no empty Shapely Objects are present
if any(shapely.is_empty(linestring_gdf.geometry)):
- raise ValueError('One or more Shapely objects are empty')
+ raise ValueError("One or more Shapely objects are empty")
# Creating list from geometry column
linestring_gdf = linestring_gdf.geometry.tolist()
# Checking that all LineStrings are valid
if not all(i.is_valid for i in linestring_gdf):
- raise ValueError('Not all Shapely LineStrings are valid')
+ raise ValueError("Not all Shapely LineStrings are valid")
# Checking that no LineStrings are empty
if any(i.is_empty for i in linestring_gdf):
- raise ValueError('One or more LineString Objects are empty')
+ raise ValueError("One or more LineString Objects are empty")
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in linestring_gdf):
- raise TypeError('All geometry elements of the linestring_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString) for n in linestring_gdf
+ ):
+ raise TypeError(
+ "All geometry elements of the linestring_gdf must be Shapely LineStrings"
+ )
# Calculating midpoints
midpoints = [calculate_midpoint_linestring(linestring=i) for i in linestring_gdf]
@@ -5449,8 +6443,10 @@ def calculate_midpoints_linestrings(linestring_gdf: Union[gpd.geodataframe.GeoDa
#######################################################################
-def calculate_orientation_from_cross_section(profile_linestring: shapely.geometry.linestring.LineString,
- orientation_linestring: shapely.geometry.linestring.LineString) -> list:
+def calculate_orientation_from_cross_section(
+ profile_linestring: shapely.geometry.linestring.LineString,
+ orientation_linestring: shapely.geometry.linestring.LineString,
+) -> list:
"""Calculating the orientation for one LineString on one cross sections
Parameters
@@ -5508,44 +6504,50 @@ def calculate_orientation_from_cross_section(profile_linestring: shapely.geometr
# Checking that the LineString is a Shapely LineString
if not isinstance(profile_linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is a Shapely LineString
if not isinstance(orientation_linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not profile_linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if profile_linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString is valid
if not orientation_linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if orientation_linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString only consists of two vertices
if len(orientation_linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the X coordinates/ the distances to the origin are always positive
if list(orientation_linestring.coords)[0][0] < 0:
- raise ValueError('X coordinates must always be positive, check the orientation of your profile')
+ raise ValueError(
+ "X coordinates must always be positive, check the orientation of your profile"
+ )
if list(orientation_linestring.coords)[1][0] < 0:
- raise ValueError('X coordinates must always be positive, check the orientation of your profile')
+ raise ValueError(
+ "X coordinates must always be positive, check the orientation of your profile"
+ )
# Calculating midpoint of orientation LineString
midpoint = calculate_midpoint_linestring(orientation_linestring)
# Calculating the coordinates for the midpoint on the cross section
- coordinates = calculate_coordinates_for_point_on_cross_section(profile_linestring, midpoint)
+ coordinates = calculate_coordinates_for_point_on_cross_section(
+ profile_linestring, midpoint
+ )
# Calculating the dipping angle for the orientation LineString
dip = calculate_dipping_angle_linestring(orientation_linestring)
@@ -5554,16 +6556,22 @@ def calculate_orientation_from_cross_section(profile_linestring: shapely.geometr
azimuth_profile = calculate_strike_direction_straight_linestring(profile_linestring)
# Calculating the azimuth of the orientation based on the dip direction of the orientation
- if orientation_linestring.coords[0][0] < orientation_linestring.coords[1][0] and \
- orientation_linestring.coords[0][1] > orientation_linestring.coords[1][1]:
+ if (
+ orientation_linestring.coords[0][0] < orientation_linestring.coords[1][0]
+ and orientation_linestring.coords[0][1] > orientation_linestring.coords[1][1]
+ ):
azimuth = azimuth_profile
- elif orientation_linestring.coords[0][0] > orientation_linestring.coords[1][0] and \
- orientation_linestring.coords[0][1] < orientation_linestring.coords[1][1]:
+ elif (
+ orientation_linestring.coords[0][0] > orientation_linestring.coords[1][0]
+ and orientation_linestring.coords[0][1] < orientation_linestring.coords[1][1]
+ ):
azimuth = azimuth_profile
- elif orientation_linestring.coords[0][0] < orientation_linestring.coords[1][0] and \
- orientation_linestring.coords[0][1] < orientation_linestring.coords[1][1]:
+ elif (
+ orientation_linestring.coords[0][0] < orientation_linestring.coords[1][0]
+ and orientation_linestring.coords[0][1] < orientation_linestring.coords[1][1]
+ ):
azimuth = 180 + azimuth_profile
else:
@@ -5582,9 +6590,10 @@ def calculate_orientation_from_cross_section(profile_linestring: shapely.geometr
return orientation
-def calculate_orientation_from_bent_cross_section(profile_linestring: shapely.geometry.linestring.LineString,
- orientation_linestring: shapely.geometry.linestring.LineString) \
- -> list:
+def calculate_orientation_from_bent_cross_section(
+ profile_linestring: shapely.geometry.linestring.LineString,
+ orientation_linestring: shapely.geometry.linestring.LineString,
+) -> list:
"""Calculating the orientation of a LineString on a bent cross section provided as Shapely LineString
Parameters
@@ -5641,44 +6650,49 @@ def calculate_orientation_from_bent_cross_section(profile_linestring: shapely.ge
# Checking that the LineString is a Shapely LineString
if not isinstance(profile_linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is a Shapely LineString
if not isinstance(orientation_linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not profile_linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if profile_linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString is valid
if not orientation_linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if orientation_linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the LineString only consists of two vertices
if len(orientation_linestring.coords) != 2:
- raise ValueError('LineString must only contain a start and end point')
+ raise ValueError("LineString must only contain a start and end point")
# Checking that the X coordinates/ the distances to the origin are always positive
if list(orientation_linestring.coords)[0][0] < 0:
- raise ValueError('X coordinates must always be positive, check the orientation of your profile')
+ raise ValueError(
+ "X coordinates must always be positive, check the orientation of your profile"
+ )
if list(orientation_linestring.coords)[1][0] < 0:
- raise ValueError('X coordinates must always be positive, check the orientation of your profile')
+ raise ValueError(
+ "X coordinates must always be positive, check the orientation of your profile"
+ )
splitted_linestrings = explode_linestring_to_elements(linestring=profile_linestring)
# Calculating real world coordinates of endpoints of orientation LineString
- points = calculate_coordinates_for_linestring_on_cross_sections(linestring=profile_linestring,
- interfaces=orientation_linestring)
+ points = calculate_coordinates_for_linestring_on_cross_sections(
+ linestring=profile_linestring, interfaces=orientation_linestring
+ )
# Setting the orientation to None
orientation = None
@@ -5690,12 +6704,18 @@ def calculate_orientation_from_bent_cross_section(profile_linestring: shapely.ge
linestring = i
# Calculating orientation for the previously created LineString and the original orientation linestring
- orientation = calculate_orientation_from_cross_section(profile_linestring=linestring,
- orientation_linestring=orientation_linestring)
+ orientation = calculate_orientation_from_cross_section(
+ profile_linestring=linestring,
+ orientation_linestring=orientation_linestring,
+ )
# Replace point of orientation value
- midpoint = geometry.Point([((points[0].coords[0][0] + points[1].coords[0][0]) / 2),
- ((points[0].coords[0][1] + points[1].coords[0][1]) / 2)])
+ midpoint = geometry.Point(
+ [
+ ((points[0].coords[0][0] + points[1].coords[0][0]) / 2),
+ ((points[0].coords[0][1] + points[1].coords[0][1]) / 2),
+ ]
+ )
orientation[0] = midpoint
@@ -5705,15 +6725,20 @@ def calculate_orientation_from_bent_cross_section(profile_linestring: shapely.ge
# If the orientation is none, hence either one or both points are too far away from the linestring, return an error
if orientation is None:
- raise ValueError('Orientations may have been digitized across a bent, no orientations were calculated')
+ raise ValueError(
+ "Orientations may have been digitized across a bent, no orientations were calculated"
+ )
return orientation
-def calculate_orientations_from_cross_section(profile_linestring: shapely.geometry.linestring.LineString,
- orientation_linestrings: Union[gpd.geodataframe.GeoDataFrame, List[
- shapely.geometry.linestring.LineString]],
- extract_coordinates: bool = True) -> gpd.geodataframe.GeoDataFrame:
+def calculate_orientations_from_cross_section(
+ profile_linestring: shapely.geometry.linestring.LineString,
+ orientation_linestrings: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.linestring.LineString]
+ ],
+ extract_coordinates: bool = True,
+) -> gpd.geodataframe.GeoDataFrame:
"""Calculating orientations from a cross sections using multiple LineStrings
Parameters
@@ -5775,23 +6800,23 @@ def calculate_orientations_from_cross_section(profile_linestring: shapely.geomet
# Checking that the LineString is a Shapely LineString
if not isinstance(profile_linestring, shapely.geometry.linestring.LineString):
- raise TypeError('Input geometry must be a Shapley LineString')
+ raise TypeError("Input geometry must be a Shapley LineString")
# Checking that the LineString is valid
if not profile_linestring.is_valid:
- raise ValueError('LineString is not a valid object')
+ raise ValueError("LineString is not a valid object")
# Checking that the LineString is not empty
if profile_linestring.is_empty:
- raise ValueError('LineString is an empty object')
+ raise ValueError("LineString is an empty object")
# Checking that the input orientations are stored as list or GeoDataFrame
if not isinstance(orientation_linestrings, (gpd.geodataframe.GeoDataFrame, list)):
- raise TypeError('Orientations must be stored as a GeoDataFrame or in a list')
+ raise TypeError("Orientations must be stored as a GeoDataFrame or in a list")
# Copying the GeoDataFrame Data
if isinstance(orientation_linestrings, gpd.geodataframe.GeoDataFrame):
- data = orientation_linestrings.copy(deep=True).drop('geometry', axis=1)
+ data = orientation_linestrings.copy(deep=True).drop("geometry", axis=1)
else:
data = None
@@ -5800,37 +6825,50 @@ def calculate_orientations_from_cross_section(profile_linestring: shapely.geomet
orientation_linestrings = orientation_linestrings.geometry.tolist()
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in orientation_linestrings):
- raise TypeError('All geometry elements of the linestring_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in orientation_linestrings
+ ):
+ raise TypeError(
+ "All geometry elements of the linestring_gdf must be Shapely LineStrings"
+ )
# Checking that all LineStrings are valid
if not all(i.is_valid for i in orientation_linestrings):
- raise ValueError('Not all Shapely LineStrings are valid')
+ raise ValueError("Not all Shapely LineStrings are valid")
# Checking that no LineStrings are empty
if any(i.is_empty for i in orientation_linestrings):
- raise ValueError('One or more LineString Objects are empty')
+ raise ValueError("One or more LineString Objects are empty")
# Calculating the orientations
- orientations_list = [calculate_orientation_from_bent_cross_section(profile_linestring, i)
- for i in orientation_linestrings]
+ orientations_list = [
+ calculate_orientation_from_bent_cross_section(profile_linestring, i)
+ for i in orientation_linestrings
+ ]
# Creating a GeoDataFrame with the orientation data
- gdf = gpd.GeoDataFrame(data=pd.DataFrame(data=[[orientations_list[i][1] for i in range(len(orientations_list))],
- [orientations_list[i][2] for i in range(len(orientations_list))],
- [orientations_list[i][3] for i in range(len(orientations_list))],
- [orientations_list[i][4] for i in range(len(orientations_list))]]).T,
- geometry=[orientations_list[i][0] for i in range(len(orientations_list))])
+ gdf = gpd.GeoDataFrame(
+ data=pd.DataFrame(
+ data=[
+ [orientations_list[i][1] for i in range(len(orientations_list))],
+ [orientations_list[i][2] for i in range(len(orientations_list))],
+ [orientations_list[i][3] for i in range(len(orientations_list))],
+ [orientations_list[i][4] for i in range(len(orientations_list))],
+ ]
+ ).T,
+ geometry=[orientations_list[i][0] for i in range(len(orientations_list))],
+ )
# Assigning column names
- gdf.columns = ['Z', 'dip', 'azimuth', 'polarity', 'geometry']
+ gdf.columns = ["Z", "dip", "azimuth", "polarity", "geometry"]
# Extracting X and Y coordinates from point objects
if extract_coordinates:
gdf = extract_xy(gdf)
# Sorting the columns
- gdf = gdf[['X', 'Y', 'Z', 'dip', 'azimuth', 'polarity', 'geometry']]
+ gdf = gdf[["X", "Y", "Z", "dip", "azimuth", "polarity", "geometry"]]
# If the input is a GeoDataFrame, append the remaining data to the orientations GeoDataFrame
if data is not None:
@@ -5839,9 +6877,11 @@ def calculate_orientations_from_cross_section(profile_linestring: shapely.geomet
return gdf
-def extract_orientations_from_cross_sections(profile_gdf: gpd.geodataframe.GeoDataFrame,
- orientations_gdf: gpd.geodataframe.GeoDataFrame,
- profile_name_column: str = 'name') -> gpd.geodataframe.GeoDataFrame:
+def extract_orientations_from_cross_sections(
+ profile_gdf: gpd.geodataframe.GeoDataFrame,
+ orientations_gdf: gpd.geodataframe.GeoDataFrame,
+ profile_name_column: str = "name",
+) -> gpd.geodataframe.GeoDataFrame:
"""Calculating orientations digitized from cross sections
Parameters
@@ -5906,69 +6946,89 @@ def extract_orientations_from_cross_sections(profile_gdf: gpd.geodataframe.GeoDa
# Checking that the profile traces are provided as GeoDataFrame
if not isinstance(profile_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Profile traces must be provided as GeoDataFrame')
+ raise TypeError("Profile traces must be provided as GeoDataFrame")
# Checking that the input orientations are stored as GeoDataFrame
if not isinstance(orientations_gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Orientations must be provided as GeoDataFrame')
+ raise TypeError("Orientations must be provided as GeoDataFrame")
# Checking that the column profile name column is present in the GeoDataFrame
if profile_name_column not in profile_gdf:
- raise ValueError('Column with profile names not found, provide profile_name_column')
+ raise ValueError(
+ "Column with profile names not found, provide profile_name_column"
+ )
# Checking that the column profile name column is present in the GeoDataFrame
if profile_name_column not in orientations_gdf:
- raise ValueError('Column with profile names not found, provide profile_name_column')
+ raise ValueError(
+ "Column with profile names not found, provide profile_name_column"
+ )
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in profile_gdf.geometry.tolist()):
- raise TypeError('All geometry elements of the profile_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in profile_gdf.geometry.tolist()
+ ):
+ raise TypeError(
+ "All geometry elements of the profile_gdf must be Shapely LineStrings"
+ )
# Checking that all elements of the geometry column are LineStrings
- if not all(isinstance(n, shapely.geometry.linestring.LineString) for n in orientations_gdf.geometry.tolist()):
- raise TypeError('All geometry elements of the orientations_gdf must be Shapely LineStrings')
+ if not all(
+ isinstance(n, shapely.geometry.linestring.LineString)
+ for n in orientations_gdf.geometry.tolist()
+ ):
+ raise TypeError(
+ "All geometry elements of the orientations_gdf must be Shapely LineStrings"
+ )
# Checking that all elements of the geometry column are valid
if not all(n.is_valid for n in profile_gdf.geometry.tolist()):
- raise ValueError('All Shapely LineStrings must be valid')
+ raise ValueError("All Shapely LineStrings must be valid")
# Checking that all elements of the geometry column are not empty
if any(n.is_empty for n in orientations_gdf.geometry.tolist()):
- raise ValueError('One or more geometries are empty')
+ raise ValueError("One or more geometries are empty")
# Checking that all elements of the geometry column are valid
if not all(n.is_valid for n in profile_gdf.geometry.tolist()):
- raise ValueError('All Shapely LineStrings must be valid')
+ raise ValueError("All Shapely LineStrings must be valid")
# Checking that all elements of the geometry column are not empty
if any(n.is_empty for n in orientations_gdf.geometry.tolist()):
- raise ValueError('One or more geometries are empty')
+ raise ValueError("One or more geometries are empty")
# Create list of GeoDataFrames containing orientation and location information for orientations on cross sections
- list_gdf = [calculate_orientations_from_cross_section(
- profile_gdf.geometry[i],
- orientations_gdf[orientations_gdf[profile_name_column] == profile_gdf[profile_name_column][i]].reset_index())
- for i in range(len(profile_gdf))]
+ list_gdf = [
+ calculate_orientations_from_cross_section(
+ profile_gdf.geometry[i],
+ orientations_gdf[
+ orientations_gdf[profile_name_column]
+ == profile_gdf[profile_name_column][i]
+ ].reset_index(),
+ )
+ for i in range(len(profile_gdf))
+ ]
# Merging the list of gdfs, resetting the index and dropping the index column
gdf = pd.concat(list_gdf)
# Dropping column if it is in the gdf
- if 'level_0' in gdf:
- gdf = gdf.drop('level_0', axis=1)
+ if "level_0" in gdf:
+ gdf = gdf.drop("level_0", axis=1)
# Resetting index and dropping columns
- gdf = gdf.reset_index().drop(['index', 'level_0'], axis=1)
+ gdf = gdf.reset_index().drop(["index", "level_0"], axis=1)
# Creating GeoDataFrame
- gdf = gpd.GeoDataFrame(data=gdf,
- geometry=gdf['geometry'],
- crs=orientations_gdf.crs)
+ gdf = gpd.GeoDataFrame(data=gdf, geometry=gdf["geometry"], crs=orientations_gdf.crs)
return gdf
-def calculate_orientation_for_three_point_problem(gdf: gpd.geodataframe.GeoDataFrame) -> gpd.geodataframe.GeoDataFrame:
+def calculate_orientation_for_three_point_problem(
+ gdf: gpd.geodataframe.GeoDataFrame,
+) -> gpd.geodataframe.GeoDataFrame:
"""Calculating the orientation for a three point problem
Parameters
@@ -6008,35 +7068,34 @@ def calculate_orientation_for_three_point_problem(gdf: gpd.geodataframe.GeoDataF
# Checking that the points are provided as GeoDataFrame
if not isinstance(gdf, gpd.geodataframe.GeoDataFrame):
- raise TypeError('Profile traces must be provided as GeoDataFrame')
+ raise TypeError("Profile traces must be provided as GeoDataFrame")
# Checking that the GeoDataFrame consists of points
if not all(shapely.get_type_id(gdf.geometry) == 0):
- raise TypeError('All elements must be of geometry type Point')
+ raise TypeError("All elements must be of geometry type Point")
# Checking that the length of the GeoDataFrame is 3
if not len(gdf) == 3:
- raise ValueError('GeoDataFrame must only contain three points')
+ raise ValueError("GeoDataFrame must only contain three points")
# Extracting X and Y values
- if not {'X', 'Y'}.issubset(gdf.columns):
+ if not {"X", "Y"}.issubset(gdf.columns):
gdf = extract_xy(gdf=gdf)
# Checking that the Z column is in the GeoDataFrame
- if 'Z' not in gdf:
- raise ValueError('Z values missing in GeoDataFrame')
+ if "Z" not in gdf:
+ raise ValueError("Z values missing in GeoDataFrame")
# Sorting the points by altitude and reset index
- gdf = gdf.sort_values(by='Z', ascending=True).reset_index(drop=True)
+ gdf = gdf.sort_values(by="Z", ascending=True).reset_index(drop=True)
# Getting the point values
- point1 = gdf[['X', 'Y', 'Z']].loc[0].values
- point2 = gdf[['X', 'Y', 'Z']].loc[1].values
- point3 = gdf[['X', 'Y', 'Z']].loc[2].values
+ point1 = gdf[["X", "Y", "Z"]].loc[0].values
+ point2 = gdf[["X", "Y", "Z"]].loc[1].values
+ point3 = gdf[["X", "Y", "Z"]].loc[2].values
# Calculating the normal for the points
- normal = np.cross(a=point3 - point2,
- b=point1 - point2)
+ normal = np.cross(a=point3 - point2, b=point1 - point2)
normal /= np.linalg.norm(normal)
@@ -6051,16 +7110,36 @@ def calculate_orientation_for_three_point_problem(gdf: gpd.geodataframe.GeoDataF
azimuth = 180 - azimuth
# Calculate location of orientation
- x = np.mean(gdf['X'].values)
- y = np.mean(gdf['Y'].values)
- z = np.mean(gdf['Z'].values)
+ x = np.mean(gdf["X"].values)
+ y = np.mean(gdf["Y"].values)
+ z = np.mean(gdf["Z"].values)
# Creating GeoDataFrame
- orientation = gpd.GeoDataFrame(data=pd.DataFrame(
- [float(z), gdf['formation'].unique()[0], float(azimuth), float(dip), float(1), float(x), float(y)]).T,
- geometry=gpd.points_from_xy(x=[x], y=[y]),
- crs=gdf.crs)
- orientation.columns = ['Z', 'formation', 'azimuth', 'dip', 'polarity', 'X', 'Y', 'geometry']
+ orientation = gpd.GeoDataFrame(
+ data=pd.DataFrame(
+ [
+ float(z),
+ gdf["formation"].unique()[0],
+ float(azimuth),
+ float(dip),
+ float(1),
+ float(x),
+ float(y),
+ ]
+ ).T,
+ geometry=gpd.points_from_xy(x=[x], y=[y]),
+ crs=gdf.crs,
+ )
+ orientation.columns = [
+ "Z",
+ "formation",
+ "azimuth",
+ "dip",
+ "polarity",
+ "X",
+ "Y",
+ "geometry",
+ ]
return orientation
@@ -6069,9 +7148,10 @@ def calculate_orientation_for_three_point_problem(gdf: gpd.geodataframe.GeoDataF
#########################################
-def intersection_polygon_polygon(polygon1: shapely.geometry.polygon.Polygon,
- polygon2: shapely.geometry.polygon.Polygon) \
- -> Union[shapely.geometry.linestring.LineString, shapely.geometry.polygon.Polygon]:
+def intersect_polygon_polygon(
+ polygon1: shapely.geometry.polygon.Polygon,
+ polygon2: shapely.geometry.polygon.Polygon,
+) -> Union[shapely.geometry.linestring.LineString, shapely.geometry.polygon.Polygon]:
"""Calculating the intersection between to Shapely Polygons
Parameters
@@ -6093,6 +7173,8 @@ def intersection_polygon_polygon(polygon1: shapely.geometry.polygon.Polygon,
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -6109,42 +7191,42 @@ def intersection_polygon_polygon(polygon1: shapely.geometry.polygon.Polygon,
'POLYGON ((10 0, 20 0, 20 10, 10 10, 10 0))'
>>> # Calculating the intersection between two polygons
- >>> intersection = gg.vector.intersection_polygon_polygon(polygon1=polygon1, polygon2=polygon2)
+ >>> intersection = gg.vector.intersect_polygon_polygon(polygon1=polygon1, polygon2=polygon2)
>>> intersection.wkt
'LINESTRING (10 0, 10 10)'
See Also
________
- intersections_polygon_polygons : Intersecting a polygon with mutiple polygons
- intersections_polygons_polygons : Intersecting multiple polygons with multiple polygons
+ intersect_polygon_polygons : Intersecting a polygon with mutiple polygons
+ intersect_polygons_polygons : Intersecting multiple polygons with multiple polygons
extract_xy_from_polygon_intersections : Extracting intersections between multiple polygons
"""
# Checking that the input polygon is a Shapely Polygon
if not isinstance(polygon1, shapely.geometry.polygon.Polygon):
- raise TypeError('Input Polygon1 must a be Shapely Polygon')
+ raise TypeError("Input Polygon1 must a be Shapely Polygon")
# Checking that the input polygon is a Shapely Polygon
if not isinstance(polygon2, shapely.geometry.polygon.Polygon):
- raise TypeError('Input Polygon2 must a be Shapely Polygon')
+ raise TypeError("Input Polygon2 must a be Shapely Polygon")
# Checking if input geometries are valid
if not polygon1.is_valid:
- raise ValueError('Input polygon 1 is an invalid input geometry')
+ raise ValueError("Input polygon 1 is an invalid input geometry")
# Checking if input geometries are valid
if not polygon2.is_valid:
- raise ValueError('Input polygon 2 is an invalid input geometry')
+ raise ValueError("Input polygon 2 is an invalid input geometry")
# Checking if input geometries are empty
if polygon1.is_empty:
- raise ValueError('Input polygon 1 is an empty input geometry')
+ raise ValueError("Input polygon 1 is an empty input geometry")
# Checking if input geometries are empty
if polygon2.is_empty:
- raise ValueError('Input polygon 2 is an empty input geometry')
+ raise ValueError("Input polygon 2 is an empty input geometry")
# Calculating the intersections
intersection = polygon1.intersection(polygon2)
@@ -6152,10 +7234,12 @@ def intersection_polygon_polygon(polygon1: shapely.geometry.polygon.Polygon,
return intersection
-def intersections_polygon_polygons(polygon1: shapely.geometry.polygon.Polygon,
- polygons2: Union[
- gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]]) \
- -> List[shapely.geometry.base.BaseGeometry]:
+def intersect_polygon_polygons(
+ polygon1: shapely.geometry.polygon.Polygon,
+ polygons2: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]
+ ],
+) -> List[shapely.geometry.base.BaseGeometry]:
"""Calculating the intersections between one polygon and a list of polygons
Parameters
@@ -6176,6 +7260,8 @@ def intersections_polygon_polygons(polygon1: shapely.geometry.polygon.Polygon,
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -6211,27 +7297,27 @@ def intersections_polygon_polygons(polygon1: shapely.geometry.polygon.Polygon,
See Also
________
- intersection_polygon_polygon : Intersecting a polygon with a polygon
- intersections_polygons_polygons : Intersecting multiple polygons with multiple polygons
+ intersect_polygon_polygon : Intersecting a polygon with a polygon
+ intersect_polygons_polygons : Intersecting multiple polygons with multiple polygons
extract_xy_from_polygon_intersections : Extracting intersections between multiple polygons
"""
# Checking that the input polygon is a Shapely Polygon
if not isinstance(polygon1, shapely.geometry.polygon.Polygon):
- raise TypeError('Input Polygon1 must a be Shapely Polygon')
+ raise TypeError("Input Polygon1 must a be Shapely Polygon")
# Checking if input geometries are valid
if not polygon1.is_valid:
- raise ValueError('Input polygon 1 is an invalid input geometry')
+ raise ValueError("Input polygon 1 is an invalid input geometry")
# Checking if input geometries are empty
if polygon1.is_empty:
- raise ValueError('Input polygon 1 is an empty input geometry')
+ raise ValueError("Input polygon 1 is an empty input geometry")
# Checking that the input polygon is a list or a GeoDataFrame
if not isinstance(polygons2, (gpd.geodataframe.GeoDataFrame, list)):
- raise TypeError('Input Polygon2 must a be GeoDataFrame or list')
+ raise TypeError("Input Polygon2 must a be GeoDataFrame or list")
# Converting the Polygons stored in the GeoDataFrame into a list and removing invalid geometries
if isinstance(polygons2, gpd.geodataframe.GeoDataFrame):
@@ -6240,27 +7326,33 @@ def intersections_polygon_polygons(polygon1: shapely.geometry.polygon.Polygon,
# Checking that all elements of the geometry column are Polygons
if not all(isinstance(n, shapely.geometry.polygon.Polygon) for n in polygons2):
- raise TypeError('All geometry elements of polygons2 must be Shapely Polygons')
+ raise TypeError("All geometry elements of polygons2 must be Shapely Polygons")
# Checking that all elements of the geometry column are valid
if not all(n.is_valid for n in polygons2):
- raise TypeError('All geometry elements of polygons2 must be valid')
+ raise TypeError("All geometry elements of polygons2 must be valid")
# Checking that all elements of the geometry column are not empty
if any(n.is_empty for n in polygons2):
- raise TypeError('None of the geometry elements of polygons2 must be empty')
+ raise TypeError("None of the geometry elements of polygons2 must be empty")
# Creating the list of intersection geometries
- intersections = [intersection_polygon_polygon(polygon1=polygon1,
- polygon2=polygon) for polygon in polygons2]
+ intersections = [
+ intersect_polygon_polygon(polygon1=polygon1, polygon2=polygon)
+ for polygon in polygons2
+ ]
return intersections
-def intersections_polygons_polygons(
- polygons1: Union[gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]],
- polygons2: Union[gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]]) \
- -> List[shapely.geometry.base.BaseGeometry]:
+def intersect_polygons_polygons(
+ polygons1: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]
+ ],
+ polygons2: Union[
+ gpd.geodataframe.GeoDataFrame, List[shapely.geometry.polygon.Polygon]
+ ],
+) -> List[shapely.geometry.base.BaseGeometry]:
"""Calculating the intersections between a list of Polygons
Parameters
@@ -6280,6 +7372,8 @@ def intersections_polygons_polygons(
.. versionadded:: 1.0.x
+ .. versionchanged:: 1.2
+
Example
_______
@@ -6302,7 +7396,7 @@ def intersections_polygons_polygons(
>>> polygons2 = [polygon2, polygon2]
>>> # Calculating intersections between polygons and polygons
- >>> intersection = gg.vector.intersections_polygons_polygons(polygons1=polygons1, polygons2=polygons2)
+ >>> intersection = gg.vector.intersect_polygons_polygons(polygons1=polygons1, polygons2=polygons2)
>>> intersection
[