3

When I run the following script via OSGEO4W64 Shell, I receive the following error when trying to run the qgis:fieldcalculator algorithm:

'NoneType' object has no attribute 'mapCanvas'

I read that the error message relates to the script trying to access an interface although I'm not sure. The algorithm does what it's supposed to with the output layer containing a new ID column, but the layer has no features saved.

Basically, I would like to add a new ID field using the formula $rownum and remove the longitude and latitude fields which are generated by the Create grid algorithm. I would also be happy if this can be achieved without having to use the Field calculator algorithm (ie. by directly accessing the data).

import os, sys, glob

from qgis.core import *
from PyQt4.QtGui import *
app = QApplication([])
QgsApplication.setPrefixPath("C:\\OSGeo4W64\\apps\\qgis", True)
QgsApplication.initQgis()

from os.path import expanduser
home = expanduser("~")

#   Folder path of the Results for shapefiles
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"

# Prepare processing framework 
sys.path.append( home + '\.qgis2\python\plugins' )
from processing.core.Processing import Processing
Processing.initialize()
from processing.tools import *

def run():

    outputs_1=general.runalg("qgis:creategrid", 1000, 1000, 24108, 18351.157175, 258293.802316, 665638.226408, 1, 'EPSG:7405', None)
    outputs_2=general.runalg("qgis:fieldcalculator", outputs_1['SAVENAME'], 'ID', 1, 10, 0, True, '$rownum', None)
    outputs_3=processing.runalg("qgis:deletecolumn", outputs_2['OUTPUT_LAYER'], 'longitude', None)
    outputs_4=processing.runalg("qgis:deletecolumn", outputs_3['SAVENAME'], 'latitude', path_res  + "/" + "grid.shp")

#   Paths of the shapefiles in the Result folder with list comprehension
    output = [shp for shp in glob.glob(path_res + "*.shp")]

run()
QgsApplication.exitQgis()
2

The algorithm you are running requires some references to common QGIS components, which are available to plugins via an iface (QgisInterface) object. In this case you need a custom iface object because i) there is no QGIS instance running, ii) you are running a plugin, and iii) the algorithm you are running requires access to QGIS components (e.g. map canvas).

You can emulate the iface object by yourself, but thankfully my custom iface is included in Processing, so we can use it.

However, because of some changes to QgisInterface in the official QGIS project, you would need to either i) edit the file .../plugins/processing/tests/qgis_interface.py to make it equivalent to this one, or ii) download the file and replace the existing one. I've just changed 5 lines.

This is the working script:

import os, sys, glob

from qgis.core import *
from qgis.gui import QgsMapCanvas
from PyQt4.QtGui import *
app = QApplication([])
QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()

from os.path import expanduser
home = expanduser("~")

#   Folder path of the Results for shapefiles
path_dir = home + "/Test/"
path_res = path_dir + "/Results"

# Prepare processing framework 
sys.path.append( home + '/.qgis2/python/plugins' )

# Get an iface object
canvas = QgsMapCanvas()
from processing.tests.qgis_interface import QgisInterface
iface = QgisInterface( canvas )

# Initialize the Processing plugin passing an iface object
from processing.ProcessingPlugin import ProcessingPlugin
plugin = ProcessingPlugin(iface)
from processing.tools import *

def run():

    outputs_1=general.runalg("qgis:creategrid", 1000, 1000, 24108, 18351.157175, 258293.802316, 665638.226408, 1, 'EPSG:7405', None)
    outputs_2=general.runalg("qgis:fieldcalculator", outputs_1['SAVENAME'], 'ID', 1, 10, 0, True, '$rownum', path_res  + "/" + "grid.shp")
    outputs_3=general.runalg("qgis:deletecolumn", outputs_2['OUTPUT_LAYER'], 'longitude', None)
    outputs_4=general.runalg("qgis:deletecolumn", outputs_3['SAVENAME'], 'latitude', path_res  + "/" + "grid.shp")

#   Paths of the shapefiles in the Result folder with list comprehension
    output = [shp for shp in glob.glob(path_res + "*.shp")]

run()
QgsApplication.exitQgis()
app.exit()

I tested it on GNU/Linux succesfully.

  • Many thanks @gcarrillo. When I run this, I receive several messages (nothing about errors) but it crashes my python.exe. I will keep trying but I edited my question to include that I don't mind if the Field Calculator algorithm is not used as I only want to add a new field to the grid and remove 2 other fields. It would be equally great if there's another way to do this without having to use the Field Calculator. – Joseph Jan 16 '15 at 10:55
  • I've edited my answer with some important changes. Please test it on your environment. It shouldn't crash your python this time. – Germán Carrillo Jan 16 '15 at 13:23
  • 1
    Bingo! I had to change the QgsApplication.setPrefixPath to match my own as I'm guessing the one in your script is for Linux. I now have the output shapefile I require! One little thing is that an error shows up: QGraphicsScene::addItem: item has already been added to this scene. ERROR 4: `data/raster' does not exist in the file system, and is not recognised as a supported dataset name. Any ideas? Otherwise, many thanks for your help @gcarrillo :) – Joseph Jan 16 '15 at 15:05
  • 1
    Great! Always make sure paths are set properly. Regarding the 'data/raster' error, it occurs because the QgisInterface that is in processing (not the original I wrote) loads a raster from 'data/raster' for testing purposes. You have 2 options to avoid the error: i) Copy the file processing/tests/data/raster.tif to your_script_path + '/data/' + 'raster', or ii) Take the processing/tests/qgis_interface.py script, move it to your script folder, modify it removing the code that uses test data, since it's not necessary for your purposes, and adjust the import. I would choose ii). – Germán Carrillo Jan 16 '15 at 15:43
  • 1
    Excellent tips buddy! Yes, I have to remember to keep checking that the paths remain consistent. You're right, I also think option ii) would be much more convenient so will test that out. Thank you very much again! – Joseph Jan 16 '15 at 15:48

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.