1

Is there a way to change the style of only PART of a polygon's border in QGIS? I would like one or two edges of certain polygons to render a different color, or not at all, depending on the type of feature that is adjacent. (For example, a political division that adjoins a waterbody would show that one edge as blue.)

The obvious way seems to be changing the style of the adjoining feature, then using symbol levels to have it render on top of the first feature, but this doesn't work; there is always a little bit of the other border showing through underneath:

I can increase the line thickness of the adjoining feature so that it fully covers the feature underneath (in the example image it's already twice as thick), but then it also begins to cover the interior of that polygon. I can also convert to polylines and just clip off the shoreline, but then I lose the geometry. I think what I really need is a way to suppress rendering of the border on the one side, and just covering it with something else isn't working.

  • I don't believe that there is any easy way. I think that the way to go is to render polygons with just fill and create a planar graph for coloring the edges. If the edges in the planar graph have attributes for the left side face and right side face you should be able to make the coloring as you wish. I don't know graph tools of QGIS but OpenJUMP seems to create graph tables which have all the necessary information. Some extra work will be needed to join attributes from faces to edges, though. – user30184 Dec 12 '15 at 9:41
1

As user30184 points out you need the boundary geometry of polygons to render one polygons outline in a different way. To create such a planar graph you can downgrade polygons to polylines, and keep only one instance of these segments being shared by two polygons.

The following script might help. It mimics kind of topology building process. It takes into account, that neighboring polygon may not be digitized in the same direction. In the result each segment has attributes with the feature ids of the left and right polygon. These values can be used, to establish a join to the attribute table of the polygons. If you want to dissolve the segments to continous lines, use the dissolve tool from processing toolset. For this to create useful results you should consider to combine attributes lpoly and rpoly into a composite attribute, and use this for the dissolve process.

from PyQt4.QtCore import QVariant

layer = iface.activeLayer()

segments = {}
j = 0

for feat in layer.getFeatures():
    # polylines
    line = feat.geometry().asPolygon()[0]

    for i in xrange(len(line)-1):
        lsegment = ((line[i][0], line[i][1]), (line[i+1][0], line[i+1][1]))
        rsegment = ((line[i+1][0], line[i+1][1]), (line[i][0], line[i][1]))
        if lsegment in segments:
            if segments[lsegment]['lpoly'] == -9999:
                segments[lsegment]['lpoly'] = feat.id()
            elif segments[lsegment]['rpoly'] == -9999:
                segments[lsegment]['rpoly'] = feat.id()
        elif rsegment in segments:
            if segments[rsegment]['lpoly'] == -9999:
                segments[rsegment]['lpoly'] = feat.id()
            elif segments[rsegment]['rpoly'] == -9999:
                segments[rsegment]['rpoly'] = feat.id()
        else:
            segments[lsegment] = {'lpoly': feat.id(), 'rpoly': -9999, 'fid': j}
        j += 1

layer = QgsVectorLayer('LineString?crs=EPSG:4326', 'Result', 'memory')
prov = layer.dataProvider()
attributes = [QgsField('fid', QVariant.Int), QgsField('lpoly', QVariant.Int), QgsField('rpoly', QVariant.Int), QgsField('length', QVariant.Double)]
prov.addAttributes(attributes)
QgsMapLayerRegistry.instance().addMapLayer(layer)

# create features
feats = []
layer.startEditing()

for segment in segments:
    feat = QgsFeature()
    vertices = [QgsPoint(segment[0][0], segment[0][1]), QgsPoint(segment[1][0], segment[1][1])]
    attributes = [segments[segment]['fid'], segments[segment]['lpoly'], segments[segment]['rpoly']]
    feat.setGeometry(QgsGeometry.fromPolyline(vertices))
    attributes.append(feat.geometry().length())
    feat.setAttributes(attributes)
    feats.append(feat)

prov.addFeatures(feats)
layer.updateExtents()
layer.commitChanges()

Example: Polygons, labeled with id()

Polygons

Boundary of polygons, labeled with lpoly above rpoly

Linestrings

  • Hmm, OK. That may be rather beyond my experience level right now, but I'll file it away for when I've become more of a power user! – Nathan Dec 13 '15 at 6:07
  • @Nathan Ok. To execute it open python console, show editor window and copy / paste the code. See what happens when you run the script while your polygon layer is the active layer. The general direction to think in is topology building. Since these processes restructure geometry down to single components to create new features, you will have to attribute or join tables too. – Detlev Dec 13 '15 at 7:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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