Skip to article frontmatterSkip to article content

EODAG - A quick start with DEDL

This notebook provides a quickstart guide for using the EODAG Python API and CLI to search, discover, and download DEDL data.

🚀 Launch in JupyterHub

Copyright: 2025 EUMETSAT
License: MIT
Authors: Serena Avolio (EUMETSAT/Starion)

EODAG - A quick start with DEDL

Prerequisites:References:Credit:

EODAG is a command line tool and a Python package for searching and downloading earth observation data via a unified API.

This quickstart tutorial has the aim to show how to get DEDL data using the EODAG python API. It contains some help tools to select the dataset of interest, the bounding box and the time range for searching DEDL data.

Detailed information about the usage of EODAG can be found on the project documentation page.

Throughout this quickstart notebook, you will learn:

  1. Setup: How to configure EODAG to use the provider DEDL.

  2. Discover: How to discover DEDL datasets through EODAG.

  3. Search products: How to search DEDL data through EODAG.

  4. Download products: How to download DEDL data through EODAG.

In this notebook the word ‘collection’, ‘dataset’ and ‘product type’ have the same meaning.

Note:

Please note that the two factor authentication (2FA) is still not implemented in EODAG. The users who have enabled 2FA on DESP will not be able to run this notebook.

Setup

In this section, we set:

  • The output_dir, the directory where to store downloaded products.

  • The DEDL credentials, you’ll be asked to enter your DEDL credentials.

  • The search timeout, it is of 60 seconds to avoid any unexpected errors because of long running search queries.

pip install --user --quiet --upgrade eodag
Note: you may need to restart the kernel to use updated packages.
import os
from getpass import getpass

workspace = 'eodag_workspace'
if not os.path.isdir(workspace):
    os.mkdir(workspace)
    
os.environ["EODAG__DEDL__DOWNLOAD__OUTPUT_DIR"] = os.path.abspath(workspace)

os.environ["EODAG__DEDL__SEARCH__TIMEOUT"]="60"
os.environ["DEFAULT_STREAM_REQUESTS_TIMEOUT"] = "15"
os.environ["EODAG__DEDL__PRIORITY"]="10"


DESP_USERNAME = input("Please input your DESP username or email: ")
DESP_PASSWORD = getpass("Please input your DESP password: ")

os.environ["EODAG__DEDL__AUTH__CREDENTIALS__USERNAME"]=DESP_USERNAME
os.environ["EODAG__DEDL__AUTH__CREDENTIALS__PASSWORD"]=DESP_PASSWORD
Please input your DESP username or email:  eum-dedl-user
Please input your DESP password:  ········

EODiscover

In this section, we:

  • import and instantiate an EODataAccessGateway object that will be used for all the operations in this tutorial.

  • discover DEDL collections. The collections are presented in a dropdown menu, selecting a collection its description will be prompted.

  • the collection selected will be used in the rest of the tutorial

#import and instantiate an EODataAccessGateway object 
from eodag import EODataAccessGateway, setup_logging
setup_logging(0)
dag = EODataAccessGateway()

#discover DEDL collections. The collections are presented in a dropdown menu, selecting a collection its description will be prompted.
import ipywidgets as widgets
from IPython.display import display, clear_output, HTML
from ipywidgets import Layout, Box
import json

#default values
DATASET_ID = 'EO.EUM.DAT.SENTINEL-3.OL_2_WFR___'


# Event listeners
def on_change(change):
    with output_area:
        clear_output()
        print(f'Selected: {change["new"]}')
        print('---------------------------------------------')
        delimiter=''
        global DATASET_ID
        DATASET_ID = delimiter.join(change["new"])
        product_types=dag.list_collections("dedl")
        index = next((i for i, d in enumerate(product_types) if d.id == DATASET_ID), None)
        
        print("TITLE: "+product_types[index].title)
        print("ABSTRACT: "+product_types[index].description)

options=[item.id for item in dag.list_collections("dedl")]
# Widgets
output_area = widgets.Output()

dropdown = widgets.Dropdown(
    options=options,
    value=options[0],
    description="Datasets:",
    disabled=False,
) 

dropdown.observe(on_change, names='value')


# Layout
# Define the layout for the dropdown
dropdown_layout = Layout(display='space-between', justify_content='center', width='80%')
# Create a box to hold the dropdown with the specified layout
box = Box([dropdown, output_area], layout=dropdown_layout)
display( box)  
Loading...

EOSearch

In this section, we define the search criteria to find data inside the chosen dataset.

  • Bounding box can be modified using the text inputs, it will be visualized on the map. Once selected, to use it for the search we need to use the ‘save bbox’ button under the map.

  • Time range can be modified using the inputs for dates under the map.

import folium
import datetime
import ipywidgets as widgets

from IPython.display import display, clear_output

# -----------------------------------------------------------------------------
# Default values
# -----------------------------------------------------------------------------

START_DATE = '2024-08-11'
END_DATE = '2024-08-13'

sw_lat = 37.0
sw_lng = 14.0
ne_lat = 38.0
ne_lng = 16.0

# -----------------------------------------------------------------------------
# Output widgets
# -----------------------------------------------------------------------------

map_output = widgets.Output(
    layout=widgets.Layout(
        width='1000px',
        height='550px'
    )
)

message_output = widgets.Output()

# -----------------------------------------------------------------------------
# Coordinate widgets
# -----------------------------------------------------------------------------

sw_lat_input = widgets.FloatText(
    value=sw_lat,
    description='SW Lat'
)

