biglimp / PhDCourseVT2021

This repo include teaching materials for the PhD-course "Automate your GIS - Scripting in Python" (NGEO306)
7 stars 1 forks source link

Accessing unique attributes from vector layer and showing unique values in a scroll bar QGIS-Plugin #3

Open gusbacos opened 3 years ago

gusbacos commented 3 years ago

Hello (unsure which language to use, but someone else may be interested I dont know)

I am struggling with how to make get unique attribues from a selected field from a vector layer into a scroll list

So in the box called Class: in the picture below i would like to be able to select fields from the selected attributes

# Reharvested code from UAVPrepare

        self.layerComboManagerPoint = QgsMapLayerComboBox(self.dlg.comboBoxVector)
        self.layerComboManagerPoint.setCurrentIndex(-1)
        self.layerComboManagerPoint.setFilters(QgsMapLayerProxyModel.PolygonLayer)
        self.layerComboManagerPoint.setFixedWidth(175)

        self.layerComboManagerPointField = QgsFieldComboBox(self.dlg.comboBoxField)
        self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.AllTypes) # All types?
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerPointField.setLayer)

        # Somewhere here I am looking for like
        self.layerComboManagerPointFieldAttribute = QgsFieldComboBox(self.dlg.comboBoxAttribute)
        self.layerComboManagerPointFieldAttribute.setFilters(QgsFieldProxyModel.AllTypes)
        self.layerComboManagerPointFieldAttribute.layerChanged.connect(
                    self.layerComboManagerPointFieldAttribute.setATTRIBUTE(??)) # here i just wrote something 

I might be missing an important step, do you have any tips on google-words or code too search for?

image

nilswallenberg commented 3 years ago

Is it related to this:

https://gis.stackexchange.com/questions/396711/list-the-row-of-dataframe-attributes-in-combobox

biglimp commented 3 years ago

Did Nils suggestion solve your problem?

biglimp commented 3 years ago

Oskar, it also looks like you try to populate this in the init function in your plugin. I think you need to do this in a separate function after the user have chosen vector layer and attribute field. You can do something like when Attribute Field is changed, activate fuction that list attribute values in yout Class comboboxes.

gusbacos commented 3 years ago

Got good help from posting a Question at Stackoverflow (https://gis.stackexchange.com/questions/397335/populating-combobox-with-unique-features-in-selected-attribute-field-using-pyqgi/397391#397391) and has now found a way using this line of code

`` self.layerComboManagerPoint = QgsMapLayerComboBox(self.dlg.comboBoxVector) self.layerComboManagerPoint.setCurrentIndex(-1) self.layerComboManagerPoint.setFilters(QgsMapLayerProxyModel.PolygonLayer) self.layerComboManagerPoint.setFixedWidth(175)

    self.layerComboManagerPointField = QgsFieldComboBox(self.dlg.comboBoxField)
    self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.AllTypes)
    self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerPointField.setLayer)

    def field_changed(field):
        # get current layer
        layer = self.layerComboManagerPoint.currentLayer()
        # get index of the field
        i = layer.fields().indexOf(field)
        # get unique values
        unique_values = layer.uniqueValues(i)    
        # remove all values from comboBoxAttribute
        self.dlg.comboBoxClass1.clear()
        self.dlg.comboBoxClass2.clear()
        self.dlg.comboBoxClass3.clear()
        self.dlg.comboBoxClass4.clear()
        self.dlg.comboBoxClass5.clear()
        self.dlg.comboBoxClass6.clear()
        self.dlg.comboBoxClass7.clear()
        self.dlg.comboBoxClass8.clear()
        self.dlg.comboBoxClass9.clear()
        self.dlg.comboBoxClass10.clear()
        self.dlg.comboBoxClass11.clear()
        self.dlg.comboBoxClass12.clear()

        # Set set to string. ComboBox does not accept other than string ATM
        # Have not yet found a way to fix this. 
        # this loop will do the trick as workaround

        if isinstance(unique_values, str):
            att_list = unique_values
        else:
            att_list = []
            for i in unique_values:
                att_list.append(str(i))

        # # add unique values
        self.dlg.comboBoxClass1.addItems(att_list)
        self.dlg.comboBoxClass2.addItems(att_list)
        self.dlg.comboBoxClass3.addItems(att_list)
        self.dlg.comboBoxClass4.addItems(att_list)
        self.dlg.comboBoxClass5.addItems(att_list)
        self.dlg.comboBoxClass6.addItems(att_list)
        self.dlg.comboBoxClass7.addItems(att_list)
        self.dlg.comboBoxClass8.addItems(att_list)
        self.dlg.comboBoxClass9.addItems(att_list)
        self.dlg.comboBoxClass10.addItems(att_list)
        self.dlg.comboBoxClass11.addItems(att_list)
        self.dlg.comboBoxClass12.addItems(att_list)

    self.layerComboManagerPointField.fieldChanged.connect(field_changed)    

So now I am going to start reclassify into desired new classes. In geopandas I would have gone with the approach of creating a dictionary based on the choices the user takes, and then use .map() to update in a new column. like this

rclass_dict = {
    'BEBHÖG': 'type1',
    'BEBIND': 'type2',
    'BEBLÅG': 'type3',
    'BEBSLUT': 'type4',
    'ÖPTORG': 'type5'}

vectorlayer['new_class'] = vectorlayer['DETALJTYP'].map(rclass_dict)

image

Are there any similar feature in QGIS, or do i need to loop through to find and replace in a new Column?

biglimp commented 3 years ago

Nice solution! Your other issue, why not use geopandas (if it is available from QGIS). Otherwise a loop can be used.

gusbacos commented 3 years ago

Yes, that is reasonable!

I´ll try that.

gusbacos commented 3 years ago

https://gis.stackexchange.com/questions/397550/reclassifying-vectorlayer-attribute-column-using-dictionary-in-pyqgis#397550

Here is a reasonable solution provided by a kind soul at Stackexchange, might be good to have as backup