2

I have a loop in Python to list out LAS files in a folder, and run two commands in Grass GIS on these files to write them out as rasters. The loop runs but at the end I get an arg must be string not list error. Please have a look at the code and suggest a work around.

import glob
import os

os.chdir(r'C:\Program Files\QGIS 3.0\bin')
grassbat = r'C:\Program Files\QGIS 3.0\bin\grass74.bat' #not needed as the os dir is changed
input_las = r'E:\Rohan\Heimdall\data\LAS'
output_directory = r'E:\Rohan\Heimdall\data\Raster\GRASS'
grass_location = r'E:\Rohan\Heimdall\grassdata\lidar\PERMANENT' # r'  reads a path as a raw string
print(grass_location)
path = "E:/Rohan/Heimdall/data/LAS/*.las"
files = glob.glob(path)
print(files)  # okay. But lists files with odd slash pattern e.g'E:/Rohan/Heimdall/data/LAS\\PNOA_2016_CAT_huso31_346-4562.las'

def las_to_GTIFF_lidardata(input_las, grass_location, output_directory):
    las_file_list = glob.glob(input_las + '\\*.las')  # lists all files in folder that (*.las)
    print(las_file_list)
    for files in las_file_list:
        tif_file_name = os.path.basename(files)[:-4] + '.tif'
        out_tif = os.path.join(output_directory, tif_file_name)
        las2raster_commands=[
            [r'grass74 -text -f E:\Rohan\Heimdall\grassdata\lidar\PERMANENT --exec r.in.lidar -e -n -o --overwrite --verbose input= files output=lidar_in resolution=2'], # removed + files here as only str is taken not list
            [r'grass74 -text -f E:\Rohan\Heimdall\grassdata\lidar\PERMANENT --exec r.out.gdal --overwrite --verbose -m input=lidar_in@PERMANENT output=out_tif + format=GTiff type=Float32 nodata=-9999'],#brackets needed?
        ]
    for command in las2raster_commands:
        print(command)
        command_final = ['grassbat', '-text', '-f', grass_location, '--exec'] + command
        print(command_final)
        os.system(command_final)
    return True

las_to_GTIFF_lidardata(input_las=input_las, grass_location=grass_location, output_directory=output_directory)

I also have tried using pyQGIS but without success:

  • At a guess it is the os.system(command_final) line since that function would expect a string not a list and command_final is a list. Changing to os.system(' '.join(command_final)) might work. If you post up your error message it will tell us the line where the script is failing - you can just copy paste it. – RoperMaps Apr 27 '18 at 9:10
  • @RoperMaps Thanks for the reply and suggestion. While I try it, here is the error I get: 'las_to_GTIFF_lidardata(input_las=input_las, grass_location=grass_location, output_directory=output_directory) File "E:/Rohan/Heimdall/pyIDE/lidar.py", line 31, in las_to_GTIFF_lidardata os.system(command_final) TypeError: system() argument 1 must be str, not list' – RK4gis Apr 27 '18 at 9:16
  • Since las2raster_commands is a list of lists, command will be also a list. Change las2raster_commands to contain two strings instead (remove all brackets but the first and last) – BERA Apr 27 '18 at 9:25
  • @Ropermaps, you first suggestion worked and ino longer get the Typeerror, however the code produces a path not found error for a variable,this i will have to look up. But ist super weird as thepath takes it to wehere my Grass.bat file is. As for you second sugestion on comand containing two strings gives an error. – RK4gis Apr 27 '18 at 11:07
  • The link to the help center: gis.stackexchange.com/help – Andre Silva Apr 27 '18 at 16:00
1

At a general level I think you're probably using lists to get around string formatting/interpolation, but you're not turning them back into strings.

You're also putting variable names in strings, when you do this python doesn't know they're variables so won't insert the value you want.

Wrong:

var = 'cat'
my_string = 'look: a var'

Right:

var = 'cat'
my_string = 'look: a {}'.format(var)

NB there are lots of ways to do 'string interpolation' in Python. This is just one.

Based on that, but not on having tried to run the code, I think your function should probably look something like this:

def las_to_GTIFF_lidardata(input_las, grass_location, output_directory):
    las_file_list = glob.glob(input_las + '\\*.las')  # lists all files in folder that (*.las)
    print(las_file_list)
    for files in las_file_list:
        tif_file_name = os.path.basename(files)[:-4] + '.tif'
        out_tif = os.path.join(output_directory, tif_file_name)
        las2raster_commands=[
            'grass74 -text -f E:\\Rohan\\Heimdall\\grassdata\\lidar\\PERMANENT --exec r.in.lidar -e -n -o --overwrite --verbose input={} output=lidar_in resolution=2'.format(files), 
            'grass74 -text -f E:\\Rohan\\Heimdall\\grassdata\\lidar\\PERMANENT --exec r.out.gdal --overwrite --verbose -m input=lidar_in@PERMANENT output={} + format=GTiff type=Float32 nodata=-9999'.format(out_tif)]
    for command in las2raster_commands:
        print(command)
        command_final = '{} -text -f, {} --exec '.format(grassbat, grass_location) + command
        print(command_final)
        os.system(command_final)
    return True

As an aside, the line for files in las_file_list: might be clearer as for file (singular file) since you are referring to one file at a time.

  • thank you so much fo rthis help. i have made the changes but the run gives me and error about the early steps on directory. Unable to find the "C:\Program" where my grass74.bat file is. Just ridiculous. Chnaged it multiple times and rechecked all files paths also. – RK4gis Apr 27 '18 at 11:49
  • No problem. You might need to open a separate question for that if it's about calling grass on windows. Have you tried copying an pasting an example command into your terminal? – RoperMaps Apr 27 '18 at 13:41
1

If you are simply looking to interpolate all of the LAS files contained in a folder using Python, then I can suggest the following four-line solution, taken from the the section titled 'I have many LAS files and want to interpolate all of them at once' in the WhiteboxTools tutorial on intepolating LiDAR:

When you have hundreds, or even thousands, of LAS files you might be inclined to write a Python script that calls the above function for each input file contained within a folder. But that isn't the best way to handle this common situation. Instead, if the input (i) and output parameters are left unspecified, each of WhiteboxTool's LiDAR gridding methods will interpolate all of the LAS files in the working directory, e.g.

from WBT.whitebox_tools import WhiteboxTools

wbt = WhiteboxTools()
wbt.work_dir = "/path/to/data/"
wbt.lidar_idw_interpolation(parameter="elevation", returns="last", resolution=1.0, weight=1.0, radius=2.5)

Using this approach to folder-based interpolation has some advantages other than a greatly simplified script. WhiteboxTools will be able to parallelize the operation better, greatly improving the overall time required to interpolate the batch of files. Also, the gridding operations will be carried out with a strip of buffered data surrounding each LiDAR tile, i.e. there will be reduced edge-effects. This will reduce the potential for artifacts in the final mosaiced DEM.

WhiteboxTools is an open-source geoprocessing library that has extensive LiDAR processing capabilities.

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.