EcoMap#
Setup#
Ecoscope#
[ ]:
ECOSCOPE_RAW = "https://raw.githubusercontent.com/wildlife-dynamics/ecoscope/master"
# !pip install ecoscope
[ ]:
import os
import sys
import geopandas as gpd
import numpy as np
import pandas as pd
import shapely
import ecoscope
ecoscope.init(selenium=True)
Google Drive Setup#
[ ]:
output_dir = "Ecoscope-Outputs"
if "google.colab" in sys.modules:
from google.colab import drive
drive.mount("/content/drive/", force_remount=True)
output_dir = os.path.join("/content/drive/MyDrive/", output_dir)
os.makedirs(output_dir, exist_ok=True)
Earth Engine#
[ ]:
import ee
try:
EE_ACCOUNT = os.getenv("EE_ACCOUNT")
EE_PRIVATE_KEY_DATA = os.getenv("EE_PRIVATE_KEY_DATA")
if EE_ACCOUNT and EE_PRIVATE_KEY_DATA:
ee.Initialize(credentials=ee.ServiceAccountCredentials(EE_ACCOUNT, key_data=EE_PRIVATE_KEY_DATA))
else:
ee.Initialize()
except ee.EEException:
ee.Authenticate()
ee.Initialize()
Load sample data#
Vehicle tracks#
[ ]:
ecoscope.io.download_file(
f"{ECOSCOPE_RAW}/tests/sample_data/vector/KDB025Z.csv",
os.path.join(output_dir, "KDB025Z.csv"),
)
vehicle_gdf = pd.read_csv(os.path.join(output_dir, "KDB025Z.csv"), index_col="id")
vehicle_gdf["geometry"] = vehicle_gdf["geometry"].apply(lambda x: shapely.wkt.loads(x))
vehicle_gdf = ecoscope.base.Relocations.from_gdf(gpd.GeoDataFrame(vehicle_gdf, crs=4326))
vehicle_gdf = ecoscope.base.Trajectory.from_relocations(vehicle_gdf)
Elephant Sightings#
[ ]:
ecoscope.io.download_file(
f"{ECOSCOPE_RAW}/tests/sample_data/vector/elephant_sighting.csv",
os.path.join(output_dir, "elephant_sighting.csv"),
)
events_df = pd.read_csv(os.path.join(output_dir, "elephant_sighting.csv"), index_col="id")
events_df["geometry"] = events_df["geometry"].apply(lambda x: shapely.wkt.loads(x))
events_gdf = gpd.GeoDataFrame(events_df, crs=4326)
Regions#
[ ]:
ecoscope.io.download_file(
f"{ECOSCOPE_RAW}/tests/sample_data/vector/maec_4zones_UTM36S.gpkg",
os.path.join(output_dir, "maec_4zones_UTM36S.gpkg"),
)
region_gdf = gpd.read_file(os.path.join(output_dir, "maec_4zones_UTM36S.gpkg")).to_crs(4326)
MovBank Relocations#
[ ]:
ecoscope.io.download_file(
f"{ECOSCOPE_RAW}/tests/sample_data/vector/movbank_data.csv",
os.path.join(output_dir, "movbank_data.csv"),
)
df = pd.read_csv(os.path.join(output_dir, "movbank_data.csv"), index_col=0)
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(x=df["location-long"], y=df["location-lat"]), crs=4326)
movbank_relocations_gdf = ecoscope.base.Relocations.from_gdf(
gdf, groupby_col="individual-local-identifier", time_col="timestamp"
)
pnts_filter = ecoscope.base.RelocsCoordinateFilter(
min_x=-5,
max_x=1,
min_y=12,
max_y=18,
filter_point_coords=[[180, 90], [0, 0]],
)
movbank_relocations_gdf.apply_reloc_filter(pnts_filter, inplace=True)
movbank_relocations_gdf.remove_filtered(inplace=True)
EcoMap#
Basic Two-Layer EcoMap#
[ ]:
# Initialize EcoMap by setting the zoom level and center
m = ecoscope.mapping.EcoMap(center=(0.0236, 37.9062), zoom=6, height=800, width=1000, static=False)
# Add two tiled basemaps (OSM and Google satellite)
m.add_basemap("OpenStreetMap")
m.add_tile_layer(
url="https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
name="Google Satellite",
attribution="Google",
opacity=0.5,
)
# Display
m
Elephant Sighting Map#
[ ]:
m = ecoscope.mapping.EcoMap(width=800, height=600)
# Add two tiled basemaps (OSM and Google Satellite Hybrid)
m.add_basemap("OpenStreetMap")
m.add_basemap("HYBRID")
# Set DEM visualization parameters
vis_params = {"min": 0, "max": 4000, "opacity": 0.5, "palette": ["006633", "E5FFCC", "662A00", "D8D8D8", "F5F5F5"]}
# Add Google Earth Engine elevation layer
dem = ee.Image("USGS/SRTMGL1_003")
m.add_ee_layer(dem.updateMask(dem.gt(0)), vis_params, "DEM")
# Zoom in and add regions outlines
m.zoom_to_gdf(region_gdf)
m.add_gdf(
region_gdf,
style_kwds={"fillOpacity": 0.1, "opacity": 0.5, "color": "black"},
color=["#7fc97f", "#beaed4", "#fdc086", "#ffff99"],
)
# Add trajectory
vehicle_gdf.geometry.explore(m=m, color="#468af7")
# Add elephant sighting events
m.add_gdf(
events_gdf[["geometry", "serial_number", "location", "title", "event_type"]],
color="#f746ad",
marker_type="circle_marker",
marker_kwds={"radius": 7, "fill": True, "draggable": False},
)
# Add title
m.add_title(title="Elephant Sighting Map", align="center", font_size="18px")
# Add north-arrow
m.add_north_arrow(
position="top-left",
)
# Add legend
m.add_legend(legend_dict={"KDB025Z_Tracks": "468af7", "Elephant_Sighting_Events": "f746ad"})
# Display
m
Add local geotiff to a map#
[ ]:
ecoscope.io.download_file(
f"{ECOSCOPE_RAW}/tests/sample_data/raster/mara_dem.tif",
os.path.join(output_dir, "mara_dem.tif"),
)
m = ecoscope.mapping.EcoMap(width=800, height=600)
m.add_local_geotiff(path=os.path.join(output_dir, "mara_dem.tif"), zoom=True, cmap="jet", colorbar=True)
m
Day-Night Relocations Map#
[ ]:
movbank_relocations_gdf["is_night"] = ecoscope.analysis.astronomy.is_night(
movbank_relocations_gdf.geometry, movbank_relocations_gdf.fixtime
)
movbank_relocations_gdf[["groupby_col", "fixtime", "geometry", "is_night"]]
[ ]:
colors = ["#292965" if is_night else "#e7a553" for is_night in movbank_relocations_gdf.is_night]
m = movbank_relocations_gdf[["groupby_col", "fixtime", "geometry", "is_night"]].explore(
m=ecoscope.mapping.EcoMap(width=800, height=600), color=colors
)
m.zoom_to_gdf(movbank_relocations_gdf)
m.add_legend(title="Is Night", legend_dict={True: "292965", False: "e7a553"})
m.add_north_arrow(position="topright")
m.add_title(title="Day-Night Relocation Map", align="center", font_size="18px")
m
Day-Night Trajectory Map#
[ ]:
movbank_trajectory_gdf = ecoscope.base.Trajectory.from_relocations(movbank_relocations_gdf)
movbank_traj_seg_filter = ecoscope.base.TrajSegFilter(
min_length_meters=0.0,
max_length_meters=float("inf"),
min_time_secs=0.0,
max_time_secs=4 * 60 * 60,
min_speed_kmhr=0.0,
max_speed_kmhr=10.0,
)
movbank_trajectory_gdf.apply_traj_filter(movbank_traj_seg_filter, inplace=True)
[ ]:
colors = ["#292965" if is_night else "#e7a553" for is_night in movbank_trajectory_gdf.extra__is_night]
m = movbank_trajectory_gdf[["groupby_col", "segment_start", "segment_end", "geometry", "extra__is_night"]].explore(
color=colors, m=ecoscope.mapping.EcoMap(width=800, height=600)
)
m.zoom_to_gdf(movbank_trajectory_gdf)
m.add_legend(title="Is Night", legend_dict={True: "292965", False: "e7a553"})
m.add_north_arrow(position="topright")
m.add_title(title="Day-Night Trajectory Map", align="center", font_size="18px")
m
Speed Map#
[ ]:
m = ecoscope.mapping.EcoMap()
m.add_speedmap(trajectory=movbank_trajectory_gdf, classification_method="equal_interval", num_classes=6, bins=None)
m.add_north_arrow(position="topright")
m.add_title(title="Elephant Speed Map", align="center", font_size="18px")
m.zoom_to_gdf(movbank_trajectory_gdf)
m
ETD Range#
[ ]:
raster_profile = ecoscope.io.raster.RasterProfile(
pixel_size=250.0, # You may need to reduce grid size if you receive a warning during the calculation
crs="ESRI:102022", # Albers Africa Equal Area Conic
nodata_value=np.nan,
band_count=1,
)
[ ]:
def f(trajectory_gdf):
output_path = os.path.join(output_dir, f"{trajectory_gdf.name}.tif")
ecoscope.analysis.UD.calculate_etd_range(
trajectory_gdf=trajectory_gdf,
output_path=output_path,
max_speed_kmhr=1.05 * trajectory_gdf.speed_kmhr.max(), # Choose a value above the max recorded segment speed
raster_profile=raster_profile,
expansion_factor=1.3,
)
return output_path
etd = movbank_trajectory_gdf.groupby("groupby_col").apply(f)
[ ]:
percentile_areas = ecoscope.analysis.get_percentile_area(
percentile_levels=[50, 60, 70, 80, 90, 99.9], raster_path=etd.at["Salif Keita"], subject_id="Salif Keita"
).to_crs(4326)
m = ecoscope.mapping.EcoMap(width=800, height=600, static=True)
m.add_gdf(percentile_areas, column="percentile", cmap="RdYlGn")
m.zoom_to_gdf(percentile_areas)
m.add_title(title="Salif ETD Range", align="center", font_size="18px")
m.add_north_arrow(position="topleft")
m
Export#
As HTML#
[ ]:
m.to_html(os.path.join(output_dir, "ecomap.html"))
As PNG#
[ ]:
m.to_png(os.path.join(output_dir, "ecomap.png"))