from qgis.core import * from qgis.PyQt.QtCore import QVariant import math --- Config --- source_layer = iface.activeLayer() fields_cats = ["Heterosexu", "Gay or les", "Bisexual", "Other", "Don't Know"] colors = ["#4e79a7", "#f28e2b", "#e15759", "#76b7b2", "#59a14f"] --- Output layer setup --- out_layer = QgsVectorLayer("Polygon?crs=" + source_layer.crs().authid(), "pie_fill", "memory") pr = out_layer.dataProvider() pr.addAttributes([ QgsField("fid", QVariant.Int), QgsField("category", QVariant.String), QgsField("pct", QVariant.Double), ]) out_layer.updateFields() feats_out = [] for feat in source_layer.getFeatures(): geom = feat.geometry() centroid = geom.centroid().asPoint() vals = [feat[f] or 0 for f in fields_cats] total = sum(vals) if total == 0: continue pcts = [v / total for v in vals] # Build a large spoke polygon, then intersect with the feature geometry # Use a radius large enough to always exceed the polygon extent bbox = geom.boundingBox() radius = math.sqrt(bbox.width()**2 + bbox.height()**2) start_angle = 90 # start at top (north) for i, (cat, pct) in enumerate(zip(fields_cats, pcts)): if pct == 0: continue end_angle = start_angle - (pct * 360) # Build wedge points steps = max(int(abs(pct * 360) / 2), 3) points = [QgsPointXY(centroid)] for s in range(steps + 1): angle_deg = start_angle - (pct * 360 * s / steps) angle_rad = math.radians(angle_deg) x = centroid.x() + radius * math.cos(angle_rad) y = centroid.y() + radius * math.sin(angle_rad) points.append(QgsPointXY(x, y)) points.append(QgsPointXY(centroid)) wedge_geom = QgsGeometry.fromPolygonXY([points]) clipped = geom.intersection(wedge_geom) if clipped and not clipped.isEmpty(): f = QgsFeature() f.setGeometry(clipped) f.setAttributes([feat.id(), cat, round(pct * 100, 2)]) feats_out.append(f) start_angle = end_angle pr.addFeatures(feats_out) out_layer.updateExtents() QgsProject.instance().addMapLayer(out_layer) Apply categorized style by category field cats = [] for cat, color in zip(fields_cats, colors): sym = QgsSymbol.defaultSymbol(out_layer.geometryType()) sym.setColor(QColor(color)) cats.append(QgsRendererCategory(cat, sym, cat)) renderer = QgsCategorizedSymbolRenderer("category", cats) out_layer.setRenderer(renderer) out_layer.triggerRepaint() print("Done! pie_fill layer added.") ![[SOE_2024.jpeg]]