2

I need to color each polygon based on its area and length. I can loop through all polygons, find out their area .geometry().area() and if it is larger than 100 meters squared, than I want it to be green, otherwise red. Is it possible? I found solution for one attribute. (Setting color of feature depending on attributes with PyQGIS?)

Aerov
  • 333
  • 1
  • 2
  • 9

2 Answers2

4

There is a nice example from QGIS Python Cookbook:

from PyQt4.QtGui import QColor

# load the vector layer:
lyr = QgsVectorLayer("Users/joellawhead/qgis_data/hancock/landuse.shp","Land Use", "ogr")

# create our three land use categories using a Python dictionary with a field value as the key, color name, and label
landuse = {"0":("yellow", "Developed"),"1":("darkcyan", "Water"),"2":("green","Land")}

# build our categorized renderer items
categories = []
for terrain, (color, label) in landuse.items():
    sym = QgsSymbolV2.defaultSymbol(lyr.geometryType())
    sym.setColor(QColor(color))
    category = QgsRendererCategoryV2(terrain, sym, label)
    categories.append(category)

# name the field containing the land use value:
field = "DN"

# build the renderer:
renderer = QgsCategorizedSymbolRendererV2(field, categories)

# add the renderer to the layer:
lyr.setRendererV2(renderer)

# add the categorized layer to the map:
QgsMapLayerRegistry.instance().addMapLayer(lyr)

And there you have another example:

# define some rules: label, expression, color name, (min scale, max scale)
road_rules = (
    ('Major road', '"type" LIKE \'major\'', 'orange', None),
    ('Minor road', '"type" LIKE \'minor\'', 'black', (0.0, 2500.0,)),
    ('Residential road', '"type" LIKE \'residential\'', 'grey', (100.0, 1000.0,)),
)

# create a new rule-based renderer
symbol = QgsSymbolV2.defaultSymbol(layer.geometryType())
renderer = QgsRuleBasedRendererV2(symbol)

# get the "root" rule
root_rule = renderer.rootRule()

for label, expression, color_name, scale in road_rules:
    # create a clone (i.e. a copy) of the default rule
    rule = root_rule.children()[0].clone()
    # set the label, expression and color
    rule.setLabel(label)
    rule.setFilterExpression(expression)
    rule.symbol().setColor(QColor(color_name))
    # set the scale limits if they have been specified
    if scale is not None:
        rule.setScaleMinDenom(scale[0])
        rule.setScaleMaxDenom(scale[1])
    # append the rule to the list of rules
    root_rule.appendChild(rule)

# delete the default rule
root_rule.removeChildAt(0)

# apply the renderer to the layer
layer.setRendererV2(renderer)

And don't loop through polygons, just create a column "area" and calculate it.

dmh126
  • 6,732
  • 2
  • 21
  • 36
  • thanks, but your answer missed both my questions. I asked, if it is possible use feature.geometry().area() instead of value from attribute table and second if it is possible to use two parameters (.area() and .length()) – Aerov Sep 01 '15 at 07:09
  • I'm afraid it's not posible, because with geometry().area() you have to create two different renderers, and one layer can't have more than one at the same time. – dmh126 Sep 01 '15 at 08:13
  • So it is not possible create render based on two different values? Let's say, that in my attribute value I have values "v1" and "v2". Isn't there way to set render on expression e.g. "v1 > 10 and v2<25"? – Aerov Sep 01 '15 at 08:23
1

So I solved it. I post my solution, if somebody will have similar problem. I add new attribute to my layer, I called it "COLOR".

res = provider.addAttributes([QgsField(COLOR,QVariant.String)])

then I run this:

index = layer.fieldNameIndex('COLOR')
    layer.startEditing()
    for feature in layer.getFeatures():
        COLOR = 'BW'
        if feature.geometry().area() < 10000:
            if feature.geometry().length() < 50:
                COLOR = 'BR'
            else:
                COLOR = 'LW'
        elif feature.geometry().length() < 50:
            COLOR = 'AW'
        layer.changeAttributeValue(feature.id(),index,str(COLOR))
    layer.commitChanges()

So I set that value to one of (BW,BR,LW,AW). Of course I could put .area() there and color it by it's size. My dictionary looks like this:

 correct = {
            'BR':('green','Both right'),
            'AW':('yellow','Area wrong'),
            'LW':('orange','Length wrong'),
            'BW':('red','Both wrong')
            }

Hope this helps somebody!

Aerov
  • 333
  • 1
  • 2
  • 9
  • 1
    Your question is not clear ... and i don't see how this "answer" solve your problem ... your code is not matching your question ... + How do u colour polygons ? – Snaileater Sep 04 '15 at 07:21
  • I use what I wrote and then the answer above with land. – Aerov Sep 04 '15 at 14:07