1

I’m trying to create a PNG image containing pie charts as style for a layer using a standalone pyqgis script (QGIS v2.18.14).

The script works fine with other layers and style files, but the layer containing the pie charts stays blank.

I suspect this is caused by one or several of the following reasons:

  1. A bug might be preventing pyqgis to correctly apply the QML style file. The bug can be reproduced in QGIS as follows:
    • a. Open Layer Properties for a layer containing centroid_geo/point spatial type, and set style for layer to include diagrams (pie charts) and custom colors by attribute
    • b. Save the style as QML
    • c. In a new project containing the same layer with different styling, load the previous QML file a first time. The Layers Panel will automatically update the point’s style according to the QML file, but not the colors for the selected attributes (see screenshot).
    • d. Repeat the import of the QML file in the Layers Properties a second time, and the colors in the Layers Panel will now automatically update with the new colors from the QML file (see screenshot), but they will still not update in the Layers Properties window under Assigned attributes (right side of the screenshot).
    • e. When clicking Apply or OK in the Layers Properties window, the former style is finally adopted and overwrites the style file’s colors in the Layers Panel
    • Note: i figured out that a trick to apply the styling from the QML is to do steps a-d, then instead of clicking Apply or OK, click Cancel, then reopen the Layers Properties window, and then only are the updated colors visible in the window, and can be applied to the map by clicking Apply/OK.

annotated screenshot describing bug

  1. Maybe pie charts cannot be rendered using pyqgis simple rendering, which is the method I’m using (cf code below)
  2. Maybe I’m doing something wrong/missing something in the pyqgis script.

So far I also tried repeating three times the lyr_ecs.loadNamedStyle(...) command hoping the workaround for the bug in the QGIS GUI might work in a similar way from the script, but this didn't work.

canvas = QgsMapCanvas()

# Load project
QgsProject.instance().read(QFileInfo(root_path + project_path))
uri = QgsDataSourceURI()
    # set host name, port, database name, username and password
    uri.setConnection("{}".format(host), "{}".format(port), "{}".format(dbname), "{}".format(user), "{}".format(password))


##########################################################
        #Add new layer to image
##########################################################
        # SUBSECTORS       
        # Set database schema, table name, geometry column and optionally a subset (WHERE clause)
        uri.setDataSource(schema_name2, "geo_girec", "geom", "numero IN ('{}')".format(geo_girec_numero)) #('2800080','2800152','2800079')") 
        uri.setKeyColumn('numero')

        # Load layer to PyQgis environment
        print "loading SUBSECTORS layer"
        lyr_subsectors = QgsVectorLayer(uri.uri(False), "subsectors2", "postgres")

        # Check if layer was correctly loaded to PyQgis and if so, process its style
        if not lyr_subsectors.isValid():
            print "Layer 'subsectors2' failed to load! Probably not existent."
        else:
            print "Layer 'subsectors2' loaded!"        
            # Add layer to the registry                    
            QgsMapLayerRegistry.instance().addMapLayer(lyr_subsectors)
            print "QgsMapLayerRegistry correctly added map layer lyr_subsectors"

            # Load style file corresponding to the layer
            lyr_subsectors.loadNamedStyle(root_path + '/layerStyles/citygml/subsector_style_gray' + '.qml')



##########################################################
        #Add new layer to image
##########################################################
        #First check if the BUILDING_ECS_ENY_VIEW is to be used in the requested style
        if 'qml_name_ecs' not in globals():
            print "Pies are not requested by user, moving on"
        else:
            # BUILDING_ECS_ENY_VIEW        
            # Set database schema, table name, geometry column and optionally a subset (WHERE clause)
            uri.setDataSource(schema_name, "building_ecs_eny_view", "centroid_geo", "scenario_id = " + scenario_id + " AND cityobjectgroup_id = " + cityobjectgroup_id)

            # Define primary key of view (https://gis.stackexchange.com/questions/151686/selecting-column-like-primary-key-in-view-from-postgis-using-pyqgis)
            uri.setKeyColumn('citymodel_id,scenario_id,cityobjectgroup_id,blg_id')

            # Load layer to PyQgis environment        
            print "loading BUILDING_ECS_ENY_VIEW layer"
            lyr_ecs = QgsVectorLayer(uri.uri(False), "building_ecs", "postgres")

            # Check if layer was correctly loaded to PyQgis and if so, process its style        
            if not lyr_ecs.isValid():
                print "Layer 'building_ecs_eny_view' failed to load! Probably not existent."
            else:
                print "Layer 'building_ecs_eny_view' seemingly loaded!"
                # Add layer to the registry
                QgsMapLayerRegistry.instance().addMapLayer(lyr_ecs)
                print "QgsMapLayerRegistry correctly added map layer lyr_ecs"

                # Set canvas extent  
                canvas.setExtent(lyr_ecs.extent())

                # Load style file corresponding to the layer
                lyr_ecs.loadNamedStyle(root_path + '/layerStyles/citygml/{}'.format(qml_name_ecs) + '.qml') #e.g. "2.5d-height_energy-standard.gml"

                ##################################3
                #NOTE: i tried repeating the line above three times here to mimick the workaround from the bug described above in the QGIS interface, but this didn't work..
                ##################################

            # Set layer set
            lst = [lyr_ecs.id(),lyr_subsectors.id()]  # unlike documentation, use .id() instead of .getLayerId()      


##########################################################
        #Simple renderer approach (handles multiple layers)
##########################################################

        # Create image
        img = QImage(QSize(1600, 1200), QImage.Format_ARGB32_Premultiplied)

        # Set image's background color
        color = QColor(255, 255, 255)
        img.fill(color.rgb())

        # Create painter
        p = QPainter()
        p.begin(img)
        p.setRenderHint(QPainter.Antialiasing)            
        render = QgsMapRenderer()

        render.setLayerSet(lst)

        # Set extent
        rect = QgsRectangle(render.fullExtent())
        rect.scale(1.1)
        render.setExtent(rect)

        # Set output size
        render.setOutputSize(img.size(), img.logicalDpiX())

        # Do the rendering
        render.render(p)
        p.end()

        # Export PNG image
        img.save(result_path + '/' + "map_" + scenario_id + '_' +  map_style + '_simple.png', "png") #previously from sty object sty['pdf']

    QgsProject.instance().clear()

Your Answer

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

Browse other questions tagged or ask your own question.