IO Tasks¶
ecoscope.platform.tasks.io ¶
Attributes¶
SpatialFeaturesConfig
module-attribute
¶
SpatialFeaturesConfig = LocalFileSpatialFeatures | RemoteFileSpatialFeatures | EarthRangerSpatialFeatures
Classes¶
EarthRangerSpatialFeatures ¶
Bases: BaseModel
Attributes¶
data_source
instance-attribute
¶
data_source: Annotated[str, Field(title='Data Source', description='Select one of your configured EarthRanger data sources.')]
model_config
class-attribute
instance-attribute
¶
source
class-attribute
instance-attribute
¶
spatial_features_group_name
instance-attribute
¶
spatial_features_group_name: Annotated[str, Field(description='Name of the spatial features group in EarthRanger')]
LocalFileSpatialFeatures ¶
Bases: BaseModel
Attributes¶
file_path
instance-attribute
¶
file_path: Annotated[str, Field(description='Path to geoparquet (.parquet) or geopackage (.gpkg) file')]
layer
class-attribute
instance-attribute
¶
layer: Annotated[str | SkipJsonSchema[None], AdvancedField(default=None, description='Layer name (only applicable to geopackage files)')] = None
model_config
class-attribute
instance-attribute
¶
name_column
instance-attribute
¶
source
class-attribute
instance-attribute
¶
Methods:¶
validate_file_extension ¶
validate_file_extension() -> LocalFileSpatialFeatures
Source code in ecoscope/platform/tasks/io/_spatial_features.py
RemoteFileSpatialFeatures ¶
Bases: BaseModel
Attributes¶
layer
class-attribute
instance-attribute
¶
layer: Annotated[str | SkipJsonSchema[None], AdvancedField(default=None, description='Layer name (only applicable for geopackage files)')] = None
model_config
class-attribute
instance-attribute
¶
name_column
instance-attribute
¶
source
class-attribute
instance-attribute
¶
url
instance-attribute
¶
Methods:¶
validate_url_extension ¶
validate_url_extension() -> RemoteFileSpatialFeatures
Source code in ecoscope/platform/tasks/io/_spatial_features.py
Functions:¶
calculate_ndvi_range ¶
calculate_ndvi_range(client: EarthEngineClient, roi: AnyGeoDataFrame, time_range: Annotated[TimeRange, Field(description='Current time range for trend analysis')], image_size: Annotated[int, Field(description='Number of historical satellite images to fetch. Set to a large value to retrieve all available historical data. Only used when baseline_time_range is not provided.')] = 1000000000, baseline_time_range: Annotated[Optional[BaselineTimeRange], Field(description='Explicit historical baseline and current time range. When provided, overrides time_range and image_size.')] = None, ndvi_method: Annotated[NDVIMethod, Field(description="Method to obtain NDVI values. 'MODIS MYD13A1 16-Day Composite': Uses pre-calculated NDVI from 16-day composites. Provides quality-filtered 'best pixel' values at 500m resolution with ~0.025 accuracy. Better for phenology studies but may saturate in dense canopies. 'MODIS MCD43A4 Daily NBAR': Uses daily nadir BRDF-adjusted reflectance. Computes NDVI from NIR/Red bands with view-angle correction for consistent measurements. Higher temporal resolution but more susceptible to cloud gaps.")] = 'MODIS MYD13A1 16-Day Composite', grouping_unit: Annotated[GroupingUnit, Field(description="Temporal unit for grouping historical data when calculating statistics. 'month': Compare against same calendar month (1-12). 'week': Compare against same ISO week number (1-53). 'day_of_year': Compare against same day of year (1-366). 'modis_16_day': Compare against same MODIS 16-day composite period (0-22).")] = 'month') -> AnyDataFrame
Calculate NDVI values over an ROI using Earth Engine Image Collections.
Compares current NDVI values against historical statistics (min, max, mean) grouped by a configurable temporal unit to identify trends and anomalies.
Supports two modes
- Mode A (default): Uses time_range + image_size to fetch N historical images before the current period. Deprecated; will be removed in a future release.
- Mode B: Uses baseline_time_range with explicit historical_start, current_start, current_end for precise control over both periods.
Functions:
| Name | Description |
|---|---|
- MODIS MYD13A1 16-Day Composite |
Uses pre-calculated NDVI band |
- MODIS MCD43A4 Daily NBAR |
Computes NDVI from (NIR - Red) / (NIR + Red) |
Grouping
- month: Compare against same calendar month across historical years
- week: Compare against same ISO week number across historical years
- day_of_year: Compare against same day of year across historical years
- modis_16_day: Compare against same MODIS 16-day composite period (0-22) across historical years
Source code in ecoscope/platform/tasks/io/_earthengine.py
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | |
determine_season_windows ¶
determine_season_windows(client: EarthEngineClient, roi: AnyGeoDataFrame, time_range: Annotated[TimeRange, Field(description='Time range filter')]) -> AnyDataFrame
Determine wet/dry season windows from NDVI values over an ROI.
Computes standardized NDVI values using MODIS MCD43A4 daily NBAR data, then identifies seasonal transition points to classify time windows as "dry" or "wet" seasons.
Source code in ecoscope/platform/tasks/io/_earthengine.py
download_roi ¶
download_roi(url: Annotated[str, Field(description='The path to ROI gpkg file')], roi_column: Annotated[str | None, Field(description='The column name of the ROI name')] = 'name', roi_name: Annotated[str | None, Field(description='The ROI name')] = None, layer_name: Annotated[str | None, Field(description='The layer name')] = None) -> AnyGeoDataFrame
Download ROI from a URL.
Source code in ecoscope/platform/tasks/io/_downloader.py
get_analysis_field_from_event_details ¶
get_analysis_field_label_from_event_details ¶
get_analysis_field_unit_from_event_details ¶
get_category_field_from_event_details ¶
get_category_field_label_from_event_details ¶
get_choices_from_v2_event_type ¶
get_choices_from_v2_event_type(client: EarthRangerClient, event_type: SingleEventTypeAnnotation, choice_field: Annotated[str | SkipJsonSchema[None], Field(description='The choice field to lookup values from')]) -> dict[str, str]
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_event_type_display_names_from_events ¶
get_event_type_display_names_from_events(client: EarthRangerClient, events_gdf: EventGDF, append_category_names: AppendCategorySelectionAnnotation = 'duplicates') -> EventsWithDisplayNamesGDF
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_event_type_from_event_details ¶
get_events ¶
get_events(client: EarthRangerClient, time_range: TimeRangeAnnotation, event_types: EventTypesAnnotation, event_columns: EventColumnsAnnotation = None, include_null_geometry: IncludeNullGeometryAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, include_details: IncludeDetailsAnnotation = False, include_updates: IncludeUpdatesAnnotation = False, include_related_events: IncludeRelatedEventsAnnotation = False, include_display_values: IncludeDisplayValuesAnnotation = False, force_point_geometry: ForcePointGeometryAnnotation = True) -> EventGDF | EventsWithDisplayNamesGDF | EmptyDataFrame
Get events.
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_events_from_combined_params ¶
get_events_from_combined_params(combined_params: CombinedEventsAndDetailsParams) -> EventGDF | EventsWithDisplayNamesGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_events_from_smart ¶
get_events_from_smart(client: SmartClient, time_range: Annotated[TimeRange, Field(description='Time range filter')], ca_uuid: Annotated[str, Field(description='Conservation Area UUID', title='Conservation Area UUID')], language_uuid: Annotated[str, Field(description='Language UUID', title='Language UUID')]) -> EventGDF | EmptyDataFrame
Get events.
Source code in ecoscope/platform/tasks/io/_smart.py
get_fields_from_event_type_schema ¶
get_fields_from_event_type_schema(client: EarthRangerClient, event_type: SingleEventTypeAnnotation) -> dict[str, str]
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_events ¶
get_patrol_events(client: EarthRangerClient, time_range: TimeRangeAnnotation, patrol_types: PatrolTypesAnnotation, event_types: EventTypesAnnotation, status: PatrolStatusAnnotation = None, include_null_geometry: IncludeNullGeometryAnnotation = True, truncate_to_time_range: TruncateToTimeRangeAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, sub_page_size: SubPageSizeAnnotation = 100, include_display_values: IncludeDisplayValuesAnnotation = False, patrols_overlap_daterange: PatrolsOverlapDateRangeAnnotation = True) -> EventGDF | EventsWithDisplayNamesGDF | EmptyDataFrame
Get events from patrols.
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_events_from_combined_params ¶
get_patrol_events_from_combined_params(combined_params: CombinedPatrolAndEventsParams) -> EventGDF | EventsWithDisplayNamesGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_observations ¶
get_patrol_observations(client: EarthRangerClient, time_range: TimeRangeAnnotation, patrol_types: PatrolTypesAnnotation, status: PatrolStatusAnnotation = None, include_patrol_details: IncludePatrolDetailsAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, sub_page_size: SubPageSizeAnnotation = 100, patrols_overlap_daterange: PatrolsOverlapDateRangeAnnotation = True) -> PatrolObservationsGDF | EmptyDataFrame
Get observations for a patrol type from EarthRanger.
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_observations_from_combined_params ¶
get_patrol_observations_from_combined_params(combined_params: CombinedPatrolAndEventsParams) -> PatrolObservationsGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_observations_from_patrols_df ¶
get_patrol_observations_from_patrols_df(client: EarthRangerClient, patrols_df: PatrolsDF, include_patrol_details: IncludePatrolDetailsAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, sub_page_size: SubPageSizeAnnotation = 100) -> PatrolObservationsGDF | EmptyDataFrame
Get observations for a patrol type from EarthRanger.
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_observations_from_patrols_df_and_combined_params ¶
get_patrol_observations_from_patrols_df_and_combined_params(patrols_df: PatrolsDF, combined_params: CombinedPatrolAndEventsParams) -> PatrolObservationsGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrol_observations_from_smart ¶
get_patrol_observations_from_smart(client: SmartClient, time_range: Annotated[TimeRange, Field(description='Time range filter')], ca_uuid: Annotated[str, Field(description='Conservation Area UUID', title='Conservation Area UUID')], language_uuid: Annotated[str, Field(description='Language UUID', title='Language UUID')], patrol_mandate: Annotated[str | SkipJsonSchema[None], AdvancedField(default=None, description='Patrol Mandate', title='Patrol Mandate')] = None, patrol_transport: Annotated[str | SkipJsonSchema[None], AdvancedField(default=None, description='Patrol Transport', title='Patrol Transport')] = None) -> PatrolObservationsGDF | EmptyDataFrame
Get observations for a patrol type from Smart.
Source code in ecoscope/platform/tasks/io/_smart.py
get_patrols ¶
get_patrols(client: EarthRangerClient, time_range: TimeRangeAnnotation, patrol_types: PatrolTypesAnnotation, status: PatrolStatusAnnotation = None, raise_on_empty: RaiseOnEmptyAnnotation = True, sub_page_size: SubPageSizeAnnotation = 100, patrols_overlap_daterange: PatrolsOverlapDateRangeAnnotation = True) -> PatrolsDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_patrols_from_combined_params ¶
get_patrols_from_combined_params(combined_params: CombinedPatrolAndEventsParams) -> PatrolsDF | EmptyDataFrame
get_spatial_features_group ¶
get_spatial_features_group(client: EarthRangerClient, spatial_features_group_name: Annotated[str, Field(description='The name of the group to fetch')]) -> RegionsGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
get_subjectgroup_observations ¶
get_subjectgroup_observations(client: EarthRangerClient, subject_group_name: Annotated[str, Field(description='⚠️ The use of a group with mixed subtypes could lead to unexpected results')], time_range: Annotated[TimeRange, Field(description='Time range filter')], raise_on_empty: Annotated[bool, AdvancedField(default=True, description='Whether or not to abort the workflow if no data is returned from EarthRanger')] = True, include_details: Annotated[bool, AdvancedField(default=False, title='Include Observation Details', description='Whether or not to include observation details')] = False, include_subjectsource_details: Annotated[bool, AdvancedField(default=False, title='Include Subject Source Details', description='Whether or not to include subject source details')] = False, filter: Annotated[ExclusionFilter, AdvancedField(default=clean, description='Filter observations based on exclusion flags.')] = 'clean') -> SubjectGroupObservationsGDF | EmptyDataFrame
Get observations for a subject group from EarthRanger.
Source code in ecoscope/platform/tasks/io/_earthranger.py
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | |
load_spatial_features_group ¶
load_spatial_features_group(config: Annotated[SpatialFeaturesConfig, Field(title='Spatial Feature Data Source')]) -> RegionsGDF | EmptyDataFrame
Load spatial feature group from local file, remote URL, or EarthRanger.
Supports geoparquet and geopackage files. All geometries are converted to CRS 4326 and filtered to polygons only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Annotated[SpatialFeaturesConfig, Field(title='Spatial Feature Data Source')]
|
Configuration specifying the source type and parameters. |
required |
Returns:
| Type | Description |
|---|---|
RegionsGDF | EmptyDataFrame
|
RegionsGDF with columns: pk, name, short_name, feature_type, geometry, metadata. |
RegionsGDF | EmptyDataFrame
|
Returns EmptyDataFrame if no polygons found. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If file format is invalid or required columns are missing. |
Source code in ecoscope/platform/tasks/io/_spatial_features.py
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | |
persist_df ¶
persist_df(df: Annotated[AnyDataFrame, Field(description='Dataframe to persist')], root_path: Annotated[str, Field(description='Root path to persist text to')], filename: Annotated[str | None, Field(description=' Optional filename to persist text to within the `root_path`.\n If not provided, a filename will be generated based on a hash of the df content.\n ')] = None, filetype: Annotated[FileType, Field(description='The output format')] = 'csv') -> Annotated[str, Field(description='Path to persisted data')]
Persist dataframe to a file or cloud storage object.
Source code in ecoscope/platform/tasks/io/_persist.py
persist_json ¶
persist_json(data: Annotated[dict[str, Any] | BaseModel, Field(description='JSON-serializable dict or pydantic model to persist')], root_path: Annotated[str, Field(description='Root path to persist data to')], filename: Annotated[str | None, Field(description=" Optional filename (within `root_path`). If not provided, a filename will\n be generated from a hash of the serialized JSON content. The `.json`\n extension is appended automatically when one isn't already present.\n ", exclude=True)] = None, filename_suffix: Annotated[str | None, Field(description='If present, appended to the filename stem before the extension.', exclude=True)] = None) -> Annotated[str, Field(description='Path to persisted JSON')]
Serialize JSON-shaped data and persist to a file or cloud storage object.
Source code in ecoscope/platform/tasks/io/_persist.py
persist_text ¶
persist_text(text: Annotated[str, Field(description='Text to persist')], root_path: Annotated[str, Field(description='Root path to persist text to')], filename: Annotated[str | None, Field(description=' Optional filename to persist text to within the `root_path`.\n If not provided, a filename will be generated based on a hash of the text content.\n ', exclude=True)] = None, filename_suffix: Annotated[str | None, Field(description=' If present, will be appended to the filename as filename_suffix.html\n ', exclude=True)] = None) -> Annotated[str, Field(description='Path to persisted text')]
Persist text to a file or cloud storage object.
Source code in ecoscope/platform/tasks/io/_persist.py
set_er_connection ¶
set_event_details_params ¶
set_event_details_params(client: str, time_range: TimeRangeAnnotation, event_type: SingleEventTypeAnnotation, analysis_field: AnalysisFieldAnnotation, analysis_field_label: AnalysisFieldLabelAnnotation, analysis_field_unit: AnalysisFieldUnitAnnotation, event_columns: EventColumnsAnnotation = DefaultEventColumns, category_field: CategoryFieldAnnotation = '', category_field_label: CategoryFieldLabelAnnotation = '', include_null_geometry: IncludeNullGeometryAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, include_details: IncludeDetailsAnnotation = True, include_updates: IncludeUpdatesAnnotation = False, include_related_events: IncludeRelatedEventsAnnotation = False, include_display_values: IncludeDisplayValuesAnnotation = False) -> Annotated[CombinedEventsAndDetailsParams, Field(description='Passthrough selected events settings for use in downstream tasks')]
Source code in ecoscope/platform/tasks/io/_earthranger.py
set_gee_connection ¶
set_patrol_status ¶
set_patrol_types ¶
set_patrol_types(patrol_types: Annotated[list[str], Field(description='Specify the patrol type(s) to analyze (optional). Leave empty to analyze all patrol types.')]) -> Annotated[list[str], Field(description='Passthrough selected patrol types for use in downstream EarthRanger queries')]
Source code in ecoscope/platform/tasks/io/_earthranger.py
set_patrols_and_patrol_events_params ¶
set_patrols_and_patrol_events_params(client: str, time_range: TimeRangeAnnotation, patrol_types: PatrolTypesAnnotation, event_types: EventTypesAnnotation, status: PatrolStatusAnnotation = None, include_patrol_details: IncludePatrolDetailsAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True, include_null_geometry: IncludeNullGeometryAnnotation = True, truncate_to_time_range: TruncateToTimeRangeAnnotation = True, sub_page_size: SubPageSizeAnnotation = 100, patrols_overlap_daterange: PatrolsOverlapDateRangeAnnotation = True) -> Annotated[CombinedPatrolAndEventsParams, Field(description='Passthrough selected patrol and event types for use in downstream EarthRanger queries')]
Source code in ecoscope/platform/tasks/io/_earthranger.py
set_smart_connection ¶
unpack_events_from_patrols_df ¶
unpack_events_from_patrols_df(patrols_df: PatrolsDF, event_types: EventTypesAnnotation, time_range: TimeRangeAnnotation, include_null_geometry: IncludeNullGeometryAnnotation = True, truncate_to_time_range: TruncateToTimeRangeAnnotation = True, raise_on_empty: RaiseOnEmptyAnnotation = True) -> EventGDF | EmptyDataFrame
Source code in ecoscope/platform/tasks/io/_earthranger.py
unpack_events_from_patrols_df_and_combined_params ¶
unpack_events_from_patrols_df_and_combined_params(patrols_df: PatrolsDF, combined_params: CombinedPatrolAndEventsParams) -> EventGDF | EmptyDataFrame