sw_lng_input = widgets.FloatText(
    value=sw_lng,
    description='SW Lng'
)

ne_lat_input = widgets.FloatText(
    value=ne_lat,
    description='NE Lat'
)

ne_lng_input = widgets.FloatText(
    value=ne_lng,
    description='NE Lng'
)

# -----------------------------------------------------------------------------
# Date widgets
# -----------------------------------------------------------------------------

start_date = widgets.DatePicker(
    description='Start Date',
    value=datetime.date(2024, 8, 11)
)

end_date = widgets.DatePicker(
    description='End Date',
    value=datetime.date(2024, 8, 13)
)

# -----------------------------------------------------------------------------
# Button
# -----------------------------------------------------------------------------

save_button = widgets.Button(
    description='Save BBox',
    button_style='success'
)

# -----------------------------------------------------------------------------
# Functions
# -----------------------------------------------------------------------------

def update_dates(change):
    global START_DATE, END_DATE

    if start_date.value:
        START_DATE = start_date.value.strftime('%Y-%m-%d')

    if end_date.value:
        END_DATE = end_date.value.strftime('%Y-%m-%d')


def update_map(change=None):

    with map_output:
        clear_output(wait=True)

        center_lat = (sw_lat_input.value + ne_lat_input.value) / 2
        center_lng = (sw_lng_input.value + ne_lng_input.value) / 2

        m = folium.Map(
            location=[center_lat, center_lng],
            zoom_start=6,
            tiles=None,
            width=1000,
            height=500
        )

        folium.WmsTileLayer(
            url='https://gibs.earthdata.nasa.gov/wms/epsg4326/best/wms.cgi',
            name='NASA Blue Marble',
            layers='BlueMarble_ShadedRelief',
            format='image/png',
            transparent=True,
            attr='NASA'
        ).add_to(m)

        folium.Rectangle(
            bounds=[
                [sw_lat_input.value, sw_lng_input.value],
                [ne_lat_input.value, ne_lng_input.value]
            ],
            color="#ff7800",
            fill=True,
            fill_opacity=0.3
        ).add_to(m)

        display(m)


def save_bbox(button):

    with message_output:
        clear_output()

        print("Current BBox:")
        print(f"SW Latitude : {sw_lat_input.value}")
        print(f"SW Longitude: {sw_lng_input.value}")
        print(f"NE Latitude : {ne_lat_input.value}")
        print(f"NE Longitude: {ne_lng_input.value}")

        print()
        print(f"Start Date: {START_DATE}")
        print(f"End Date  : {END_DATE}")

# -----------------------------------------------------------------------------
# Event handlers
# -----------------------------------------------------------------------------

for widget in [
    sw_lat_input,
    sw_lng_input,
    ne_lat_input,
    ne_lng_input
]:
    widget.observe(update_map, names='value')

start_date.observe(update_dates, names='value')
end_date.observe(update_dates, names='value')

save_button.on_click(save_bbox)

# -----------------------------------------------------------------------------
# Right panel
# -----------------------------------------------------------------------------

control_panel = widgets.VBox(
    [
        start_date,
        end_date,
        widgets.HTML("<hr>"),
        sw_lat_input,
        sw_lng_input,
        ne_lat_input,
        ne_lng_input,
        save_button,
        message_output
    ],
    layout=widgets.Layout(
        width='500px',
        padding='10px'
    )
)

# -----------------------------------------------------------------------------
# Main layout
# -----------------------------------------------------------------------------

layout = widgets.HBox(
    [
        map_output,      # LEFT
        control_panel    # RIGHT
    ],
    layout=widgets.Layout(
        align_items='flex-start'
    )
)

# Initial map draw
update_map()

display(layout)
Loading...

Selected criteria:

search_criteria = {
    "collection": DATASET_ID,    
    "datetime": f"{START_DATE}/{END_DATE}",
    "bbox": [sw_lng,sw_lat,ne_lng,ne_lat],
    "count": True
}

print(json.dumps(search_criteria, indent=2))
{
  "collection": "EO.EUM.DAT.SENTINEL-3.OL_2_WFR___",
  "datetime": "2024-08-11/2024-08-13",
  "bbox": [
    14.0,
    37.0,
    16.0,
    38.0
  ],
  "count": true
}

Use selected criteria to search data:

products_first_page = dag.search(**search_criteria)
print(f"Got {len(products_first_page)} products and an estimated total number of {products_first_page.number_matched} products.")
products_first_page
Loading...

See the available metadata:


if(len(products_first_page)>0):
    one_product = products_first_page[0]
    print(one_product.properties.keys())
dict_keys(['datetime', 'end_datetime', 'id', 'instruments', 'platform', 'start_datetime', 'title', 'updated', 'dedl:providers', 'dedl:size', 'dedl:uid', 'eodag:default_geometry', 'eodag:download_link', 'eumetsat:links', 'order:status', 'product:timeliness', 'product:type', 'sat:absolute_orbit', 'sat:orbit_cycle', 'sat:orbit_state', 'sat:relative_orbit'])

EODownload

In this section, we download one of the retrievied product.The first product is going to be downloaded.

if(len(products_first_page)>0):
    product_to_download = one_product
    product_path = dag.download(product_to_download)
    print(product_path)
/home/jovyan/dev-branch/DestinE-DataLake-Lab/HDA/EODAG/eodag_workspace/S3A_OL_2_WFR____20240811T091234_20240811T091534_20240812T163228_0180_115_321_2340_MAR_O_NT_003