# PyQGIS QgsExpression which categorizes the values of a field in a new field

I have a code that works well in the GUI for the field calculator but I am trying to make it work in the python console of QGIS. Firstly I start off with a roads then calculate the azimuth of the road with this PyQGIS code:

``````fp = "C:/Users/my/file/path/roads.geojson"
pv = layer.dataProvider()
layer.updateFields()
print (layer.fields().names())
``````

The field "azimuth" is successfully created. Next is to calculate the azimuth using the method answered in the question below. Adding Direction and Distance into Attribute table

``````expression1 = QgsExpression('CASE WHEN ((yat(-1)-yat(0)) = 0 and (xat(-1) - xat(0)) >0) THEN 90 WHEN ((yat(-1)-yat(0)) = 0 and (xat(-1) - xat(0)) <0) THEN 270 ELSE (atan((xat(-1)-xat(0))/(yat(-1)-yat(0)))) * 180/pi() + (180 * (((yat(-1)-yat(0)) < 0) + (((xat(-1)-xat(0)) < 0 AND (yat(-1) - yat(0)) > 0)*2))) END')
context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))
with edit(layer):
for f in layer.getFeatures():
context.setFeature(f)
f['azimuth'] = expression1.evaluate(context)
layer.updateFeature(f)
``````

My goal is to categorize the roads by quadrant. In the field calculator GUI of QGIS the following code works perfectly.

``````CASE
WHEN  (0.000 <= "azimuth" AND "azimuth" <= 90.000 )THEN 'quad-1'
WHEN  (90.000 < "azimuth" AND "azimuth"  <= 180.000 )THEN 'quad-2'
WHEN  (180.000 < "azimuth" AND "azimuth" <= 270.000 )THEN 'quad-3'
WHEN  (270.000 < "azimuth" AND "azimuth" <= 360.000 )THEN 'quad-4'
END
``````

I have not been able to find documentation for PyQGIS where the expression references values from an existing column to add a text string to a new column. The expression from the documentation is very simple. 11. Expressions, Filtering and Calculating Values I know that the field (column) name must be in a double quote "azimuth" was the previously created column where I calculated the az as a decimal. My attempt looks like:

``````pv = layer.dataProvider()

layer.updateFields()

print (layer.fields().names())
## or
for field in layer.fields():
print(field.name(), field.typeName())

e = QgsExpression('CASE WHEN  (0.000 <= "azimuth" AND "azimuth" <= 90.000 )THEN "quad-1" WHEN  (90.000 < "azimuth" AND "azimuth"  <= 180.000 )THEN "quad-2" WHEN  (180.000 < "azimuth" AND "azimuth" <= 270.000 )THEN "quad-3" WHEN  (270.000 < "azimuth" AND "azimuth" <= 360.000 )THEN "quad-4" END')

context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

with edit(layer):
for f in layer.getFeatures():
context.setFeature(f)
layer.updateFeature(f)
``````

The only difference between the python equation and the GUI field calculator was that I changed the single quote to double quote to get rid of the syntax error. It does not add any values to the az_cat column.

In QGIS expressions, double quotes are strictly for field names, single quotes are string literals, so I guess that in your Python attempt, the expression evaluation is looking for fields called "quad-1", "quad-2" etc. Therefore, you should remove the double quotes from your string values.

I have found that parsing QGIS expressions into Python syntax can be tricky. I have also found in the past that wrapping the entire expression in triple double quotes often works. I tested this with your expression and it worked for me.

Modified code:

``````pv = layer.dataProvider()

layer.updateFields()

e = QgsExpression("""CASE
WHEN (0.000 <= "azimuth" AND "azimuth" <= 90.000 )THEN 'quad-1'
WHEN (90.000 < "azimuth" AND "azimuth"  <= 180.000 )THEN 'quad-2'
WHEN (180.000 < "azimuth" AND "azimuth" <= 270.000 )THEN 'quad-3'
WHEN (270.000 < "azimuth" AND "azimuth" <= 360.000 )THEN 'quad-4'
END""")

context = QgsExpressionContext()
context.appendScopes(QgsExpressionContextUtils.globalProjectLayerScopes(layer))

with edit(layer):
for f in layer.getFeatures():
context.setFeature(f)
layer.updateFeature(f)
``````

Example result: I played around some more and this also worked (no quotes around field names and single quotes around strings; whole expression wrapped in double quotes).

``````e = QgsExpression("CASE WHEN 0.000 <= azimuth AND azimuth <= 90.000 THEN 'quad-1' WHEN 90.000 < azimuth AND azimuth  <= 180.000 THEN 'quad-2' WHEN 180.000 < azimuth AND azimuth <= 270.000 THEN 'quad-3' WHEN 270.000 < azimuth AND azimuth <= 360.000 THEN 'quad-4' END")
``````

Another option is to calculate and update the new values entirely with PyQGIS. An example of that (which produced the identical result) looks like this:

``````pv = layer.dataProvider()

layer.updateFields()

# retrieve index of 'az_quad' field

# a dictionary which will be populated with feature id keys and
# value dictionaries composed of field index and attribute value
att_map = {}

# loop through features and populate attribute map with values calculated
# from value in 'azimuth' field
for f in layer.getFeatures():
az = f['azimuth']
if az == NULL:
continue
if 0.000 <= az <= 90.000: