1

I have a vector layer containing around 17000 polygons with a field named 'theme'. Each polygon of the layer has one of 30 unique values (e.g. buildings, roads etc.) assigned to this field. I now want to add a field to each polygon, the field should be named after the field 'theme' and contain the area of the polygon (e.g. a Polygon with the attribute 'buildings' in the field 'theme' gets a new field called 'buildings' containing it's area). In Model Builder I can use the expression editor for the field name, my thinking was that I could get what I want with the expression: attribute( $currentfeature ,'theme') which does not add any new fields to the output at all (it does not generate any errors as well though).

Is this possible with Model Builder? Did I even use the correct expression or do I need to write some code to get this done?

The only way I found that works is creating 30 field calculators, one for each unique value and a lot of expression madness to only populate certain fields for certain values, since the Values might differ on a project basis this is really time consuming.

3
  • What's about using the expression concat("theme", ' - ', $area) to create a new field using the FIeld Calculator? It would be doing the job are you looking for.
    – Val P
    Jul 1, 2020 at 19:09
  • in your example, your final file with have "buildings" field and a "roads", but they'll only be populate in the records where [theme] == {fieldname}?
    – Paul H
    Jul 1, 2020 at 21:44
  • also, can you use pthon + geopandas? this would be easy in geopandas
    – Paul H
    Jul 1, 2020 at 21:45

2 Answers 2

1

You can use SQL to generate what you want without any processing

Go to https://www.naturalearthdata.com/downloads/10m-cultural-vectors/10m-admin-0-countries/ take the ne_10m_admin_0_countries.shp and create a virtual layer using the following

SELECT "NAME",
CASE
  WHEN "REGION_UN" = 'Asia' THEN St_Area(geometry)
  ELSE NULL
END AS asia,
CASE
  WHEN "REGION_UN" = 'Africa' THEN St_Area(geometry)
  ELSE NULL
END AS africa,
CASE
  WHEN "REGION_UN" = 'Americas' THEN St_Area(geometry)
  ELSE NULL
END AS americas,
CASE
  WHEN "REGION_UN" = 'Oceania' THEN St_Area(geometry)
  ELSE NULL
END AS oceania,
CASE
  WHEN "REGION_UN" = 'Antarctica' THEN St_Area(geometry)
  ELSE NULL
END AS antarctica,
CASE
  WHEN "REGION_UN" = 'Europe' THEN St_Area(geometry)
  ELSE NULL
END AS europe,
CASE
  WHEN "REGION_UN" = 'Seven seas (open ocean)' THEN St_Area(geometry)
  ELSE NULL
END AS seven_seas,
geometry
FROM ne_10m_admin_0_countries

This code could be generated as it seems you will need it more than one time depending of your attributes. You can see below a code to create the virtual layer

vectorLayer = iface.activeLayer()
unique_col = 'REGION_UN'
other_cols = ['NAME']
geometry_col = ['Geometry']
idx = vectorLayer.fields().indexOf(unique_col)
values = vectorLayer.uniqueValues(idx)
table = iface.activeLayer().name()

cols = []
for val in values:
    cols.append("""CASE
      WHEN "{0}" = '{1}' THEN St_Area(geometry)
      ELSE NULL
    END AS {2}""".format(unique_col, val, val.replace(' ','_').replace(')','').replace('(','').lower())
    )

query = """SELECT {0} FROM {1}""".format(', '.join(other_cols + cols + geometry_col), table)
print(query)

from qgis.core import QgsVectorLayer, QgsProject

vlayer = QgsVectorLayer( "?query={}".format(query), "vlayer", "virtual" )
QgsProject.instance().addMapLayer(vlayer)
0

If you can use geopandas and I understand correctly that you want ~30 sparse fields for each value of theme, here's how I would do it:

import numpy
import geopandas

def make_a_bunch_of_sparse_fields(df, catcol):
    new_fields = {
        category: lambda df: numpy.where(
            df[catcol] == category,
            f"{field} - {df['geometrty'].area.round(2)}",
            None
        )
        for category in df[catcol].unique()
    }
    return df.assign(**new_fields)

(
    geopandas.read_file(path_to_shpfile)
      .pipe(make_a_bunch_of_sparse_fields, 'theme')
      .to_file(path_to_shpfile)
)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.