vector module¶
Vector processing utilities for pysatgeo.
assign_crs_to_vector(input_geojson_path, output_geojson_path, crs_epsg)
¶
Assign a CRS to a vector dataset and export the result.
Source code in pysatgeo/vector.py
def assign_crs_to_vector(input_geojson_path, output_geojson_path, crs_epsg):
"""Assign a CRS to a vector dataset and export the result."""
gdf = _read_vector(input_geojson_path)
gdf.set_crs(epsg=crs_epsg, inplace=True, allow_override=True)
_write_vector(gdf, output_geojson_path)
print(f"Output saved to: {output_geojson_path}")
return output_geojson_path
clip_vector_with_masks(input_vector_path, mask_folder, output_folder)
¶
Clip a vector dataset with every supported mask found in a folder.
Source code in pysatgeo/vector.py
def clip_vector_with_masks(input_vector_path, mask_folder, output_folder):
"""Clip a vector dataset with every supported mask found in a folder."""
os.makedirs(output_folder, exist_ok=True)
valid_extensions = [".parquet", ".geojson", ".gpkg", ".shp"]
mask_files = [
file_name
for file_name in os.listdir(mask_folder)
if os.path.splitext(file_name)[1].lower() in valid_extensions
]
if not mask_files:
return []
input_gdf = _read_vector(input_vector_path)
vector_extension = os.path.splitext(input_vector_path)[1].lower()
outputs = []
for mask_file in mask_files:
mask_path = os.path.join(mask_folder, mask_file)
mask_gdf = _read_vector(mask_path)
clipped_gdf = gpd.clip(input_gdf, mask_gdf)
output_name = f"{os.path.splitext(mask_file)[0]}_clipped{vector_extension}"
output_path = os.path.join(output_folder, output_name)
_write_vector(clipped_gdf, output_path)
outputs.append(output_path)
return outputs
convert_and_buffer_vectors(input_folder, output_folder, target_epsg, buffer_distance=None)
¶
Reproject, dissolve, and optionally buffer vector files in a directory.
Source code in pysatgeo/vector.py
def convert_and_buffer_vectors(input_folder, output_folder, target_epsg, buffer_distance=None):
"""Reproject, dissolve, and optionally buffer vector files in a directory."""
os.makedirs(output_folder, exist_ok=True)
outputs = []
for file_name in os.listdir(input_folder):
if file_name.endswith((".shp", ".geojson")):
input_path = os.path.join(input_folder, file_name)
gdf = gpd.read_file(input_path).to_crs(epsg=target_epsg).dissolve()
if buffer_distance is not None:
gdf["geometry"] = gdf.buffer(buffer_distance)
base_name, ext = os.path.splitext(file_name)
parts = base_name.split("_")
if parts[-1].isdigit() and len(parts[-1]) == 4:
parts.pop()
output_base = "_".join(parts) + f"_{target_epsg}"
output_path = os.path.join(output_folder, f"{output_base}_buffered{ext}")
gdf.to_file(output_path)
outputs.append(output_path)
return outputs
convert_epsg_vectors(input_folder, output_folder, target_epsg)
¶
Reproject and dissolve vector files in a directory.
Source code in pysatgeo/vector.py
def convert_epsg_vectors(input_folder, output_folder, target_epsg):
"""Reproject and dissolve vector files in a directory."""
os.makedirs(output_folder, exist_ok=True)
outputs = []
for file_name in os.listdir(input_folder):
if file_name.endswith((".shp", ".geojson")):
input_path = os.path.join(input_folder, file_name)
gdf = gpd.read_file(input_path).to_crs(epsg=target_epsg).dissolve()
base_name, ext = os.path.splitext(file_name)
parts = base_name.split("_")
if parts[-1].isdigit() and len(parts[-1]) == 4:
parts.pop()
output_base = "_".join(parts) + f"_{target_epsg}"
output_path = os.path.join(output_folder, f"{output_base}{ext}")
gdf.to_file(output_path)
outputs.append(output_path)
return outputs
convert_geojson_to_geoparquet(input_folder, output_folder)
¶
Convert every GeoJSON file in a folder into GeoParquet format.
Source code in pysatgeo/vector.py
def convert_geojson_to_geoparquet(input_folder, output_folder):
"""Convert every GeoJSON file in a folder into GeoParquet format."""
os.makedirs(output_folder, exist_ok=True)
geojson_files = [f for f in os.listdir(input_folder) if f.endswith(".geojson")]
if not geojson_files:
print("No GeoJSON files found in the input folder.")
return
for geojson_file in geojson_files:
input_path = os.path.join(input_folder, geojson_file)
output_path = os.path.join(output_folder, f"{os.path.splitext(geojson_file)[0]}.parquet")
try:
gdf = gpd.read_file(input_path)
gdf.to_parquet(output_path)
print(f"Converted: {geojson_file} -> {os.path.basename(output_path)}")
except Exception as e:
print(f"Error processing {geojson_file}: {e}")
print("\nConversion complete!")
convert_pk_to_string(pk_string)
¶
Convert a PK string like 12+3 into a zero-padded numeric string.
Source code in pysatgeo/vector.py
def convert_pk_to_string(pk_string):
"""Convert a PK string like `12+3` into a zero-padded numeric string."""
if "+" in pk_string:
pk_integer = int(pk_string.replace("+", ""))
return f"{pk_integer:04d}"
return f"{int(pk_string):04d}"
dissolve_vector(input_vector, output_vector, dissolve_field=None)
¶
Dissolve features from a vector dataset into a new output layer.
Source code in pysatgeo/vector.py
def dissolve_vector(input_vector, output_vector, dissolve_field=None):
"""Dissolve features from a vector dataset into a new output layer."""
gdf = _read_vector(input_vector)
dissolved_gdf = gdf.dissolve(by=dissolve_field) if dissolve_field else gdf.dissolve()
_write_vector(dissolved_gdf, output_vector)
return output_vector
merge_geoparquet_files(vector_dir)
¶
Merge all GeoParquet files in a directory into one file.
Source code in pysatgeo/vector.py
def merge_geoparquet_files(vector_dir):
"""Merge all GeoParquet files in a directory into one file."""
input_parquets = glob.glob(os.path.join(vector_dir, "*.parquet"))
if not input_parquets:
return None
geodataframes = [gpd.read_parquet(path) for path in input_parquets]
merged_gdf = gpd.GeoDataFrame(pd.concat(geodataframes, ignore_index=True))
base_filename = os.path.basename(input_parquets[0])
base_name, ext = os.path.splitext(base_filename)
if "_" in base_name:
base_name = "_".join(base_name.split("_")[:-1]) + "_merged"
else:
base_name += "_merged"
output_file = os.path.join(vector_dir, f"{base_name}{ext}")
merged_gdf.to_parquet(output_file)
return output_file
merge_vector_files(vector_dir)
¶
Merge supported vector files in a directory using ogrmerge.py.
Source code in pysatgeo/vector.py
def merge_vector_files(vector_dir):
"""Merge supported vector files in a directory using `ogrmerge.py`."""
input_vectors = (
glob.glob(os.path.join(vector_dir, "*.gpkg"))
+ glob.glob(os.path.join(vector_dir, "*.geojson"))
+ glob.glob(os.path.join(vector_dir, "*.shp"))
)
if not input_vectors:
return None
base_name, ext = os.path.splitext(os.path.basename(input_vectors[0]))
output_format_map = {
".gpkg": "GPKG",
".geojson": "GeoJSON",
".shp": "ESRI Shapefile",
}
output_format = output_format_map.get(ext.lower(), "GPKG")
output_file = os.path.join(vector_dir, f"{base_name}_merged{ext}")
merge_command = ["ogrmerge.py", "-single", "-f", output_format, "-o", output_file]
merge_command.extend(input_vectors)
subprocess.run(merge_command, check=True)
return output_file
rasterize(target_resolution, input_directory, no_data_value, field_name=None)
¶
Rasterize GeoJSON files in a directory into GeoTIFF files.
Source code in pysatgeo/vector.py
def rasterize(target_resolution, input_directory, no_data_value, field_name=None):
"""Rasterize GeoJSON files in a directory into GeoTIFF files."""
for file_name in os.listdir(input_directory):
if file_name.endswith(".geojson"):
input_geojson = os.path.join(input_directory, file_name)
output_tif = os.path.join(
input_directory, file_name.replace(".geojson", ".tif")
)
command = [
"gdal_rasterize",
"-tr",
str(target_resolution),
str(target_resolution),
"-of",
"GTiff",
]
if field_name:
command.extend(["-a", field_name])
else:
command.extend(["-burn", "1"])
command.extend(
["-a_nodata", str(no_data_value), input_geojson, output_tif]
)
subprocess.run(command, check=True)
shift_vector_to_raster_reference(vector_path, raster_path, output_vector_path)
¶
Shift a vector layer so its lower-left corner matches a raster extent.
Source code in pysatgeo/vector.py
def shift_vector_to_raster_reference(vector_path, raster_path, output_vector_path):
"""Shift a vector layer so its lower-left corner matches a raster extent."""
with rasterio.open(raster_path) as src:
raster_bounds = src.bounds
raster_crs = src.crs
vector_gdf = _read_vector(vector_path)
if vector_gdf.crs is not None and raster_crs is not None and vector_gdf.crs != raster_crs:
vector_gdf = vector_gdf.to_crs(raster_crs)
vector_bounds = vector_gdf.total_bounds
x_offset = raster_bounds[0] - vector_bounds[0]
y_offset = raster_bounds[1] - vector_bounds[1]
print(f"X offset (m) is: {x_offset}")
print(f"Y offset (m) is: {y_offset}")
vector_gdf["geometry"] = vector_gdf["geometry"].translate(
xoff=x_offset, yoff=y_offset
)
_write_vector(vector_gdf, output_vector_path)
print(f"Shifted vector saved to: {output_vector_path}")
return output_vector_path