Search code examples
naminggoogle-earth-enginevector-tiles

Export data from individual tiles to CSV and create unique names in gee


In earth engine, I divided my Image in several tiles and want to sample 500 pixels from each tile, then export the samples in separate .csv file to my drive. I don't find a solution to name the files for export in a unique way. In the code below, I created a basename ("Tile_") and unique tile indices ("indices"). However, I don't find a way to bring "Tile_" and the individual index together in the mapping process.

// sample random pixels from each tile

// Step 1: Convert the grid to a FeatureCollection
var gridFc = ee.FeatureCollection(ee.List(grid));

// Step 2: Dynamically define band names
var bandNames = ee.List.sequence(0, 20).map(function(i) {
  i = ee.Number(i).format('%d'); // Format the number as an integer (no decimal)
  return ee.List(['temperature_2m', 'precipitation', 'snowCover']).map(function(varName) {
    return ee.String(i).cat('_').cat(varName);
  });
}).flatten();

print('Dynamic Band Names:', bandNames);

// Step 4: Function to process and export each tile
// Function to process each tile and sample 500 random pixels
var processTile = function(tileFeature, index) {
  var tileGeometry = tileFeature.geometry(); // Correctly retrieve the geometry from the tile

  // Sample 500 random pixels from the tile
  var tileSamples = standImage.sample({
    region: tileGeometry,
    scale: pixelSize, // Match the pixel size of the image
    projection: crs,
    numPixels: 500, // Limit to 500 random pixels per tile
    geometries: true // Include pixel geometry for indexing
  });

  // Ensure the samples are valid before proceeding
 // tileSamples = ee.FeatureCollection(tileSamples).filter(ee.Filter.notNull(['latitude', 'longitude']));

  // Generate a description using the index for naming the export task
  var description = ee.String('Tile_Samples_').cat(ee.Number(index).format('%d')); // Correct tile name
  print(description, 'description');
  
  var bandNames = bandNames;
  print(bandnames, 'var bandnames');
  // Create the export task
  Export.table.toDrive({
    collection: tileSamples, // Collection of sampled pixels
    description: description, // Use description to set the name
    fileFormat: 'CSV', // Export as CSV
    selectors: bandNames // Use valid band names for the export
  });

  return tileFeature; // Return the tileFeature for continued processing
};

// Get the number of tiles in the grid
var numTiles = grid.size();

// Create a list of tile indices
var indices = ee.List.sequence(0, numTiles.subtract(1));

// Map the processTile function to each tile
indices.evaluate(function(indicesList) {
  indicesList.forEach(function(index) {
    var tileFeature = grid.filter(ee.Filter.eq('system:index', ee.Number(index).format('%d'))).first();
    
    // Only process if tileFeature is valid (it should have geometry)
    if (tileFeature) {
      processTile(tileFeature, index);  // Process and export each tile
    }
  });
});

This results in useless file names: "ee.String({ "type": "Invocation", "arguments": { "string1": "Tile_Samples_", "string2": { "type": "Invocation", "arguments": { "number": 0, "pattern": "%d" }, "functionName": "Number.format" } }, "functionName": "String.cat"})". Although the print log looks the way it should: "Tile_Samples_1" etc.


Solution

  • When using the foreach javascrit method you are actually running a client side process where all the API invocation are just the json description you see as file name. the quick and dirty solution is to use getInfo() in the eport method.

    Note that it's a bad way of creating a GEE query, you should rethink a bit the logic to make it work with a .map instead and run everything in one single query to GEE servers.