1

I am trying to export an image collection to a 2D table where :

  • axis 0 are pixels over the collection
  • axis 1 are bands from the image collection

I would loose spatial information, as pixels would be unordered which is OK. It could look like this (pixel Id unecessary):

example of table

I found the function toArray() that seems to do exactly what I want, but I am unable to export it to a CSV file or any type of format

// Load a Landsat collection, select the bands of interest.
var imageCol = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
  .select(['B1', 'B2', 'B3'])
  .filterDate('2017-09-01', '2017-09-02');

// Make an Array Image, with a 1-D Array per pixel.
var im_array = imageCol.toArray();

I have tried to transform this into a featureCollection but it doesn't work :

var im_feats = im_array.reduceToVectors()

I would have then export it in CSV with Export.table (it would be quite a heavy file):

Export.table.toDrive({
  collection: im_feats ,
  description:'pix_bands',
  fileFormat: 'CSV'
});

Am I taking a wrong approach ? Is there a trick to get around this issue ?

2 Answers 2

1

This is a very strange thing to do, but I'm sure you've got your reasons.

var pixels = image.reduceRegion({
  reducer: ee.Reducer.toList(),
  geometry: geometry,
  scale: 100
}) // A Dictionary with pixel values by band name

var numberOfPixels = ee.List(pixels.values().get(0)).size() // Pixel count for first band
var bandNames = image.bandNames()
var features = ee.FeatureCollection(
  ee.List.sequence(0, numberOfPixels.subtract(1))
    .map(function (i) {
      return bandNames.iterate(function (bandName, feature) {
        bandName = ee.String(bandName)
        var pixelValue = ee.List(pixels.get(bandName)).get(i)
        return ee.Feature(feature)
          .set(bandName, pixelValue)
      }, ee.Feature(ee.Geometry.Point([0, 0])))
    })
) // Turn Dictionary into FeatureCollection

https://code.earthengine.google.com/79d849a54ffecfb4a710a1d8a71dddd7

1
  • Thanks, this has worked for me. I have an alternative way I am using combining exporting tif from gee and data processing outside of gee (I do it in python). I was hoping the technique native to gee would be faster than the mixed one, but it is roughly 10 times slower.
    – spalice
    Dec 14, 2019 at 11:00
0

One easier way I found on one of the tutorials exports all the pixels out directly in Python very rapidly (see https://developers.google.com/earth-engine/tutorials/community/intro-to-python-api-guiattard). The logic goes:

  • Define area of interest using a ee.Geometry() object
  • Perform "clipping" by doing collection.getRegion(geometry, scale=4000).getInfo(). Note that I inputted scale=4000 to reduce the resolution, which you can also just ignore if you need the original image pixels. This returns a python list like this:
,
 ['2003_09_14',
  -92.86783407227614,
  42.059121602476,
  1063497600000,
  5729,
  3067],
 ...]
  • Using the ee_array_to_df(), you can turn this long list into a data frame, which you could then save as a csv. This is more efficient in my opinion if you are planning to save multiple images (at different locations and times) at the same time.

Minimum working example attached

import pandas as pd 
import matplotlib.pyplot as plt
import ee 
# Trigger the authentication flow.
ee.Authenticate()

# Initialize the library.
ee.Initialize()

def ee_array_to_df(arr, list_of_bands):
    """Transforms client-side ee.Image.getRegion array to pandas.DataFrame.
    Modification of 
    https://developers.google.com/earth-engine/tutorials/community/intro-to-python-api-guiattard
    """
    df = pd.DataFrame(arr)

    # Rearrange the header.
    headers = df.iloc[0]
    df = pd.DataFrame(df.values[1:], columns=headers)

    # Remove rows without data inside.
    df = df[['longitude', 'latitude', 'time', *list_of_bands]].dropna()

    # Convert the data to numeric values.
    for band in list_of_bands:
        df[band] = pd.to_numeric(df[band], errors='coerce')

    # Convert the time field into a datetime.
    df['datetime'] = pd.to_datetime(df['time'], unit='ms')
    # Keep the columns of interest.
    df = df[['datetime', "longitude", "latitude", *list_of_bands]]

    return df
bands = ["NDVI", "EVI"]
date_start = "2003-04-01"
date_end = "2003-10-31"

collection = ee.ImageCollection("MODIS/006/MOD13Q1").filterDate(
        ee.Date(date_start), ee.Date(date_end)
    ).select(bands)

# this could also be user-defined
geometry = ee.Geometry.Polygon(
        [[[-92.9341420641855, 42.67007391984631],
          [-92.9341420641855, 41.94316737537707],
          [-92.0407572499231, 41.94316737537707],
          [-92.0407572499231, 42.67007391984631]]])

# now perform the clipping and dataframe conversion 
collection_area_of_interest = collection.getRegion(geometry, scale=4000).getInfo()
df_area_of_interest = ee_array_to_df(collection_area_of_interest, bands)

# to give you a preview
# df_area_of_interest.head()

# Plot the spatial map using the latitude and longitude (in practice, you need to pick specific date by doing df_area_of_interest[df_area_of_interest["datetime"]=="2003-06-10"]
plt.scatter(df_area_of_interest["longitude"], df_area_of_interest["latitude"], c=df_area_of_interest["NDVI"])
plt.colorbar()

enter image description here enter image description here

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.