How to Automate Cleaning Vector Map Tiles/Labels in QGIS Using PyQGIS
25 Sep 26 (1mo ago)
The Challenge of Messy Vector Maps
When styling vector maps for design projects, map layers imported from sources like OpenStreetMap (OSM) or MapTiler often come loaded with an overwhelming amount of data. While having every residential street, alleyway, and Point of Interest (POI) is great for navigation, it creates a cluttered, spiderweb-like appearance when you only need a clean graphical map of main arteries.
While vector editing tools like Affinity Designer are excellent for final artistic touches, they lack native scripting APIs to batch-process these layers efficiently. Attempting to manually hide thousands of paths using "Select Same" workarounds is tedious.
The most efficient solution is to process the data directly in QGIS using Python (PyQGIS) before exporting your final vector file.
Automating Vector Tile Clean-Up in QGIS
Unlike standard shapefiles where you can apply a simple SQL subset string, Vector Tiles (like .mvt or MapTiler layers) rely on complex styling engines. You have to programmatically disable specific style rules and labeling engines.
Below is a comprehensive PyQGIS script designed to loop through your active vector tile layer and turn off minor roads, POIs, and all text labels in one click.
The PyQGIS Script
To use this, select your Vector Tile layer (e.g., MapTiler) in the QGIS layers panel, open the Python Console (Ctrl + Alt + P), and run the following code:
from qgis.core import QgsVectorTileLayer, QgsVectorTileBasicLabeling
# --- CONFIGURATION ---
RESET_ALL = False # True = Turn everything ON | False = Clean the map
DISABLE_ALL_LABELS = True # True = Hide ALL text | False = Only hide specific label keywords
# Keywords to hide in SYMBOLOGY (Visuals like lines/icons)
minor_keywords = [
'residential', 'service', 'unclassified', 'tertiary',
'footway', 'track', 'path', 'cycleway', 'pedestrian',
'living_street', 'minor', 'ferry',
'poi', 'place', 'shield', 'aerodrome', 'airport'
]
# ---------------------
layer = iface.activeLayer()
if isinstance(layer, QgsVectorTileLayer):
print(f"--- Processing Layer: {layer.name()} (Reset: {RESET_ALL}) ---")
# ==============================
# PART 1: SYMBOLOGY (Lines/Icons)
# ==============================
renderer = layer.renderer()
styles = renderer.styles()
new_styles = []
for style in styles:
s_name = style.styleName() if style.styleName() else ""
s_layer = style.layerName() if style.layerName() else ""
s_filter = style.filterExpression()
check_string = (s_name + " " + s_layer + " " + s_filter).lower()
if RESET_ALL:
style.setEnabled(True)
else:
is_minor = any(k in check_string for k in minor_keywords)
style.setEnabled(not is_minor) # Enable if NOT minor
new_styles.append(style)
renderer.setStyles(new_styles)
print("Symbology updated.")
# ==============================
# PART 2: LABELS (Text)
# ==============================
labeling = layer.labeling()
# Check if labeling is active and is the standard type
if labeling and isinstance(labeling, QgsVectorTileBasicLabeling):
l_styles = labeling.styles()
new_l_styles = []
for l_style in l_styles:
if RESET_ALL:
l_style.setEnabled(True)
elif DISABLE_ALL_LABELS:
l_style.setEnabled(False)
new_l_styles.append(l_style)
labeling.setStyles(new_l_styles)
layer.setLabeling(labeling) # Apply changes back to layer
print("Labels updated.")
else:
print("No active labeling found or incompatible labeling type.")
# ==============================
# REFRESH
# ==============================
layer.triggerRepaint()
iface.layerTreeView().refreshLayerSymbology(layer.id())
print("--- Map Cleaned ---")
else:
print("Error: Please select the MapTiler/Vector Tile Layer first.")
How It Works
- Symbology Targeting: The script extracts the
styleName,layerName, andfilterExpressionfrom the renderer. It cross-references these attributes against a list of keywords (likeresidential,poi, andshield) to safely disable only the visual clutter while strictly enforcing that main arteries remain active. - Label Nullification: Because QGIS processes text separately from vector lines, the script accesses the
QgsVectorTileBasicLabelingclass. By togglingDISABLE_ALL_LABELS = True, it instantly unchecks every rule-based label in the layer properties. - Non-Destructive: By toggling
RESET_ALL = Trueand running the script again, you can instantly recover all hidden data, making it highly flexible for iterative map design.