From f3db9fec9b63cef01757a27d67563fa423d75832 Mon Sep 17 00:00:00 2001 From: Jeff Osundwa Date: Thu, 19 Sep 2024 02:08:30 +0300 Subject: [PATCH 1/5] Added points_per_grid_cell function and tests --- .../jobs/points_per_grid_cell.py | 123 ++++++++++++++++++ test/test_points_per_grid_cell.py | 88 +++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py create mode 100644 test/test_points_per_grid_cell.py diff --git a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py new file mode 100644 index 0000000..e0bdd13 --- /dev/null +++ b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py @@ -0,0 +1,123 @@ +import os +from qgis.PyQt.QtCore import QVariant +from qgis.core import ( + QgsVectorLayer, + QgsField, + QgsSpatialIndex, + QgsProcessingFeedback, +) +import processing +from .create_grids import GridCreator +from .extents import Extents + + +class RasterFromScore: + def __init__(self, country_boundary, pixel_size, output_path, crs, input_points): + self.country_boundary = country_boundary + self.pixel_size = pixel_size + self.output_path = output_path + self.crs = crs + self.input_points = input_points + + def raster_from_score(self): + """ + Generates a raster based on the number of input points within each grid cell. + :param country_boundary: Layer defining the country boundary to clip the grid. + :param cellsize: The size of each grid cell. + :param output_path: Path to save the output raster. + :param crs: The CRS in which the grid and raster will be projected. + :param input_points: Layer of point features to count within each grid cell. + """ + + # Create grid + self.h_spacing = 100 + self.v_spacing = 100 + create_grid = GridCreator(h_spacing=self.h_spacing, v_spacing=self.v_spacing) + output_dir = os.path.join("output") + merged_output_path = os.path.join(output_dir, "merged_grid.gpkg") + grid_layer = create_grid.create_grids( + self.country_boundary, output_dir, self.crs, merged_output_path + ) + grid_layer = QgsVectorLayer(merged_output_path, "merged_grid", "ogr") + + # Add score field + provider = grid_layer.dataProvider() + field_name = "score" + if not grid_layer.fields().indexFromName(field_name) >= 0: + provider.addAttributes([QgsField(field_name, QVariant.Int)]) + grid_layer.updateFields() + + # Create spatial index for the input points + # Reproject the country layer if necessary + if self.input_points.crs() != self.crs: + self.input_points = processing.run( + "native:reprojectlayer", + { + "INPUT": self.input_points, + "TARGET_CRS": self.crs, + "OUTPUT": "memory:", + }, + feedback=QgsProcessingFeedback(), + )["OUTPUT"] + point_index = QgsSpatialIndex(self.input_points.getFeatures()) + + # Count points within each grid cell and assign a score + reclass_vals = {} + for grid_feat in grid_layer.getFeatures(): + grid_geom = grid_feat.geometry() + # Get intersecting points + intersecting_points = point_index.intersects(grid_geom.boundingBox()) + num_points = len(intersecting_points) + + # Reclassification logic: assign score based on the number of points + if num_points >= 2: + reclass_val = 5 + elif num_points == 1: + reclass_val = 3 + else: + reclass_val = 0 + + reclass_vals[grid_feat.id()] = reclass_val + + # Step 5: Apply the score values to the grid + grid_layer.startEditing() + for grid_feat in grid_layer.getFeatures(): + grid_layer.changeAttributeValue( + grid_feat.id(), + provider.fieldNameIndex(field_name), + reclass_vals[grid_feat.id()], + ) + grid_layer.commitChanges() + + extents_processor = Extents( + output_dir, self.country_boundary, self.pixel_size, self.crs + ) + + # Get the extent of the vector layer + country_extent = extents_processor.get_country_extent() + xmin, ymin, xmax, ymax = ( + country_extent.xMinimum(), + country_extent.yMinimum(), + country_extent.xMaximum(), + country_extent.yMaximum(), + ) + + # Rasterize the clipped grid layer to generate the raster + rasterize_params = { + "INPUT": grid_layer, + "FIELD": field_name, + "BURN": 0, + "USE_Z": False, + "UNITS": 1, + "WIDTH": self.pixel_size, + "HEIGHT": self.pixel_size, + "EXTENT": f"{xmin},{xmax},{ymin},{ymax}", + "NODATA": -9999, + "OPTIONS": "", + "DATA_TYPE": 5, # Use Int32 for scores + "OUTPUT": self.output_path, + } + + processing.run( + "gdal:rasterize", rasterize_params, feedback=QgsProcessingFeedback() + ) diff --git a/test/test_points_per_grid_cell.py b/test/test_points_per_grid_cell.py new file mode 100644 index 0000000..f495590 --- /dev/null +++ b/test/test_points_per_grid_cell.py @@ -0,0 +1,88 @@ +import unittest +import os +from qgis.core import ( + QgsVectorLayer, + QgsCoordinateReferenceSystem, + QgsProject, + QgsRectangle, +) +from qgis_gender_indicator_tool.jobs.points_per_grid_cell import ( + RasterFromScore, +) # Adjust the path to your class + + +class TestRasterFromScore(unittest.TestCase): + """Test the RasterFromScore class.""" + + def test_raster_from_score(self): + """ + Test raster generation using the RasterFromScore class. + """ + self.working_dir = os.path.dirname(__file__) + self.test_data_dir = os.path.join(self.working_dir, "test_data") + + # Load the input data (points and country boundary layers) + self.point_layer = QgsVectorLayer( + os.path.join(self.test_data_dir, "points/points.shp"), "test_points", "ogr" + ) + self.country_boundary = os.path.join(self.test_data_dir, "admin/Admin0.shp") + + self.assertTrue(self.point_layer.isValid(), "The point layer is not valid.") + + # Define output path for the generated raster + self.output_path = os.path.join( + self.working_dir, "output", "test_points_per_grid_cell.tif" + ) + os.makedirs(os.path.join(self.working_dir, "output"), exist_ok=True) + + # Define CRS (for example UTM Zone 20N) + self.crs = QgsCoordinateReferenceSystem("EPSG:32620") + self.pixel_size = 100 # 100m grid + + # Create an instance of the RasterFromScore class + rasterizer = RasterFromScore( + country_boundary=self.country_boundary, + pixel_size=self.pixel_size, + output_path=self.output_path, + crs=self.crs, + input_points=self.point_layer, + ) + + # Run the raster_from_score method + rasterizer.raster_from_score() + + # Load the generated raster layer to verify its validity + # Verify that the raster file was created + self.assertTrue( + os.path.exists(self.output_path), "The raster output file was not created." + ) + raster_layer = QgsVectorLayer(self.output_path, "test_raster", "gdal") + self.assertTrue( + raster_layer.isValid(), "The generated raster layer is not valid." + ) + + # Verify raster statistics (e.g., minimum, maximum, mean) + stats = raster_layer.dataProvider().bandStatistics( + 1 + ) # Get statistics for the first band + expected_min = ( + 0 # Update this with the actual expected value based on your data + ) + expected_max = ( + 3 # Update this with the actual expected value based on your data + ) + + self.assertAlmostEqual( + stats.minimumValue, + expected_min, + msg=f"Minimum value does not match: {stats.minimumValue}", + ) + self.assertAlmostEqual( + stats.maximumValue, + expected_max, + msg=f"Maximum value does not match: {stats.maximumValue}", + ) + + +if __name__ == "__main__": + unittest.main() From 920f7e52672a618381133f3c71a283dffd77ebfb Mon Sep 17 00:00:00 2001 From: Jeff Osundwa Date: Thu, 19 Sep 2024 02:08:57 +0300 Subject: [PATCH 2/5] updated create grids function to remove lock files --- src/qgis_gender_indicator_tool/jobs/create_grids.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qgis_gender_indicator_tool/jobs/create_grids.py b/src/qgis_gender_indicator_tool/jobs/create_grids.py index 1b97fe1..24d4902 100644 --- a/src/qgis_gender_indicator_tool/jobs/create_grids.py +++ b/src/qgis_gender_indicator_tool/jobs/create_grids.py @@ -31,9 +31,7 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): # Check if the merged grid already exists if os.path.exists(merged_output_path): print(f"Merged grid already exists: {merged_output_path}") - return QgsVectorLayer( - merged_output_path, "merged_grid", "ogr" - ) # Load the existing merged grid layer + return merged_output_path layer = QgsVectorLayer(layer, "country_layer", "ogr") if not layer.isValid(): @@ -118,4 +116,12 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): print(f"Merging grids into: {merged_output_path}") merge_params = {"LAYERS": all_grids, "CRS": crs, "OUTPUT": merged_output_path} merged_grid = processing.run("native:mergevectorlayers", merge_params)["OUTPUT"] + lock_files = [ + f"{merged_output_path}-journal", + f"{merged_output_path}-wal", + f"{merged_output_path}-shm", + ] + for lock_file in lock_files: + if os.path.exists(lock_file): + os.remove(lock_file) return merged_grid From 4f2b10699c50f4a0e02352e9ab4da8139828325d Mon Sep 17 00:00:00 2001 From: Jeff Osundwa Date: Thu, 19 Sep 2024 11:41:41 +0300 Subject: [PATCH 3/5] fix: fix for points per grid score(error reading grid) --- .../jobs/create_grids.py | 20 +++++++++------- .../jobs/points_per_grid_cell.py | 13 ++++++++--- test/test_points_per_grid_cell.py | 23 +++++++++---------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/qgis_gender_indicator_tool/jobs/create_grids.py b/src/qgis_gender_indicator_tool/jobs/create_grids.py index 24d4902..8c782b8 100644 --- a/src/qgis_gender_indicator_tool/jobs/create_grids.py +++ b/src/qgis_gender_indicator_tool/jobs/create_grids.py @@ -81,6 +81,17 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): grid_layer = QgsVectorLayer( grid_output_path, "grid_layer", "ogr" ) # Load the existing grid layer + # Clip the grid to the polygon feature (to restrict it to the boundaries) + clipped_grid_output_path = ( + f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.gpkg" + ) + clip_params = { + "INPUT": grid_layer, # The grid we just created + "OVERLAY": layer, # The layer we're clipping to + "OUTPUT": clipped_grid_output_path, + } + clip_result = processing.run("native:clip", clip_params) + grid_layer = clip_result["OUTPUT"] # The clipped grid else: print(f"Creating grid: {grid_output_path}") # Define grid creation parameters @@ -116,12 +127,5 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): print(f"Merging grids into: {merged_output_path}") merge_params = {"LAYERS": all_grids, "CRS": crs, "OUTPUT": merged_output_path} merged_grid = processing.run("native:mergevectorlayers", merge_params)["OUTPUT"] - lock_files = [ - f"{merged_output_path}-journal", - f"{merged_output_path}-wal", - f"{merged_output_path}-shm", - ] - for lock_file in lock_files: - if os.path.exists(lock_file): - os.remove(lock_file) + return merged_grid diff --git a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py index e0bdd13..589dc2b 100644 --- a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py +++ b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py @@ -11,7 +11,7 @@ from .extents import Extents -class RasterFromScore: +class RasterPointGridScore: def __init__(self, country_boundary, pixel_size, output_path, crs, input_points): self.country_boundary = country_boundary self.pixel_size = pixel_size @@ -19,7 +19,7 @@ def __init__(self, country_boundary, pixel_size, output_path, crs, input_points) self.crs = crs self.input_points = input_points - def raster_from_score(self): + def raster_point_grid_score(self): """ Generates a raster based on the number of input points within each grid cell. :param country_boundary: Layer defining the country boundary to clip the grid. @@ -89,6 +89,13 @@ def raster_from_score(self): ) grid_layer.commitChanges() + Merge = processing.run( + "native:mergevectorlayers", + {"LAYERS": [grid_layer], "CRS": None, "OUTPUT": "memory:"}, + ) + + merge = Merge["OUTPUT"] + extents_processor = Extents( output_dir, self.country_boundary, self.pixel_size, self.crs ) @@ -104,7 +111,7 @@ def raster_from_score(self): # Rasterize the clipped grid layer to generate the raster rasterize_params = { - "INPUT": grid_layer, + "INPUT": merge, "FIELD": field_name, "BURN": 0, "USE_Z": False, diff --git a/test/test_points_per_grid_cell.py b/test/test_points_per_grid_cell.py index f495590..3631f5b 100644 --- a/test/test_points_per_grid_cell.py +++ b/test/test_points_per_grid_cell.py @@ -2,21 +2,20 @@ import os from qgis.core import ( QgsVectorLayer, + QgsRasterLayer, QgsCoordinateReferenceSystem, - QgsProject, - QgsRectangle, ) from qgis_gender_indicator_tool.jobs.points_per_grid_cell import ( - RasterFromScore, + RasterPointGridScore, ) # Adjust the path to your class -class TestRasterFromScore(unittest.TestCase): - """Test the RasterFromScore class.""" +class TestRasterPointGridScore(unittest.TestCase): + """Test the RasterPointGridScore class.""" - def test_raster_from_score(self): + def test_raster_point_grid_score(self): """ - Test raster generation using the RasterFromScore class. + Test raster generation using the RasterPointGridScore class. """ self.working_dir = os.path.dirname(__file__) self.test_data_dir = os.path.join(self.working_dir, "test_data") @@ -39,8 +38,8 @@ def test_raster_from_score(self): self.crs = QgsCoordinateReferenceSystem("EPSG:32620") self.pixel_size = 100 # 100m grid - # Create an instance of the RasterFromScore class - rasterizer = RasterFromScore( + # Create an instance of the RasterPointGridScore class + rasterizer = RasterPointGridScore( country_boundary=self.country_boundary, pixel_size=self.pixel_size, output_path=self.output_path, @@ -48,15 +47,15 @@ def test_raster_from_score(self): input_points=self.point_layer, ) - # Run the raster_from_score method - rasterizer.raster_from_score() + # Run the raster_point_grid_score method + rasterizer.raster_point_grid_score() # Load the generated raster layer to verify its validity # Verify that the raster file was created self.assertTrue( os.path.exists(self.output_path), "The raster output file was not created." ) - raster_layer = QgsVectorLayer(self.output_path, "test_raster", "gdal") + raster_layer = QgsRasterLayer(self.output_path, "test_raster", "gdal") self.assertTrue( raster_layer.isValid(), "The generated raster layer is not valid." ) From c160232138df0302acb845a16f6a31371117e5a1 Mon Sep 17 00:00:00 2001 From: Jeff Osundwa Date: Fri, 20 Sep 2024 02:16:44 +0300 Subject: [PATCH 4/5] reverted to use of shapfiles and memory(due lock files issues with gpkg) --- .../jobs/create_grids.py | 190 +++++++++--------- .../jobs/points_per_grid_cell.py | 11 +- test/test_create_grids.py | 2 +- 3 files changed, 104 insertions(+), 99 deletions(-) diff --git a/src/qgis_gender_indicator_tool/jobs/create_grids.py b/src/qgis_gender_indicator_tool/jobs/create_grids.py index 8c782b8..c65fc87 100644 --- a/src/qgis_gender_indicator_tool/jobs/create_grids.py +++ b/src/qgis_gender_indicator_tool/jobs/create_grids.py @@ -32,100 +32,100 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): if os.path.exists(merged_output_path): print(f"Merged grid already exists: {merged_output_path}") return merged_output_path - - layer = QgsVectorLayer(layer, "country_layer", "ogr") - if not layer.isValid(): - raise ValueError("Invalid country layer") - - # Reproject the country layer if necessary - if layer.crs() != crs: - layer = processing.run( - "native:reprojectlayer", - { - "INPUT": layer, - "TARGET_CRS": crs, - "OUTPUT": "memory:", - }, - feedback=QgsProcessingFeedback(), - )["OUTPUT"] - - all_grids = [] - - # Loop through each feature in the polygon layer - for feature in layer.getFeatures(): - geom = feature.geometry() - - # Check if the geometry is multipart - if geom.isMultipart(): - parts = ( - geom.asGeometryCollection() - ) # Separate multipart geometry into parts - else: - parts = [geom] # Single part geometry - - # Loop through each part of the geometry - for part_id, part in enumerate(parts): - part_area = part.area() - - # Get the extent of each part - part_extent = part.boundingBox() - - # Define the output grid path for each part - grid_output_path = ( - f"{output_dir}/grid_{feature.id()}_part_{part_id}.gpkg" - ) - - # Check if the grid already exists - if os.path.exists(grid_output_path): - print(f"Grid file already exists: {grid_output_path}") - grid_layer = QgsVectorLayer( - grid_output_path, "grid_layer", "ogr" - ) # Load the existing grid layer - # Clip the grid to the polygon feature (to restrict it to the boundaries) - clipped_grid_output_path = ( - f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.gpkg" - ) - clip_params = { - "INPUT": grid_layer, # The grid we just created - "OVERLAY": layer, # The layer we're clipping to - "OUTPUT": clipped_grid_output_path, - } - clip_result = processing.run("native:clip", clip_params) - grid_layer = clip_result["OUTPUT"] # The clipped grid + else: + layer = QgsVectorLayer(layer, "country_layer", "ogr") + if not layer.isValid(): + raise ValueError("Invalid country layer") + + # Reproject the country layer if necessary + if layer.crs() != crs: + layer = processing.run( + "native:reprojectlayer", + { + "INPUT": layer, + "TARGET_CRS": crs, + "OUTPUT": "memory:", + }, + feedback=QgsProcessingFeedback(), + )["OUTPUT"] + + all_grids = [] + + # Loop through each feature in the polygon layer + for feature in layer.getFeatures(): + geom = feature.geometry() + + # Check if the geometry is multipart + if geom.isMultipart(): + parts = ( + geom.asGeometryCollection() + ) # Separate multipart geometry into parts else: - print(f"Creating grid: {grid_output_path}") - # Define grid creation parameters - grid_params = { - "TYPE": 2, # Rectangle (polygon) - "EXTENT": part_extent, # Use the extent of the current part - "HSPACING": self.h_spacing, # Horizontal spacing - "VSPACING": self.v_spacing, # Vertical spacing - "CRS": crs, # Coordinate reference system (CRS) - "OUTPUT": grid_output_path, # Output path for the grid file - } - - # Create the grid using QGIS processing - grid_result = processing.run("native:creategrid", grid_params) - grid_layer = grid_result["OUTPUT"] # Get the grid layer - - # Clip the grid to the polygon feature (to restrict it to the boundaries) - clipped_grid_output_path = ( - f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.gpkg" + parts = [geom] # Single part geometry + + # Loop through each part of the geometry + for part_id, part in enumerate(parts): + part_area = part.area() + + # Get the extent of each part + part_extent = part.boundingBox() + + # Define the output grid path for each part + grid_output_path = ( + f"{output_dir}/grid_{feature.id()}_part_{part_id}.shp" ) - clip_params = { - "INPUT": grid_layer, # The grid we just created - "OVERLAY": layer, # The layer we're clipping to - "OUTPUT": clipped_grid_output_path, - } - clip_result = processing.run("native:clip", clip_params) - grid_layer = clip_result["OUTPUT"] # The clipped grid - - # Add the generated or loaded grid to the list - all_grids.append(grid_layer) - - # Merge all grids into a single layer - print(f"Merging grids into: {merged_output_path}") - merge_params = {"LAYERS": all_grids, "CRS": crs, "OUTPUT": merged_output_path} - merged_grid = processing.run("native:mergevectorlayers", merge_params)["OUTPUT"] - - return merged_grid + + # Check if the grid already exists + if os.path.exists(grid_output_path): + print(f"Grid file already exists: {grid_output_path}") + grid_layer = QgsVectorLayer( + grid_output_path, "grid_layer", "ogr" + ) # Load the existing grid layer + # Clip the grid to the polygon feature (to restrict it to the boundaries) + clipped_grid_output_path = ( + f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" + ) + clip_params = { + "INPUT": grid_layer, # The grid we just created + "OVERLAY": layer, # The layer we're clipping to + "OUTPUT": clipped_grid_output_path, + } + clip_result = processing.run("native:clip", clip_params) + grid_layer = clip_result["OUTPUT"] # The clipped grid + else: + print(f"Creating grid: {grid_output_path}") + # Define grid creation parameters + grid_params = { + "TYPE": 2, # Rectangle (polygon) + "EXTENT": part_extent, # Use the extent of the current part + "HSPACING": self.h_spacing, # Horizontal spacing + "VSPACING": self.v_spacing, # Vertical spacing + "CRS": crs, # Coordinate reference system (CRS) + "OUTPUT": grid_output_path, # Output path for the grid file + } + + # Create the grid using QGIS processing + grid_result = processing.run("native:creategrid", grid_params) + grid_layer = grid_result["OUTPUT"] # Get the grid layer + + # Clip the grid to the polygon feature (to restrict it to the boundaries) + clipped_grid_output_path = ( + f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" + ) + clip_params = { + "INPUT": grid_layer, # The grid we just created + "OVERLAY": layer, # The layer we're clipping to + "OUTPUT": clipped_grid_output_path, + } + clip_result = processing.run("native:clip", clip_params) + grid_layer = clip_result["OUTPUT"] # The clipped grid + + # Add the generated or loaded grid to the list + all_grids.append(grid_layer) + + # Merge all grids into a single layer + print(f"Merging grids into: {merged_output_path}") + merge_params = {"LAYERS": all_grids, "CRS": crs, "OUTPUT": merged_output_path} + merged_grid = processing.run("native:mergevectorlayers", merge_params)["OUTPUT"] + + return merged_grid diff --git a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py index 589dc2b..4211cd3 100644 --- a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py +++ b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py @@ -34,7 +34,9 @@ def raster_point_grid_score(self): self.v_spacing = 100 create_grid = GridCreator(h_spacing=self.h_spacing, v_spacing=self.v_spacing) output_dir = os.path.join("output") - merged_output_path = os.path.join(output_dir, "merged_grid.gpkg") + merged_output_path = os.path.join(output_dir, "merged_grid.shp") # Use Shapefile + + # Create grid layer using Shapefile grid_layer = create_grid.create_grids( self.country_boundary, output_dir, self.crs, merged_output_path ) @@ -79,7 +81,7 @@ def raster_point_grid_score(self): reclass_vals[grid_feat.id()] = reclass_val - # Step 5: Apply the score values to the grid + # Apply the score values to the grid grid_layer.startEditing() for grid_feat in grid_layer.getFeatures(): grid_layer.changeAttributeValue( @@ -89,9 +91,12 @@ def raster_point_grid_score(self): ) grid_layer.commitChanges() + merged_output_vector = os.path.join(output_dir, "merged_grid_vector.shp") # Use Shapefile for merged output + + # Merge grids into a single Shapefile layer Merge = processing.run( "native:mergevectorlayers", - {"LAYERS": [grid_layer], "CRS": None, "OUTPUT": "memory:"}, + {"LAYERS": [grid_layer], "CRS": None, "OUTPUT": 'memory:'}, ) merge = Merge["OUTPUT"] diff --git a/test/test_create_grids.py b/test/test_create_grids.py index 292da07..1d4005a 100644 --- a/test/test_create_grids.py +++ b/test/test_create_grids.py @@ -22,7 +22,7 @@ def test_create_grids(self): os.path.dirname(__file__), "test_data/admin/Admin0.shp" ) self.output_dir = os.path.join(os.path.dirname(__file__), "output") - self.merged_output_path = os.path.join(self.output_dir, "merged_grid.gpkg") + self.merged_output_path = os.path.join(self.output_dir, "merged_grid.shp") self.utm_crs = QgsCoordinateReferenceSystem("EPSG:32620") # UTM Zone 20N self.h_spacing = 100 self.v_spacing = 100 From 8e5b1b798235a3e6fd58a82e7c6e99919d22cb19 Mon Sep 17 00:00:00 2001 From: Jeff Osundwa Date: Fri, 20 Sep 2024 02:21:34 +0300 Subject: [PATCH 5/5] black format --- .../jobs/create_grids.py | 18 ++++++++++-------- .../jobs/points_per_grid_cell.py | 10 +++++++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/qgis_gender_indicator_tool/jobs/create_grids.py b/src/qgis_gender_indicator_tool/jobs/create_grids.py index c65fc87..67685ee 100644 --- a/src/qgis_gender_indicator_tool/jobs/create_grids.py +++ b/src/qgis_gender_indicator_tool/jobs/create_grids.py @@ -82,9 +82,7 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): grid_output_path, "grid_layer", "ogr" ) # Load the existing grid layer # Clip the grid to the polygon feature (to restrict it to the boundaries) - clipped_grid_output_path = ( - f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" - ) + clipped_grid_output_path = f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" clip_params = { "INPUT": grid_layer, # The grid we just created "OVERLAY": layer, # The layer we're clipping to @@ -109,9 +107,7 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): grid_layer = grid_result["OUTPUT"] # Get the grid layer # Clip the grid to the polygon feature (to restrict it to the boundaries) - clipped_grid_output_path = ( - f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" - ) + clipped_grid_output_path = f"{output_dir}/clipped_grid_{feature.id()}_part_{part_id}.shp" clip_params = { "INPUT": grid_layer, # The grid we just created "OVERLAY": layer, # The layer we're clipping to @@ -125,7 +121,13 @@ def create_grids(self, layer, output_dir, crs, merged_output_path): # Merge all grids into a single layer print(f"Merging grids into: {merged_output_path}") - merge_params = {"LAYERS": all_grids, "CRS": crs, "OUTPUT": merged_output_path} - merged_grid = processing.run("native:mergevectorlayers", merge_params)["OUTPUT"] + merge_params = { + "LAYERS": all_grids, + "CRS": crs, + "OUTPUT": merged_output_path, + } + merged_grid = processing.run("native:mergevectorlayers", merge_params)[ + "OUTPUT" + ] return merged_grid diff --git a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py index 4211cd3..a1dd6b5 100644 --- a/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py +++ b/src/qgis_gender_indicator_tool/jobs/points_per_grid_cell.py @@ -34,7 +34,9 @@ def raster_point_grid_score(self): self.v_spacing = 100 create_grid = GridCreator(h_spacing=self.h_spacing, v_spacing=self.v_spacing) output_dir = os.path.join("output") - merged_output_path = os.path.join(output_dir, "merged_grid.shp") # Use Shapefile + merged_output_path = os.path.join( + output_dir, "merged_grid.shp" + ) # Use Shapefile # Create grid layer using Shapefile grid_layer = create_grid.create_grids( @@ -91,12 +93,14 @@ def raster_point_grid_score(self): ) grid_layer.commitChanges() - merged_output_vector = os.path.join(output_dir, "merged_grid_vector.shp") # Use Shapefile for merged output + merged_output_vector = os.path.join( + output_dir, "merged_grid_vector.shp" + ) # Use Shapefile for merged output # Merge grids into a single Shapefile layer Merge = processing.run( "native:mergevectorlayers", - {"LAYERS": [grid_layer], "CRS": None, "OUTPUT": 'memory:'}, + {"LAYERS": [grid_layer], "CRS": None, "OUTPUT": "memory:"}, ) merge = Merge["OUTPUT"]