1

I'm using a standalone pyqgis script on Ubuntu 16.04 and QGIS 2.18 to print custom maps as PNG files. The script is loosely based on this script.

My goal is simple: print multiple layers in a single PNG file, but I'm encountering some issues.

The script below adds up to three layers (layer_dev, layer_parks, layer_blgs) using QgsMapLayerRegistry.instance().addMapLayer(layer_name).

If I include just the two first layers (and comment out layer_blgs), the PNG correctly contains both layers. If I include all three layers, then only the third is displayed in the PNG, and the two first are not printed.

At first I thought there was possibly some white background or something in layer_blgs masking the 2 first layers, but this behavior is similar regardless of the order with which I add the layer_blgs.

I also replicated manually the exact configuration (layers and corresponding style files) in QGIS to see if I was missing something, but the displayed map was, as expected, a combination of all layers.

I didn't find anything in the documentation that explains this issue, but suspect it might have to do with either the QgsLayerTreeMapCanvasBridge(), or with the final composition rendering composition.renderPage(imagePainter, 0).

Is there an explicit way to force all three layers to be printed in the final PNG?

root_path = '/home/me/sw/qgis'
result_path = '../../media/maps/tmp'
schema_name = 'webservice'
project_name = str(sys.argv[1]) #e.g. '048'
iteration_nb = str(sys.argv[2]) #e.g. '001'
alternative_nb = str(sys.argv[3]) #e.g. '633'
sol_nb = '001'

# Set output DPI
dpi = 300


def make_pdf(xmin, ymin, xmax, ymax, filter_expression):
    canvas = QgsMapCanvas()
    # Set canvas extent
    canvas.setExtent(QgsRectangle(xmin, ymin, xmax, ymax))

    uri = QgsDataSourceURI()
        # set host name, port, database name, username and password
    uri.setConnection("host_name", "port", "myDB", "myUsername", "pwd")


    # DEV BORDERS
    # Set database schema, table name, geometry column and optionally subset (WHERE clause)
    uri.setDataSource("mySchema", "myTable", "geom")
    print "loading boundary development layer"
    lyr_dev = QgsVectorLayer(uri.uri(False), "boundary development", "postgres")
    if not lyr_dev.isValid():
        print "Layer 'boundary development' failed to load! Probably not existent."
    else:
        QgsMapLayerRegistry.instance().addMapLayer(lyr_dev)
        lyr_dev.loadNamedStyle(root_path + '/layerStyles/dev' + '.qml')
        lyr_dev.triggerRepaint()

    # PARKS
    # Set database schema, table name, geometry column and optionally subset (WHERE clause)
    uri.setDataSource(schema_name, "p" + project_name  + "_" + iteration_nb + "_" + alternative_nb + "_" + sol_nb + "_blg", "geom", "building_type = 'park'")
    print "p" + project_name  + "_" + iteration_nb + "_" + alternative_nb + "_001_blg"
    print "loading parks layer"
    lyr_parks = QgsVectorLayer(uri.uri(False), "parks", "postgres")
    if not lyr_parks.isValid():
        print "Layer 'parks' failed to load! Probably not existent."
    else:
        QgsMapLayerRegistry.instance().addMapLayer(lyr_parks)
        lyr_parks.loadNamedStyle(root_path + '/layerStyles/parks' + '.qml')
        lyr_parks.triggerRepaint()

    # BUILDINGS
    # Set database schema, table name, geometry column and optionally subset (WHERE clause)
    uri.setDataSource(schema_name, "p" + project_name  + "_" + iteration_nb + "_" + alternative_nb + "_" + sol_nb + "_blg", "geom", "building_type <> 'park'")
    print "p" + project_name  + "_" + iteration_nb + "_" + alternative_nb + "_001_blg"
    print "loading buildings layer"
    lyr_blgs = QgsVectorLayer(uri.uri(False), "buildings", "postgres")
    if not lyr_blgs.isValid():
        print "Layer 'buildibgns' failed to load!"
    else:
        QgsMapLayerRegistry.instance().addMapLayer(lyr_blgs)
        lyr_blgs.loadNamedStyle(root_path + '/layerStyles/2.5d-height_label-floorstotal' + '.qml')        
        lyr_blgs.triggerRepaint()


#bridge used in standalone script: http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/loadproject.html; has to be created before further layers are loaded
    bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(), canvas)
    bridge.setCanvasLayers()



    # Load print composer template
#     template_path = root_path + sty['qpt'] + '.qpt'
    template_path = root_path + "/printComposers/autoexport" + '.qpt'
    template_file = file(template_path)
    template_content = template_file.read()
    template_file.close()

    document = QDomDocument()
    document.setContent(template_content)
    composition = QgsComposition(canvas.mapSettings())
    composition.loadFromTemplate(document, {})
    composition.refreshItems()

    # export to png
    dpmm = dpi / 25.4
    width = int(dpmm * composition.paperWidth())
    height = int(dpmm * composition.paperHeight())

    # create output image and initialize it
    image = QImage(QSize(width, height), QImage.Format_ARGB32)
    image.setDotsPerMeterX(dpmm * 1000)
    image.setDotsPerMeterY(dpmm * 1000)
    image.fill(0)

    # render the composition
    imagePainter = QPainter(image)
    composition.renderPage(imagePainter, 0)
    imagePainter.end()


    image.save(result_path + '/' + 'STH' + "_" + project_name + "_" + alternative_nb + "_" + sol_nb + '.png', "png")

    QgsProject.instance().clear()

make_pdf(2495987, 1113541, 2497513, 1114926, '') # this requires: (xmin, ymin, xmax, ymax, filter_expression), set filter_expression = '' if not needed
QgsApplication.exitQgis()

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.