Bringing this back as I have found a solution that some may be able to use. This seemed harder than it should be but I don't think the functionality exists yet for vector features.
It uses python to run in the QGIS console and refresh the symbology of a layer via the min-max of a selected field, everytime the user zooms or pans the canvas.
Layer name and attribute is defined at the beginning of the script.
Set continue_script to 0 and run again to pause the update of symbology.
Basic functionality but useful for some tasks.
from qgis.core import QgsProject, QgsFeatureRequest, QgsGraduatedSymbolRenderer, QgsRendererRange, QgsSymbol
from qgis.PyQt.QtGui import QColor
# Flag to control whether the script should continue running
continue_script = 1
#continue_script = 0" #this pauses the script
layer_name= 'name_of_your_layer'
field = 'attribute_name_to_be_used_for_range'
def update_graduated_symbology(layer_name):
global continue_script # Use the global flag
if continue_script == 0:
print("Script stopped by user.")
return
all_layers = QgsProject.instance().mapLayers().values()
layer = None
for l in all_layers:
if l.name() == layer_name:
layer = l
break
if layer is None:
print(f"Layer {layer_name} not found.")
return
# Get features within the current map extent
extent = iface.mapCanvas().extent()
request = QgsFeatureRequest().setFilterRect(extent)
features = layer.getFeatures(request)
min_val = float('inf')
max_val = float('-inf')
for feature in features:
val = feature[field]
min_val = min(min_val, val)
max_val = max(max_val, val)
# Fetch the existing renderer
renderer = layer.renderer()
if renderer.type() == 'graduatedSymbol':
try:
colors = [
QColor(255, 224, 224), # Very light red
QColor(255, 160, 160), # Lighter red
QColor(255, 0, 0), # Red
QColor(177, 0, 0), # Slightly less dark red
QColor(20, 0, 0) # Darker red
]
# Create 5 QgsRendererRange objects with different colors
ranges = []
interval = (max_val - min_val) / 5
# Get source symbol or create a new default one if it's None
source_symbol = renderer.sourceSymbol()
if source_symbol is None:
source_symbol = QgsSymbol.defaultSymbol(layer.geometryType())
for i in range(5):
lower = min_val + i * interval
upper = lower + interval
# Clone the source symbol
symbol = source_symbol.clone()
# Set the color
symbol.setColor(colors[i])
# Set the stroke color to be 20% darker than the fill color
if symbol.symbolLayerCount() > 0:
symbol_layer = symbol.symbolLayer(0)
if hasattr(symbol_layer, 'setStrokeColor'):
darker_stroke_color = colors[i].darker(120)
symbol_layer.setStrokeColor(darker_stroke_color)
#sets the color names with the actual values
new_range = QgsRendererRange(lower, upper, symbol, f'{lower} - {upper}') # Updated this line
ranges.append(new_range)
new_renderer = QgsGraduatedSymbolRenderer(field, ranges)
layer.setRenderer(new_renderer)
# Refresh the layer symbology in the layer tree
iface.layerTreeView().refreshLayerSymbology(layer.id())
except Exception as e:
''
#print(f"Error while setting renderer: {e}") # Debugging
# Explicitly trigger a refresh
layer.triggerRepaint()
# Function to stop the script
def stop_script():
global continue_script
continue_script = 0
print("Script will be stopped.")
# Function to restart the script
def restart_script():
global continue_script
continue_script = 1
print("Script will continue.")
# Connect the function to the extentsChanged signal
iface.mapCanvas().extentsChanged.connect(lambda: update_graduated_symbology(layer_name))