Created
May 14, 2025 15:39
-
-
Save sfkeller/7dca8ab5fa8c6f754ca384218dcb0aa8 to your computer and use it in GitHub Desktop.
This QGS Python API script enables features in a vector layer to be filtered dynamically according to the layer's current visible extent on the map canvas.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| QGIS Dynamic Filtering Script | |
| Usage: | |
| 0. Ensure your vector dataset contains a ranking field, then load it into QGIS. | |
| 1. Adapt 'LAYER_NAME' and 'SQL_FILTER_TEMPLATE' in the 'Constants' section below. | |
| 2. Open the Python console in QGIS, then open and execute this script. | |
| 3. To disable filtering, copy and paste the following into the Python console: | |
| disable_dynamic_filter() | |
| This script enables features in a vector layer to be filtered dynamically | |
| according to the layer's current visible extent on the map canvas. Only the e.g. | |
| 50 highest-ranked visible features are displayed (depending on a customizable | |
| filter query). | |
| It is assumed that there is a vector dataset containing a ranking field (e.g. | |
| 'qrank'). Here's an example (no guarantee how long this storage will last): | |
| https://drive.switch.ch/index.php/s/RsYy9oBxWfad1am | |
| """ | |
| # Constants | |
| LAYER_NAME = "castles_etc_ranked_osm_2025" | |
| SQL_FILTER_TEMPLATE = """ | |
| SELECT * FROM "{layer_name}" | |
| WHERE "X" BETWEEN {x_min} AND {x_max} | |
| AND "Y" BETWEEN {y_min} AND {y_max} | |
| ORDER BY qrank DESC LIMIT 50 | |
| """ | |
| def update_filter_on_extent_change(): | |
| """Update the layer filter whenever the map canvas extent changes.""" | |
| # Get the current map canvas | |
| canvas = iface.mapCanvas() | |
| # Get the current extent | |
| extent = canvas.extent() | |
| try: | |
| # Get the layer by name | |
| layer = QgsProject.instance().mapLayersByName(LAYER_NAME)[0] | |
| # Transform coordinates if needed | |
| layer_crs = layer.crs() | |
| canvas_crs = canvas.mapSettings().destinationCrs() | |
| if layer_crs != canvas_crs: | |
| transform = QgsCoordinateTransform(canvas_crs, layer_crs, QgsProject.instance()) | |
| extent = transform.transformBoundingBox(extent) | |
| # Create the SQL filter with the current extent coordinates | |
| sql_filter = SQL_FILTER_TEMPLATE.format( | |
| layer_name=LAYER_NAME, | |
| x_min=extent.xMinimum(), | |
| x_max=extent.xMaximum(), | |
| y_min=extent.yMinimum(), | |
| y_max=extent.yMaximum() | |
| ) | |
| # Apply the filter to the layer | |
| layer.setSubsetString(sql_filter) | |
| # Refresh the layer | |
| layer.triggerRepaint() | |
| except IndexError: | |
| print(f"Error: Layer '{LAYER_NAME}' not found") | |
| except Exception as e: | |
| print(f"Error updating filter: {e}") | |
| def disable_dynamic_filter(): | |
| """Disable the dynamic filter and restore full layer visibility. | |
| To disable the filter, copy and paste this function call: | |
| disable_dynamic_filter() | |
| """ | |
| try: | |
| # Get the layer by name | |
| layer = QgsProject.instance().mapLayersByName(LAYER_NAME)[0] | |
| # Remove filter query | |
| layer.setSubsetString("") | |
| # Disconnect the extent changed signal | |
| iface.mapCanvas().extentsChanged.disconnect(update_filter_function) | |
| print(f"Dynamic filter disabled for layer '{LAYER_NAME}'") | |
| # Refresh the layer | |
| layer.triggerRepaint() | |
| except IndexError: | |
| print(f"Error: Layer '{LAYER_NAME}' not found") | |
| except NameError: | |
| print("Error: update_filter_function not defined") | |
| except Exception as e: | |
| print(f"Error removing dynamic filter: {e}") | |
| # Store a reference to our function | |
| global update_filter_function | |
| update_filter_function = update_filter_on_extent_change | |
| # Connect the function to the extentChanged signal | |
| iface.mapCanvas().extentsChanged.connect(update_filter_function) | |
| # Run it once to set the initial filter | |
| update_filter_function() | |
| print("Dynamic filtering enabled. To disable, run 'disable_dynamic_filter()' in the Python console.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment