5 votos

Diferencia entre ejecutar un script en consola y desde el editor

Otra pregunta más sobre PyQgis... lo siento, pero soy un absoluto principiante con esto. Tengo un script que funciona bien cuando lo ejecuto a través de la consola de QGIS (ya sea paso a paso o usando "Run Selected" en el editor). Sin embargo, cuando simplemente hago clic en "Ejecutar" en el editor, obtengo resultados diferentes. Lo que hago es

  1. Cargar una capa de trama
  2. Seleccione la característica en la capa vectorial existente y haga zoom sobre ella
  3. Aplicar el estiramiento del histograma local
  4. Crear un mapa y exportarlo

Con la solución paso a paso, asumo que el script está "esperando" a que termine cada acción, lo cual puedo ver ya que el contenido del mapa cambia constantemente. Esto no ocurre cuando ejecuto el script desde el editor. ¿Por qué? ¿Hay alguna solución?

time.sleep() no hizo el truco, y no puedo conseguir mi cabeza alrededor Clase QTimer

Estoy usando QGIS 2.14. Este es mi código completo (la parte principal ocurre cerca del final, cuando disparo el tramo):

import os, time
from PyQt4.QtCore import *
from PyQt4.QtXml import *
from PyQt4.QtGui import *
from qgis import *

image_path = PATH_TO_IMAGE
export_path = EXPORT_PATH
template = PATH_TO_TEMPLATE

def exportMap(tempFile, canvas, bbox, outName):
    template_file = file(tempFile)
    template_content = template_file.read()
    template_file.close()
    document = QDomDocument()
    document.setContent(template_content)
    composer = QgsComposition(canvas.mapSettings())
    composer.loadFromTemplate(document)
    map_item = composer.getComposerItemById('main_map')
    map_item.setMapCanvas(canvas)
    bbox.scale(1.2)
    map_item.zoomToExtent(bbox)
    canvas.refresh()
    map_item.updateCachedImage()
    legend_item = composer.getComposerItemById('legend')
    legend_item.updateLegend()
    composer.refreshItems()
    composer.update()
    composer.exportAsPDF(outName)

# get map canvas
canvas = iface.mapCanvas()
li = iface.legendInterface()

# list all layers
layers = li.layers()
# get specific layer by displayed name
lakes = [l for l in layers if l.name() == 'lakes'][0]
iface.legendInterface().setLayerVisible(lakes, True)
# load raster
image = image_path
raster = QgsRasterLayer(image, QFileInfo(image).baseName())
iface.addRasterLayer(image)
canvas.refresh()
# make sure vector layer is on top
root = QgsProject.instance().layerTreeRoot()
for ch in root.children():
    if ch.layerName() == lakes.name():
        clone = ch.clone()
        root.insertChildNode(0, clone)
        root.removeChildNode(ch)

for feat in lakes.getFeatures():
    outname = abbrev[feat.attribute('name')] + '_' + QFileInfo(image).baseName() + '.pdf'
    outfile = os.path.join(export_path, outname)
    # select single feature based on attribute "name"
    expr = QgsExpression(""" \"name\" = '{0}' """.format(feat.attribute('name')))
    selection = [l.id() for l in lakes.getFeatures(QgsFeatureRequest(expr))]
    lakes.setSelectedFeatures(selection)
    # zoom to selected feature
    canvas.zoomToSelected(lakes)
    # bounding box of selected feature
    bbox = lakes.boundingBoxOfSelected()
    # deselect
    lakes.setSelectedFeatures([])
    # apply local stretch to active raster layer
    iface.setActiveLayer(raster)
    iface.mainWindow().findChild(QAction, 'mActionLocalCumulativeCutStretch').trigger()
    exportMap(template, canvas, bbox, outfile)

# remove raster
for ch in root.children():
    if ch.layerName() == raster.name():
        root.removeChildNode(ch)

Con la ayuda de @LaughU y este puesto Finalmente conseguí que funcionara. Mi solución ahora se parece a esto:

  • Cargar todas las capas que quiero utilizar
  • ¡imprimir una línea inútil! lo cual es muy importante porque estoy cargando una capa rasterizada que necesita tiempo para renderizar
  • utilizar una función más o menos inútil que no hace nada, pero que está conectada al mapCanvas().mapCanvasRefreshed señal
    • llamar a mi función de exportación (que tomará algunos argumentos que necesito establecer) después

Así que mi código ahora se ve así:

canvas = iface.mapCanvas()
li = iface.legendInterface()
# list all layers
layers = li.layers()
myLayer = [l for l in layers if l.name() == 'myName'][0]
# dummy function
def dummyAction():
    pass
# load raster
image = 'PATH_TO_RASTER'
raster = QgsRasterLayer(image, QFileInfo(image).baseName())
iface.addRasterLayer(image)
### LOAD ALL ADDITIONAL LAYERS, THEN: ###
print 'This is a useless line, but forces the map renderer to wait!'
# apply local stretch to active raster layer
iface.setActiveLayer(raster)
iface.mainWindow().findChild(QAction, 'mActionLocalCumulativeCutStretch').trigger()
### SET UP COMPOSER, THEN: ###
canvas.refresh()
canvas.mapCanvasRefreshed.connect(dummyAction)
### DO THE ACTUAL EXPORT ###

¿Por qué es tan molesto?

0 votos

¿Dónde está el código completo de PyQGIS para su pregunta?

0 votos

@xunilk - añadido

0 votos

¿Usaste time.sleep() directamente antes de la línea exportMap(template, canvas, bbox, outfile) ? Y si es así, ¿le diste un tiempo de espera decente (por ejemplo, esperar 10 segundos: time.sleep(10) )?

2voto

bretddog Puntos 210

Estoy usando QGIS 2.18.13 y me encontré con el mismo problema. La solución para mí fue conectar mi función de creación de mapas cuando el mapa terminó de refrescarse.

Mi código condensado tiene este aspecto:

def load_layer(self, temp_layer):
    # loads my layers which I want to display
    QgsMapLayerRegistry.instance().addMapLayer(temp_layer) # for demo
    self.iface.mapCanvas().refreshAllLayers()
    self.iface.mapCanvas().mapCanvasRefreshed.connect(self.mapcreater)

def mapcreater(self, templet):
    self.iface.mapCanvas().mapCanvasRefreshed.disconnect(self.mapcreater) # importen else you could end up in a loop
    template_file = file(templet, 'rt')
    template_content = template_file.read()
    template_file.close()
    prepared_name = "my_name.pdf" 
    maprender = self.iface.mapCanvas().mapRenderer()
    composition = QgsComposition(maprender)
    docu = QDomDocument()
    docu.setContent(template_content)
    composition.loadFromTemplate(docu)
    composition.setUseAdvancedEffects(False)
    map_report = composition.getComposerMapById(0)
    map_report.zoomToExtent(maprender.extent())

    self.iface.mapCanvas().refreshAllLayers()
    composition.refreshItems()
    composition.exportAsPDF(os.path.join("C:\my_folder\", prepared_name)) 

El flujo de trabajo sería:

  • Desactiva todas las capas que no quieras mostrar
  • Cargue todas las capas que desee mostrar
  • Refresca las capas con iface.mapCanvas().refreshAllLayers()
  • Conecte el mapCanvasRefreshed señal a la función de creación de mapas
  • Dentro de su función de creación de mapas desconectar la señal de nuevo
  • Crear el mapa y tal vez hacer un poco de limpieza de las capas y la visibilidad

0 votos

Buen material, ajustaré mi script e informaré de los resultados

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X