9

I have a FeatureCollection that I cannot export as a shapefile on Earth Engine — I get the following error: Error: Shapefiles cannot contain multiple geometry types; found 'LineString', 'Polygon'.

This is the export code:

Export.table.toDrive({
  collection: table,
  description:'vectorsToDriveExample',
  fileFormat: 'SHP'
});

And upon using table.geometry(), I get the following output:

GeometryCollection
type: GeometryCollection
geometries: List (10 elements)
0: LineString, 3 vertices
1: LineString, 3 vertices
2: LineString, 3 vertices
3: LineString, 2 vertices
4: Polygon, 11 vertices
5: Polygon, 1484 vertices
6: Polygon, 7113 vertices
7: Polygon, 4 vertices
8: Polygon, 4 vertices
9: Polygon, 10205 vertices

I suppose it would be necessary to convert the LineString to Polygon, but I haven't found a way to do that.

menes
  • 1,421
  • 2
  • 7
  • 24
Julia R.
  • 137
  • 1
  • 4

2 Answers2

7

I created in GEE, two LineString and one Polygon geometries and put them together in one Feature Collection. They look, printed in GEE, as follow.

enter image description here

When I tried to export this Geometry Collection in that way, I got your same error message. However, when I filtered each geometry by type, as in following script, I could export successfully each feature collection (lines and polygons).

var geometry1 = ee.Geometry.LineString(
        [[-116.557421875, 42.281127635051625],
         [-114.096484375, 44.39037997076336],
         [-110.580859375, 44.26463363444282]]);

var geometry2 = ee.Geometry.LineString( [[-104.955859375, 35.30364788916715], [-101.1765625, 34.8], [-98.803515625, 36.6549334211419]]);

var geometry3 = ee.Geometry.Polygon( [[[-107.065234375, 45.26305508470522], [-102.319140625, 44.01233232748235], [-98.100390625, 46.48681864416886], [-100.64921875, 47.565183593175995], [-103.46171875, 46.60771317183824], [-105.834765625, 47.978669380083986]]]);

var fc = ee.FeatureCollection([geometry1, geometry2, geometry3]);

var features = fc.toList(fc.size());

print(fc);

print(fc.geometry().geometries());

Map.addLayer(geometry1); Map.addLayer(geometry2); Map.addLayer(geometry3);

var polygons = features .map(function (f) { return ee.Feature(f).set('geometry_type', ee.Feature(f).geometry().type()); }) .filter(ee.Filter.equals('geometry_type', 'Polygon'));

polygons = ee.FeatureCollection(polygons);

var lines = features .map(function (f) { return ee.Feature(f).set('geometry_type', ee.Feature(f).geometry().type()); }) .filter(ee.Filter.equals('geometry_type', 'LineString'));

lines = ee.FeatureCollection(lines);

Export.table.toDrive({ collection: polygons, description:'polygons', fileFormat: 'SHP' });

Export.table.toDrive({ collection: lines, description:'lines', fileFormat: 'SHP' });

After exported (lines and polygons) to my Google Drive, I downloaded them and they look as follow in QGIS. It worked as expected.

enter image description here

xunilk
  • 29,891
  • 4
  • 41
  • 80
  • @jfoguet adds a useful refinement below ("geometry collections are a geometry type that needs to be handled the same way") ... but his approach relies on getting just the first item in a geometry collection list. Shouldn't we unpack the list & return all geometries in the collection? – antifrax Apr 27 '23 at 08:25
2

Frequently when importing shapefiles to assets, EE reads small editing errors as linestrings and polygons.

enter image description here

In this case, EE saves that polygon as a feature that has a GeometryCollection that in turn has two geometries: a linestring and a polygon.

enter image description here

If one applies the filtering method proposed by @xunilk, features with GeometryCollections that have polygons inside will be lost. In order not to loose those features, an additional step must be added: First add a geometry_type property and filter different geometries types:

    ///// FIRST.
var muestras = table.map(function (f) { 
      return ee.Feature(f).set('geometry_type', ee.Feature(f).geometry().type()); })

var geoCollection = muestras.filter(ee.Filter.equals('geometry_type', 'GeometryCollection')); var polygons = muestras.filter(ee.Filter.equals('geometry_type', 'Polygon'))

Then, get only the polygon geometry from the features with GeometryCollection and pass it to a new feature with the original properties:

var featPolygons = geoCollection.map(function(feat){
  feat = ee.Feature(feat);
  var polygon = ee.Geometry(feat.geometry().geometries().get(1));
  return ee.Feature(polygon, {'clase': feat.get('clase'), 'clasifi': feat.get('clasifi')})})

Finally,

merge both FeatureCollections:

/// THIRD.

var colFinal = polygons.merge(featPolygons)

jfoguet
  • 545
  • 3
  • 6