Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sentinel2-support #30

Merged
merged 3 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The **landsatxplore** Python package provides an interface to the [EarthExplorer](http://earthexplorer.usgs.gov/) portal to search and download [Landsat Collections](https://landsat.usgs.gov/landsat-collections) scenes through a command-line interface or a Python API.

It supports three data sets: `LANDSAT_TM_C1`, `LANDSAT_ETM_C1` and `LANDSAT_8_C1`.
It supports four data sets: `LANDSAT_TM_C1`, `LANDSAT_ETM_C1`, `LANDSAT_8_C1`, and `SENTINEL_2A`.

# Quick start

Expand Down Expand Up @@ -84,8 +84,8 @@ Usage: landsatxplore search [OPTIONS]
Options:
-u, --username TEXT EarthExplorer username.
-p, --password TEXT EarthExplorer password.
-d, --dataset [LANDSAT_TM_C1|LANDSAT_ETM_C1|LANDSAT_8_C1]
Landsat data set.
-d, --dataset [LANDSAT_TM_C1|LANDSAT_ETM_C1|LANDSAT_8_C1|SENTINEL_2A]
EO data set.
-l, --location FLOAT... Point of interest (latitude, longitude).
-b, --bbox FLOAT... Bounding box (xmin, ymin, xmax, ymax).
-c, --clouds INTEGER Max. cloud cover (1-100).
Expand Down
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ download `Landsat
Collections <https://landsat.usgs.gov/landsat-collections>`__ scenes
through a command-line interface or a Python API.

It supports three data sets: ``LANDSAT_TM_C1``, ``LANDSAT_ETM_C1`` and
``LANDSAT_8_C1``.
It supports four data sets: ``LANDSAT_TM_C1``, ``LANDSAT_ETM_C1``,
``LANDSAT_8_C1`` and ``SENTINEL_2A``.

Installation
============
Expand Down Expand Up @@ -53,8 +53,8 @@ Searching
Options:
--username TEXT EarthExplorer username.
--password TEXT EarthExplorer password.
--dataset [LANDSAT_TM_C1|LANDSAT_ETM_C1|LANDSAT_8_C1]
Landsat data set.
--dataset [LANDSAT_TM_C1|LANDSAT_ETM_C1|LANDSAT_8_C1|SENTINEL_2A]
EO data set.
--location FLOAT... Point of interest (latitude, longitude).
--bbox FLOAT... Bounding box (xmin, ymin, xmax, ymax).
--clouds INTEGER Max. cloud cover (1-100).
Expand Down
4 changes: 2 additions & 2 deletions landsatxplore/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def search(
Parameters
----------
dataset : str
LANDSAT_TM_C1, LANDSAT_ETM_C1, or LANDSAT_8_C1.
LANDSAT_TM_C1, LANDSAT_ETM_C1, LANDSAT_8_C1 or SENTINEL_2A.
latitude : float, optional
Latitude of the point of interest.
longitude : float, optional
Expand Down Expand Up @@ -100,7 +100,7 @@ def search(
}

if latitude and longitude:
params.update(spatialFilter=spatial_filter(latitude, longitude))
params.update(spatialFilter=spatial_filter(longitude, latitude))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this is swapped again: longitude is x axis, latitude is y. So, leave this as before (i.e., latitude, longitude) and change only the bbox order as the change implemented below, or only change this line to be longitude, latitude but leave the bbox as originally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Veronica, thanks for checking again, indeed I grew more and more confused with the x/y swapping ;-)
Let's do an example:

lon/lat only

Longitude 10.0°E, Latitude 50.0°N
landsatxplore search -u ... -p ... -d ... -s ... -e ... -l 50 10 (according to the readme, latitude comes first)
In cli.pyit gets into a dictionary:

    if location:
        latitude, longitude = location
        where.update(latitude=latitude, longitude=longitude) # so here latitude=50, longitude=10

Then, in api.search (api.py):

        if latitude and longitude:
            params.update(spatialFilter=spatial_filter(longitude, latitude))
# i.e.      params.update(spatialFilter=spatial_filter(10,50))

... and in datamodels.py:

def spatial_filter(xmin, ymin, xmax=None, ymax=None):
    if not xmax and not ymax:
        xmax = xmin + 0.1
        ymax = ymin + 0.1
    lower_left = coordinate(ymin, xmin) # coordinate(50,10)
    upper_right = coordinate(ymax, xmax) # coordinate(50.1,10.1)

# and coordinate is defined as
def coordinate(latitude, longitude):
    return {
        'latitude': latitude, # 'latitude': 50
        'longitude': longitude # 'longitude': 10
    }

This looks correct so far, now for a bounding box with xmin=10°E, ymin=50°N, xmax=11°E, ymax=51°N

bbox only

landsatxplore search -u ... -p ... -d ... -s ... -e ... -b 10 50 11 51 (according to the readme, x_min=longitude comes first here)
Then, in cli.py it is saved as bbox in this order:

    if bbox:
        where.update(bbox=bbox) # bbox = (10, 50, 11, 51)

then, in api.search (api.py):

        if bbox:
            params.update(spatialFilter=spatial_filter(*bbox)) # e.g. (spatial_filter(10, 50, 11, 51))

and in datamodels.py:

def spatial_filter(xmin, ymin, xmax=None, ymax=None):
    lower_left = coordinate(ymin, xmin) # coordinate(50,10)
    upper_right = coordinate(ymax, xmax) # coordinate(51,11)

...eventually

def coordinate(latitude, longitude):
    return {
        'latitude': latitude, # 'latitude': 50
        'longitude': longitude # 'longitude': 10
    }

So this looks correct too. I think most of the confusion comes from the fact that the -l flag takes latitude first and the -b flag takes longitude first. For my local testing with landsatxplore, all api-search results using both lat/lon or bbox made sense. But indeed I did not test it for i.landsat.download, as I simply assumed that since i.landsat.download depends on the bbox, which was changed in this PR, it would need to be adapted there too.

if bbox:
params.update(spatialFilter=spatial_filter(*bbox))
if max_cloud_cover:
Expand Down
4 changes: 2 additions & 2 deletions landsatxplore/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from landsatxplore.api import API
from landsatxplore.earthexplorer import EarthExplorer

DATASETS = ['LANDSAT_TM_C1', 'LANDSAT_ETM_C1', 'LANDSAT_8_C1']
DATASETS = ['LANDSAT_TM_C1', 'LANDSAT_ETM_C1', 'LANDSAT_8_C1', 'SENTINEL_2A']


@click.group()
Expand Down Expand Up @@ -88,7 +88,7 @@ def search(username, password, dataset, location, bbox, clouds, start, end, outp
envvar='LANDSATXPLORE_USERNAME')
@click.option('--password', '-p', type=click.STRING, help='EarthExplorer password.',
envvar='LANDSATXPLORE_PASSWORD')
@click.option('--output', '-o', type=click.Path(exists=True, dir_okay=True),
@click.option('--output', '-o', type=click.Path(exists=True, dir_okay=True),
default='.', help='Output directory.')
@click.argument('scenes', type=click.STRING, nargs=-1)
def download(username, password, output, scenes):
Expand Down
10 changes: 5 additions & 5 deletions landsatxplore/datamodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def spatial_filter(xmin, ymin, xmax=None, ymax=None):
Max. x coordinate (max longitude).
ymax : float, optional
Max. y coordinate (max latitude).

Returns
-------
spatial_filter : dict
Expand All @@ -46,8 +46,8 @@ def spatial_filter(xmin, ymin, xmax=None, ymax=None):
if not xmax and not ymax:
xmax = xmin + 0.1
ymax = ymin + 0.1
lower_left = coordinate(xmin, ymin)
upper_right = coordinate(xmax, ymax)
lower_left = coordinate(ymin, xmin)
upper_right = coordinate(ymax, xmax)
return {
'filterType': 'mbr',
'lowerLeft': lower_left,
Expand All @@ -64,7 +64,7 @@ def temporal_filter(start_date, end_date=None):
ISO 8601 formatted date.
end_date : str, optional
ISO 8601 formatted date.

Returns
-------
temporal_filter : dict
Expand All @@ -75,4 +75,4 @@ def temporal_filter(start_date, end_date=None):
return {
'startDate': start_date,
'endDate': end_date
}
}
3 changes: 2 additions & 1 deletion landsatxplore/earthexplorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
DATASETS = {
"LANDSAT_TM_C1": "5e83d08fd9932768",
"LANDSAT_ETM_C1": "5e83a507d6aaa3db",
"LANDSAT_8_C1": "5e83d0b84df8d8c2"
"LANDSAT_8_C1": "5e83d0b84df8d8c2",
"SENTINEL_2A": "5e83a42c6eba8084" # also contains Sentinel_2B data
}


Expand Down
6 changes: 5 additions & 1 deletion landsatxplore/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ def guess_dataset(identifier):
"""Guess data set based on a scene identifier."""
if is_product_id(identifier):
sat = int(identifier[3])
# S2 data only has numbers in entity_id
elif identifier.isdecimal():
sat = 1
else:
sat = int(identifier[2])
datasets = {5: 'LANDSAT_TM_C1', 7: 'LANDSAT_ETM_C1', 8: 'LANDSAT_8_C1'}
datasets = {1: "SENTINEL_2A", 5: 'LANDSAT_TM_C1', 7: 'LANDSAT_ETM_C1',
8: 'LANDSAT_8_C1'}
return datasets[sat]