4

I'm using gdal_calc.py to do some raster operations. The raster files stores precipitation values that are between 0 - 40 l/m² aprox. in some cases and the operations i'm trying to do:

  1. Values greater than 20 --> reclasify to 20.
  2. Values lower than 0 --> reclasify to 0.
  3. Average of the reclasified rasters.

Here are some information of the inputs raster:

  • RASTER "A":

Band 1 Block=256x16 Type=Float32, ColorInterp=undefined Description = 1072016p

Min=0 Max=0.399 NoData Value=-3.4028234663852886e+38

  • RASTER "B"

Band 1 Block=256x16 Type=Float32, ColorInterp=undefined Description = 972016p

Min=0 Max=2.599 NoData Value=-3.4028234663852886e+38

This is what I tried:

gdal_calc.py -A ./datos/10072016p -B ./datos/9072016p  --calc="20*(A>20)" --calc="0*(A<0)" --calc="20*(B>20)" --calc="0*(B<0)" --calc="A+B/2" --outfile=result.tiff

And the result i'm getting:

Band 1 Block=3922x1 Type=Float32, ColorInterp=Gray
Min=-4294967295 Max=4294967295 NoData Value=1.175494351e-38

So, as you can see is not the expected result? What i'm missing or what i'm doing wrong?

EDIT 17/08/2016

After some work trying to understand what's happening I've conclude that the operations that was failling was 0*(A<0), 20*(A>20), ... It works if I just calculate the average of all rasters:

(A + B + C + ...)/length

So the problem, really is that I can't reclassify the values lower than 0 and greater than 20.

Here is the approach i'm using that is working (NodeJS Script) :

const fs = require('fs'),
Exec = require('child_process').exec,
path = require('path'),
dataDir = './datos', // Directorio de donde coger los archivos raster
reg = /.*p$/, // Regex detecto p al final del archivo

// Devuelve una letra entre A-Z y A1-Z1 si se supera length > 26
getNums = length => length <= 26 ? 
    Array.from({length}, (el, i)=> String.fromCharCode(i + 65)) : 
    Array.from({length : 26}, (el, i)=> String.fromCharCode(i + 65)).concat(Array.from({length : length - 26}, (el, i)=> String.fromCharCode(i + 65) + 1)),

// Comprueba que sea el tipo de archivo que se quiere
_RasterFile = file => reg.exec(file),
// Coge el fichero raster y obtiene la fecha
_ParseDate = date => new Date(
    +date.substring(date.length - 5, date.length - 1), 
    +date.substring(date.length - 7, date.length - 5) - 1, 
    +date.substring(0, date.length - 7)
),
// Fecha de hoy
today = new Date(),
// Fecha hace 40 días
last40days = new Date();
last40days.setDate(last40days.getDate() - 40);

// Lista de archivos finales
let listFiles = [];
// nombre del archivo resultante
let resultRasterName = `${today.getDate()}${today.getMonth() + 1 < 10 ? '0' + (today.getMonth() + 1) : today.getMonth() + 1}${today.getFullYear()}rp.tiff`;
fs.readdir(dataDir, (err, files)=>{
  if(err) return console.error(err);
  // Ficheros filtrados con el Regex
  let rasterFiles = files.filter(_RasterFile);
  // Fecha de los ficheros anteriores
  let dateList = rasterFiles.map(_ParseDate);
  // Puesta en común de las dos listas
  listFiles = rasterFiles.map( (f, i) => ({
    name    : f,
    path    : dataDir + '/' + f,
    date    : dateList[i]
  }))
  // Cogiendo los ficheros de los últimos 40 días
  .filter( f => f.date.getTime() >= last40days.getTime() )
  // Ordenándolas por fecha
  .sort( (a, b) => b.date.getTime() - a.date.getTime() );

  // Array de letras en base a el número de archivos
  let ArrayLetras = getNums(listFiles.length);
  // Expresión de los cálculos a realizar ej : (A + B + C + ...)/length
  let calc = '(' + ArrayLetras.join(' + ') + ')/' + ArrayLetras.length;

  // Comando final que se ejecutará ej: gdal_calc.py -A ./datos/10072016p -B ... --calc="expresión" --outfile nombreArchivoFinal.tiff
  let exec = listFiles.reduce( (execString, file, idx) => execString + '-' + ArrayLetras[idx] + ' ' + file.path + ' ', 'gdal_calc.py ') + 
    '--calc="' + calc + '" --outfile ' + resultRasterName;

  console.log('executing...', exec);

  Exec(exec, (error, stdout, stderr)=>{
    console.log(stdout);
  });
})
2
  • 1
    More of an FYI but you should probably put brackets in "A+B/2" so it looks like --calc="(A+B)/2" :)
    – Joseph
    Aug 8, 2016 at 13:12
  • I'm not sure if you can chain calculations together like that, and expect it to well. For me, it is quite interesting that it actually runs, and doesn't just crash when you try that. Aug 8, 2016 at 13:19

1 Answer 1

2

If you use a simple --calc option gdal_calc.py should work fine:

gdal_calc.py -A ./datos/10072016p -B ./datos/9072016p --calc="(20*(A>20)+0*(A<0)+20*(B>20)+0*(B<0))/2" --outfile=result.tiff
3
  • Hi! I've tried but i'm getting the same output. I think your syntx is the right one, but the error should be coming from something different. Thank you for your answer! =) Aug 8, 2016 at 14:50
  • If the maxA = 0.399 and maxB = 2.599 both rasters values are always lower than 20. Furthermore, the range 0-20 is not covered in your conditions and so in the expression. Hope this helps. Aug 8, 2016 at 15:32
  • I put those rasters as examples, this is done with some other raster files whose values are in this range. Aug 8, 2016 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.