featurecollection.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #!/usr/bin/env python
  2. """Representation of an Earth Engine FeatureCollection."""
  3. # Using lowercase function naming to match the JavaScript names.
  4. # pylint: disable=g-bad-name
  5. # pylint: disable=g-long-lambda
  6. from . import apifunction
  7. from . import collection
  8. from . import computedobject
  9. from . import data
  10. from . import deprecation
  11. from . import ee_exception
  12. from . import ee_list
  13. from . import ee_types
  14. from . import feature
  15. from . import geometry
  16. class FeatureCollection(collection.Collection):
  17. """A representation of a FeatureCollection."""
  18. _initialized = False
  19. # Tell pytype to not complain about dynamic attributes.
  20. _HAS_DYNAMIC_ATTRIBUTES = True
  21. def __init__(self, args, opt_column=None):
  22. """Constructs a collection features.
  23. Args:
  24. args: constructor argument. One of:
  25. 1) A string - assumed to be the name of a collection.
  26. 2) A geometry.
  27. 3) A feature.
  28. 4) An array of features.
  29. 5) A GeoJSON FeatureCollection.
  30. 6) A computed object - reinterpreted as a collection.
  31. opt_column: The name of the geometry column to use. Only useful with the
  32. string constructor.
  33. Raises:
  34. EEException: if passed something other than the above.
  35. """
  36. self.initialize()
  37. # Wrap geometries with features.
  38. if isinstance(args, geometry.Geometry):
  39. args = feature.Feature(args)
  40. # Wrap single features in an array.
  41. if isinstance(args, feature.Feature):
  42. args = [args]
  43. if ee_types.isString(args):
  44. # An ID.
  45. actual_args = {'tableId': args}
  46. if opt_column:
  47. actual_args['geometryColumn'] = opt_column
  48. super(FeatureCollection, self).__init__(
  49. apifunction.ApiFunction.lookup('Collection.loadTable'), actual_args)
  50. elif isinstance(args, (list, tuple)):
  51. # A list of features.
  52. super(FeatureCollection, self).__init__(
  53. apifunction.ApiFunction.lookup('Collection'), {
  54. 'features': [feature.Feature(i) for i in args]
  55. })
  56. elif isinstance(args, ee_list.List):
  57. # A computed list of features.
  58. super(FeatureCollection, self).__init__(
  59. apifunction.ApiFunction.lookup('Collection'), {
  60. 'features': args
  61. })
  62. elif isinstance(args, dict) and args.get('type') == 'FeatureCollection':
  63. # A GeoJSON FeatureCollection
  64. super(FeatureCollection, self).__init__(
  65. apifunction.ApiFunction.lookup('Collection'),
  66. {'features': [feature.Feature(i) for i in args.get('features', [])]})
  67. elif isinstance(args, computedobject.ComputedObject):
  68. # A custom object to reinterpret as a FeatureCollection.
  69. super(FeatureCollection, self).__init__(
  70. args.func, args.args, args.varName)
  71. else:
  72. raise ee_exception.EEException(
  73. 'Unrecognized argument type to convert to a FeatureCollection: %s' %
  74. args)
  75. @classmethod
  76. def initialize(cls):
  77. """Imports API functions to this class."""
  78. if not cls._initialized:
  79. super(FeatureCollection, cls).initialize()
  80. apifunction.ApiFunction.importApi(
  81. cls, 'FeatureCollection', 'FeatureCollection')
  82. cls._initialized = True
  83. @classmethod
  84. def reset(cls):
  85. """Removes imported API functions from this class."""
  86. apifunction.ApiFunction.clearApi(cls)
  87. cls._initialized = False
  88. def getMapId(self, vis_params=None):
  89. """Fetch and return a map id and token, suitable for use in a Map overlay.
  90. Args:
  91. vis_params: The visualization parameters. Currently only one parameter,
  92. 'color', containing a hex RGB color string is allowed.
  93. Returns:
  94. A map ID dictionary as described in ee.data.getMapId, including an
  95. additional 'image' field containing Collection.draw image wrapping a
  96. FeatureCollection containing this feature.
  97. """
  98. painted = apifunction.ApiFunction.apply_('Collection.draw', {
  99. 'collection': self,
  100. 'color': (vis_params or {}).get('color', '000000')
  101. })
  102. return painted.getMapId({})
  103. def getDownloadURL(self, filetype=None, selectors=None, filename=None):
  104. """Gets a download URL.
  105. When the URL is accessed, the FeatureCollection is downloaded in one of
  106. several formats.
  107. Args:
  108. filetype: The format of download, one of: "csv", "json", "geojson", "kml",
  109. "kmz" ("json" outputs GeoJSON). If unspecified, defaults to "csv".
  110. selectors: Feature property names used to select the attributes to be
  111. downloaded. If unspecified, all properties are included.
  112. filename: Name of the file to be downloaded; extension is appended by
  113. default. If unspecified, defaults to "table".
  114. Returns:
  115. A URL to download this FeatureCollection.
  116. """
  117. request = {}
  118. request['table'] = self
  119. if filetype is not None:
  120. request['format'] = filetype.upper()
  121. if filename is not None:
  122. request['filename'] = filename
  123. if selectors is not None:
  124. if isinstance(selectors, (list, tuple)):
  125. selectors = ','.join(selectors)
  126. request['selectors'] = selectors
  127. return data.makeTableDownloadUrl(data.getTableDownloadId(request))
  128. # Deprecated spelling to match the JS library.
  129. getDownloadUrl = deprecation.Deprecated('Use getDownloadURL().')(
  130. getDownloadURL)
  131. def select(self, propertySelectors, newProperties=None,
  132. retainGeometry=True, *args):
  133. """Select properties from each feature in a collection.
  134. Args:
  135. propertySelectors: An array of names or regexes specifying the properties
  136. to select.
  137. newProperties: An array of strings specifying the new names for the
  138. selected properties. If supplied, the length must match the number
  139. of properties selected.
  140. retainGeometry: A boolean. When false, the result will have no geometry.
  141. *args: Selector elements as varargs.
  142. Returns:
  143. The feature collection with selected properties.
  144. """
  145. if len(args) or ee_types.isString(propertySelectors):
  146. args = list(args)
  147. if not isinstance(retainGeometry, bool):
  148. args.insert(0, retainGeometry)
  149. if newProperties is not None:
  150. args.insert(0, newProperties)
  151. args.insert(0, propertySelectors)
  152. return self.map(lambda feat: feat.select(args, None, True))
  153. else:
  154. return self.map(
  155. lambda feat: feat.select(
  156. propertySelectors, newProperties, retainGeometry))
  157. @staticmethod
  158. def name():
  159. return 'FeatureCollection'
  160. @staticmethod
  161. def elementType():
  162. return feature.Feature