1

I have a vector layer with inner boundaries delineating certain land-use types in each discrete area.

Vector layer with discrete areas of land use

I also have a raster layer that contains information related to the vegetation found in each pixel.

Raster layer with vegetation classes for each pixel

What I would like to do is create a new feature in the vector layer whose field is a list of all unique values contained within or overlapping with each vector area. I need something like Zonal Statistics, but I am not trying do math--I just need to know what values each polygon contains. For example--polygon A contains values 1, 2, and 3 from the raster layer, whereas polygon B contains values 3 & 4. Something like that.

I am using QGIS v3.34.2 on Windows.

Edit I am continuing to look for a solution, and I may have found one if I can code it correctly, which is to use Field Calculator's 'Concatenate' or 'Concatenate_Unique' expressions. For reference, I found this thread that attempts to tackle a similar but distinct problem. For my situation, I want the new field to contain a comma delimited string of all the band1 raster values with which each vector feature contains/intersects. The raster contains thousands of unique values, so I'm hoping there is a way to write the expression in a way that it is not required to write out all the raster values out in the Field Calculator, since that would defeat the purpose of having QGIS do the operation automatically.

2
  • This may be of help: How can I calculate the raster counts within an overlapping polygon in QGIS?
    – Matt
    Commented Jan 22 at 20:51
  • Thanks Matt. The issue is that I don't need to know how many unique raster cell values are within or overlap with the polygon, I need to know WHICH values they are (i.e. I need all the values themselves). The Zonal Histogram tool appears to achieve the same result as the Zonal Statistics 'Variety' option, which also indicates the number of unique values--this is not what I am looking for but thanks anyway.
    – Linus
    Commented Jan 22 at 20:58

1 Answer 1

1

Zonal histogram to get a field for each unique raster value. Dont change the default naming. My first polygon have 6755 pixels with value "2" in it:

enter image description here

Create a new field and store the field names with values using pyqgis:

zonal_histogram_out = QgsProject().instance().mapLayersByName("Output zones")[0]

#histogram_fields_names = ["HISTO_2", "HISTO_3", ...] Either list them manually
#Or using Python:
histogram_field_names = [f.name() for f in zonal_histogram_out.fields() if "hist" in f.name().lower()] #List all fields with hist in the lowercase field name

#Add a new field to hold the result
new_fieldname = "Unique_values"
provider = zonal_histogram_out.dataProvider()
new_field  = QgsField(name=new_fieldname, type=QVariant.String)
provider.addAttributes([new_field])
zonal_histogram_out.updateFields()
fieldindex = zonal_histogram_out.fields().indexOf(new_fieldname) #Find the index of the new field

attributeMap = {} #A dictionary to store each feature id as key, and a dict of {new field index : string of field names with pixel counts}
for row in zonal_histogram_out.getFeatures(): #For each row/feature in histogram output layer
    histfields_with_pixelcount = [] #Create an empty list
    for histfield in histogram_field_names: #For each field in the field list
        if row[histfield]>0: #If there are pixel count above zero
            histfields_with_pixelcount.append(histfield) #Append the fieldname to the list
    if len(histfield)>0: #If there are any field names in the list
        attributeMap[row.id()] = {fieldindex:', '.join(histfields_with_pixelcount)} #Create a comma separated list of the listed field and store in the dictionary

#attributeMap is now:

#The feature with id 1, should have these field names in field with index 23:
#print(attributeMap[1])
#{23: 'HISTO_2, HISTO_3, HISTO_41, HISTO_42, HISTO_51, HISTO_52, HISTO_53, HISTO_61, HISTO_111, HISTO_112, HISTO_113, HISTO_114, HISTO_115, HISTO_116, HISTO_117, HISTO_118, HISTO_121, HISTO_122, HISTO_123, HISTO_124, HISTO_125, HISTO_128'}

provider.changeAttributeValues(attributeMap) #update the new field with values

enter image description here

2
  • thanks for your response! This looks like it achieves what I am trying to do. Question--why do you say not to change the default naming? Also, what if the zone I am analyzing has more values than what I specify in PYQGIS? I am not a coder so following your solution will not be intuitive for me if it requires that I change any of the code on my own. Thanks in advance.
    – Linus
    Commented Jan 23 at 20:50
  • 1
    If you change the default field names for histogram output this line that lists the fields histogram_field_names = [f.name() for f in zonal_histogram_out.fields() if "hist" in f.name().lower()] wont work. You dont need to specify the field names if you use this line.
    – Bera
    Commented Jan 24 at 6:10

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.