1

I have used the osgeo.gdal module to save numpy arrays as GeoTIFF files successfully in python for some time. Today I decided to write a simple module to handle the driver and file creation routines. Calling my module to save a numpy array gives the following error:

Traceback (most recent call last):
File "saveRaster.py", line 30, in <module>
    save_raster(destination,1,array,srs,gt)
File "saveRaster.py", line 10, in save_raster
    dataset_out = driver.Create(path, cols, rows, bands, dtype)
File "/Library/Frameworks/GDAL.framework/Versions/2.1/Python/2.7/site-packages/osgeo/gdal.py", line 1440, in Create
    return _gdal.Driver_Create(self, *args, **kwargs)
TypeError: in method 'Driver_Create', argument 5 of type 'int'

This is odd since argument 5 is the datatype argument, which should take a gdal data type such as gdal.GDT_Float32. However, if it try type(gdal.GDT_Float32) it returns <type 'int'>. Why then is gdal giving me a TypeError if an integer ought to be exactly what it is expecting?

Code below:

#! /usr/bin/env python

from osgeo import gdal,osr
import numpy as np

def save_raster(path, band_count, bands, srs, gt, format='GTiff', dtype=gdal.GDT_Float32):
    cols,rows = bands.shape
    # Initialize driver & create file
    driver = gdal.GetDriverByName(format)
    dataset_out = driver.Create(path, cols, rows, bands, dtype)
    dataset_out.SetGeoTransform(gt)
    dataset_out.SetProjection(srs)
    # Write the array to raster bands
    for b in range(band_count):
        out_band = dataset_out.GetRasterBand(b+1)
        out_band.WriteArray(bands[b])
    # Write file to disk
    dataset_out.FlushCache()

gt = [0,1,0,0,0,-1]

srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg)
srs = srs.ExportToWkt()

destination = '~/Desktop/arr.tif'

array = np.arange(0,25).reshape(5,5)

save_raster(destination,1,array,srs,gt)
  • You have several issues. One of them is by using '~/Desktop/arr.tif' as your destination path. It should be 'Desktop/arr.tif'. Other are produced for your particular "band" concepts. Please, see my answer. – xunilk Dec 10 '17 at 18:16
1

You have several issues. One of them is by using '~/Desktop/arr.tif' as your destination path. It should be 'Desktop/arr.tif'. Other are produced for your particular "band" concepts. In your code, bands is your numpy array to be written as raster. Avoiding this misunderstanding and by using right band concept, I fixed your code as follow (however, you should change your name variables):

#! /usr/bin/env python

from osgeo import gdal,osr
import numpy as np

def save_raster(path, band_count, bands, srs, gt, format='GTiff', dtype = gdal.GDT_Float32):
    cols,rows = bands.shape
    # Initialize driver & create file
    driver = gdal.GetDriverByName(format)
    dataset_out = driver.Create(path, cols, rows, 1, dtype)
    dataset_out.SetGeoTransform(gt)
    dataset_out.SetProjection(srs)
    # Write file to disk
    dataset_out.GetRasterBand(1).WriteArray(bands)
    dataset_out = None

epsg = 4326

gt = [0,1,0,0,0,-1]

srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg)
srs = srs.ExportToWkt()

destination = 'Desktop/arr.tif'

array = np.arange(0, 25).reshape(5,5)

save_raster(destination,1,array,srs,gt)

After running above code at Python Console, I got following raster (as expected):

enter image description here

  • Thanks for your input -- I knew it would turn out to be something simple! I was hesitant to post because of that but it was starting to drive me kind of crazy. Good advice to use better variable names, as that's really what was tripping me up. I had to make a couple further modifications, since I want to preserve the functionality of writing a multiband raster. To this end, I just removed the band_count argument altogether and added an if clause to ensure that the array being passed was 3-dimensional. Then I can get bands, rows and cols all at once: band_count,rows,cols = bands.shape – corvus Dec 10 '17 at 21:48
  • You're welcome. By the way, my answer was for a single band raster because you only had one array in your code but, for stacking a raster, you need one array for each band. You can do that in a loop; as it was initially proposed in your code. – xunilk Dec 10 '17 at 21:49
  • Of course, it is more intuitive to replace bands with array and replace band_count with bands, then the variable names are much less confusing. – corvus Dec 10 '17 at 21:49
  • Yes, that's it. – xunilk Dec 10 '17 at 21:53

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.