I am following the QGIS Cookbook and this post where it concerns reading attributes from layers. I would like to exploit this method and implement it into a standalone script.
Essentially, I want to read the first feature of a shapefile from a field called Rank
, take the value of this feature (all values in the Rank
field are the exact same) and include it into a QGIS algorithm.
I wonder if there's an alternative to using layer.getFeatures()
as, I believe, this is used with the canvas when QGIS is running. I have the following basic script but doesn't like fname.getFeatures()
:
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"
for fname in glob.glob(path_dir + "*.shp"):
for feature in fname.getFeatures():
fid = 1
iterator = fname.getFeatures(QgsFeatureRequest().setFilterFid(fid))
idx = fname.fieldNameIndex('Rank')
Rank_value = idx[1]
#Do some processing, finish with field calculator algorithm
general.runalg("qgis:fieldcalculator", fname, 'Rank', 1, 10, 0, False, Rank_value, path_res + fname)
Is this the correct method or would it be much easier to read the Rank_value
from a shapefile and write to another programatically?
EDIT:
Following @gcarrillo's answer, the script does not produce any results. I have modified the script to match the one suggested but not sure why no output files are produced.
To try and clarify exactly what I'm looking for:
- A value from the
Rank
field of a shapefile is read. - A grid is created.
- The same shapefile is clipped onto the grid (it would then have more polygons, thus more features).
- The
Rank
field for this newly clipped shapefile is updated with the value read at the start. Next shapefile...
path_dir = home + "\Desktop\Test\\" path_res = path_dir + "Results\\" for fname in glob.glob(path_dir + "*.shp"): vLayer = QgsVectorLayer(fname,"any name","ogr") idx = fname.fieldNameIndex('Rank') Rank_value = vLayer.uniqueValues(idx)[0] outputs_1=general.runalg("qgis:creategrid", 1000, 1000, 24108, 18351.157175, 258293.802316, 665638.226408, 1, 'EPSG:7405', None) outputs_2=general.runalg("qgis:clip", outputs_1['SAVENAME'], fname, None) outputs_3=general.runalg("qgis:fieldcalculator", outputs_2, 'Rank', 1, 10, 0, False, Rank_value, path_res + fname)
2 Answers 2
I've tested the following script on GNU/Linux, QGIS v.2.8.1, Processing v.2.6 and Processing v.2.9.1.
import sys,os,glob
from qgis.core import *
from PyQt4.QtGui import *
app = QApplication([])
QgsApplication.setPrefixPath("/usr", True) # Adjust it to your path
QgsApplication.initQgis()
path_dir = "/docs/borrar/test/"
path_res = path_dir + "results/"
sys.path.append("/usr/share/qgis/python/plugins/") # Where Processing is installed
from processing.core.Processing import Processing
Processing.initialize()
from processing.tools import *
for fname in glob.glob(path_dir + "*.shp"):
vLayer = QgsVectorLayer(fname,"any name","ogr")
idx = vLayer.fieldNameIndex('rank')
Rank_value = vLayer.uniqueValues(idx)[0] # uV returns a list, get the 1st element
#Do some processing, finish with field calculator algorithm
outputs_1=general.runalg("qgis:creategrid",1,"-956314.538361,3285493.72235,-53712.3143749,1885220.75154",250000,250000,None)
outputs_2=general.runalg("qgis:clip", outputs_1['OUTPUT'], fname, None)
general.runalg("qgis:advancedpythonfieldcalculator", outputs_2['OUTPUT'], 'rank', 1, 10, 3, False, "value=%f" % Rank_value, path_res + os.path.basename(fname))
QgsApplication.exitQgis()
As you can see, the syntax of the qgis:creategrid
algorithm differs from your version and from the version we ran at Import error for qgis.core when running OSGeo4w shell script. Additionally, I ended up using the qgis:advancedpythonfieldcalculator
algorithm, which provides a help.
Hope you can make it to work in your environment, pay attention to paths.
-
Modified your script to work with my environment and it works =). Thank you very much @gcarrillo! I have one minor question regarding the advanced python field calculator algorithm: if a
Rank
field already exists, can it be updated by adding it to the formula (eg."value=%f(<Rank>)" % Rank_value
? If this requires a bit more code then I will research it before asking another question. Thanks again!Joseph– Joseph2015年04月10日 11:04:57 +00:00Commented Apr 10, 2015 at 11:04 -
1That's great! Regarding the question, I wasn't able to update a field. I'd have a look at the documentation of the algorithm or first try inside QGIS and see how the syntax looks like before writing it in a script.Germán Carrillo– Germán Carrillo2015年04月10日 12:26:45 +00:00Commented Apr 10, 2015 at 12:26
-
1Many thanks! This isn't really a necessity but I will look into the documentation and will try it inside QGIS. Fun to test out =). Will award you the bounty in 2 hours :)Joseph– Joseph2015年04月10日 12:32:07 +00:00Commented Apr 10, 2015 at 12:32
For the first question:
You need to create a QgsVectorLayer
object from your Shapefile path. Only then you can access the getFeatures()
function. That is:
for fname in glob.glob(path_dir + "*.shp"):
for feature in QgsVectorLayer(fname,"any name","ogr").getFeatures():
My recommended way of doing it
You don't actually need to access getFeatures() nor to use a for. You can accomplish what you want with this code:
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"
for fname in glob.glob(path_dir + "*.shp"):
vLayer = QgsVectorLayer(fname,"any name","ogr")
idx = vLayer.fieldNameIndex('Rank')
Rank_value = vLayer.uniqueValues(idx)[0] # uV returns a list, get the 1st element
#Do some processing, finish with field calculator algorithm
general.runalg("qgis:fieldcalculator", fname, 'Rank', 1, 10, 0, False, Rank_value, path_res + os.path.basename(fname))
Since you'll be using QgsVectorLayer
, don't forget to set the prefix path before initializing QGIS, as you did at Getting random values from geometryType() in a standalone PyQGIS script.
-
Awesome, many thanks for this @gcarrillo! Not sure why but no output is being produced. All the prefix paths are set, testing this with a single shapefile but still no result. Strange, still testing this.Joseph– Joseph2015年04月09日 11:41:30 +00:00Commented Apr 9, 2015 at 11:41
-
The error was on my part (ofcourse!), your script works great! Thank you very much =)Joseph– Joseph2015年04月09日 12:26:10 +00:00Commented Apr 9, 2015 at 12:26
-
Urgh, my sincerest apologies. Initially, I thought the script worked but later noticed the times when the files were modified which didn't change when running the script. There are still no shapefiles being produced.Joseph– Joseph2015年04月09日 14:44:39 +00:00Commented Apr 9, 2015 at 14:44