Use CopPhil JupyterLab and Python to find all Sentinel 2 products over Manila in 2024
Typical uses of Sentinel 2 Level data are
land cover and vegetation analysis
agricultural monitoring
water quality and inland water monitoring
soil and land surface monitoring
urban and coastal management
disaster and emergency management
climate change research
In this article, we cover an example of creating a search query for CopPhil OData API using CopPhil Data Explorer. We are going to discover products available from Sentinel-2 Level 2 data, acquired over Manila from 2024-01-01 to 2024-09-30.
Prerequisites
No. 1 Access to CopPhil site
You need a CopPhil hosting account, available at https://infra.copphil.philsa.gov.ph.
No. 2 Access to JupyterLab
JupyterLab used in this article is available here: https://jupyter.infra.copphil.philsa.gov.ph/hub/login?next=%2Fhub%2F.
No. 3 Working knowledge of JupyterLab
See article Introduction to JupyterLab on CopPhil
No. 4 Using API
This is an introductory example of obtaining EODATA using API calls, in Python:
Download satellite data using API on CopPhil
No. 5 Information on Sentinel-2 mission
Page Sentinel-2 mission shows basic information on Sentinel-2 mission, which is used in this article as a source of information.
What We Are Going To Cover
Preparing your environment
Generating a query using Python and API structure
Building a query
Generated URL
Inspecting the results of the request
Number of the found products
Metadata of the found products
Additional filters
Generated url
Inspecting results of the request
Number of the found products
Metadata for the found products
Prepare your environment
Import necessary python libraries.
# HTTP requests
import requests
# JSON parser
import json
# data manipulation
import pandas as pd
Generate a query using python and API structure
Now, let us build a query for Sentinel-2 Level 2 data acquired over Manila from 2024-01-01 to 2024-09-30.
Build a query
In order to find desired products it is needed to determine specific filters:
- collection_name
Sentinel-1, Sentinel-2 etc.
- product_type
MSIL1C, MSIL2A
- aoi
extent (coordinates) of the area of interest (WGS84)
- search_period_start
time range - start date
- search_period_end
time range - end date
Filters above correspond to the filters which are provided via GUI.
# base URL of the product catalogue
catalogue_odata_url = "https://catalogue.infra.copphil.philsa.gov.ph/odata/v1"
# search parameters
collection_name = "SENTINEL-2"
product_type = "S2MSI2A"
aoi = "POLYGON((120.962986 14.598416, 120.995964 14.599182, 120.999658 14.563436, 120.960348 14.567522, 120.962986 14.598416))"
search_period_start = "2024-01-01T00:00:00.000Z"
search_period_end = "2024-09-30T00:00:00.000Z"
Generated url
Show the generated query as url.
search_query = f"{catalogue_odata_url}/Products?$filter=Collection/Name eq '{collection_name}' and Attributes/OData.CSC.StringAttribute/any(att:att/Name eq 'productType' and att/OData.CSC.StringAttribute/Value eq '{product_type}') and OData.CSC.Intersects(area=geography'SRID=4326;{aoi}') and ContentDate/Start gt {search_period_start} and ContentDate/Start lt {search_period_end}"
print(f"""\n{search_query.replace(' ', "%20")}\n""")
This would be the result:
Inspect the results of the request
Get the results and verify whether query was executed properly (and whether it works). If Status code is 200, it works fine. Convert the content of the response to JSON and inspect it.
response = requests.get(search_query)
print(f'Status code is {response.status_code}')
response = requests.get(search_query).json()
Status code is 200
Number of the found products
Show the number of found products which fits into filters requirements.
result = pd.DataFrame.from_dict(response["value"])
len(result)
20
Metadata of the found products
Inspect the metadata of the products which fits into query requirements. Use pandas library to visualize metadata in table format.
result.head()
@odata.mediaContentType | Id | Name | ContentType | ContentLength | OriginDate | PublicationDate | ModificationDate | Online | EvictionDate | S3Path | Checksum | ContentDate | Footprint | GeoFootprint | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | application/octet-stream | e672713e-49bb-4875-8801-ea9ac6f75c2b | S2A_MSIL2A_20240117T022021_N0510_R003_T51PTS_2... | application/octet-stream | 1056120269 | 2024-01-17T06:19:12.000000Z | 2024-01-17T06:32:29.344413Z | 2024-03-13T18:34:26.338916Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/01/17/S2A_MSIL... | [{'Value': 'a6a7342e05993610bbfc4e98f4a88c09',... | {'Start': '2024-01-17T02:20:21.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
1 | application/octet-stream | 6cd59c03-5f06-4778-9b5a-c3896289dd22 | S2B_MSIL2A_20240312T021529_N0510_R003_T51PTS_2... | application/octet-stream | 835688199 | 2024-03-12T05:43:58.000000Z | 2024-03-12T05:51:40.416293Z | 2024-03-12T05:52:32.423248Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/03/12/S2B_MSIL... | [{'Value': 'f60a7ea9494fddc85d8ae353a87aad77',... | {'Start': '2024-03-12T02:15:29.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
2 | application/octet-stream | c1e63eb7-c683-4f0b-b706-c24198c5b114 | S2A_MSIL2A_20240127T021941_N0510_R003_T51PTS_2... | application/octet-stream | 1067374355 | 2024-01-27T06:26:14.000000Z | 2024-01-27T06:48:55.704601Z | 2024-03-13T09:08:15.643286Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/01/27/S2A_MSIL... | [{'Value': '711e110e4b428370817bf0675fb77b7f',... | {'Start': '2024-01-27T02:19:41.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
3 | application/octet-stream | 8d4f4fee-6068-48d4-82b6-dd078aca3052 | S2B_MSIL2A_20240102T022109_N0510_R003_T51PTS_2... | application/octet-stream | 1120991558 | 2024-01-02T05:39:37.416000Z | 2024-01-02T06:00:52.579790Z | 2024-03-13T12:26:57.315310Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/01/02/S2B_MSIL... | [{'Value': '57958f2c5eda253d13181238541c85b1',... | {'Start': '2024-01-02T02:21:09.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
4 | application/octet-stream | 678423d6-f064-4bbb-a708-7f0a0068683a | S2B_MSIL2A_20240112T022049_N0510_R003_T51PTS_2... | application/octet-stream | 1112555506 | 2024-01-16T15:55:45.000000Z | 2024-01-16T16:38:59.547061Z | 2024-03-13T18:31:18.750124Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/01/12/S2B_MSIL... | [{'Value': 'b56b2774d43c66b7877f3a802374109d',... | {'Start': '2024-01-12T02:20:49.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
Additional filters
Add one more filter so that only the cloudless images will be listed.
- max_cloud_cover
maximum cloud cover (%) fo the image
Generated url
Show the generated query as url.
max_cloud_cover = 20
search_query = f"{search_query} and Attributes/OData.CSC.DoubleAttribute/any(att:att/Name eq 'cloudCover' and att/OData.CSC.DoubleAttribute/Value le {max_cloud_cover})"
print(f"""\n{search_query.replace(' ', "%20")}\n""")
It yields:
Inspect results of the request
Get the results and verify whether the query was executed properly (and whether it works). If Status code is 200, it works fine. Convert content of the response to JSON format and inspect it.
response = requests.get(search_query)
print(f'Status code is {response.status_code}')
response = requests.get(search_query).json()
Status code is 200
Number of the found products
Show the number of found products which fits the requirements posed by the filters.
result = pd.DataFrame.from_dict(response["value"])
len(result)
6
Metadata for the found products
Inspect the metadata of the products which fits into query requirements. Use pandas library to visualize metadata in table format - first five rows.
result.head()
@odata.mediaContentType | Id | Name | ContentType | ContentLength | OriginDate | PublicationDate | ModificationDate | Online | EvictionDate | S3Path | Checksum | ContentDate | Footprint | GeoFootprint | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | application/octet-stream | 51b58ff8-4fd5-4fe3-b2f0-beebfee95bab | S2B_MSIL2A_20240211T021829_N0510_R003_T51PTS_2... | application/octet-stream | 1156520968 | 2024-02-11T06:09:02.000000Z | 2024-02-11T06:18:35.134676Z | 2024-03-13T10:30:49.000330Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/02/11/S2B_MSIL... | [{'Value': 'fc89b2ffa223c038953f7e67ea9145c8',... | {'Start': '2024-02-11T02:18:29.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
1 | application/octet-stream | dfe46249-bc17-401f-bf9a-bcc05efe77c7 | S2B_MSIL2A_20240302T021609_N0510_R003_T51PTS_2... | application/octet-stream | 1131528020 | 2024-03-02T05:42:43.000000Z | 2024-03-02T05:54:12.768121Z | 2024-03-02T05:55:36.451258Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/03/02/S2B_MSIL... | [{'Value': '02fce369b36758079e58eafce7ef1e9b',... | {'Start': '2024-03-02T02:16:09.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
2 | application/octet-stream | 4acc616f-1f77-460b-867e-4d3452dee225 | S2A_MSIL2A_20240426T021611_N0510_R003_T51PTS_2... | application/octet-stream | 1163640068 | 2024-04-26T08:56:54.000000Z | 2024-04-26T09:04:35.755846Z | 2024-04-26T09:06:00.728565Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/04/26/S2A_MSIL... | [{'Value': '53179d9d86cb6687ffcb3a46866ebd51',... | {'Start': '2024-04-26T02:16:11.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
3 | application/octet-stream | f5c26c11-d72d-4c91-80ec-fd7428c0d518 | S2A_MSIL2A_20240307T021541_N0510_R003_T51PTS_2... | application/octet-stream | 1130852495 | 2024-03-07T06:30:50.000000Z | 2024-03-07T06:40:56.016476Z | 2024-03-07T09:51:23.141122Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/03/07/S2A_MSIL... | [{'Value': '83ad987c68029bd4359e28dafc9e8d6a',... | {'Start': '2024-03-07T02:15:41.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
4 | application/octet-stream | cbdd1d86-52ac-4ee7-aa33-306019d525db | S2B_MSIL2A_20240421T021529_N0510_R003_T51PTS_2... | application/octet-stream | 1167844378 | 2024-04-21T05:42:13.000000Z | 2024-04-21T05:56:32.735338Z | 2024-04-21T05:58:09.183638Z | True | 9999-12-31T23:59:59.999999Z | /eodata/Sentinel-2/MSI/L2A/2024/04/21/S2B_MSIL... | [{'Value': 'f79de0b45c364db5e4a7354b39408f26',... | {'Start': '2024-04-21T02:15:29.024000Z', 'End'... | geography'SRID=4326;POLYGON ((120.205542908771... | {'type': 'Polygon', 'coordinates': [[[120.2055... |
What To Do Next
You can also use other satellites and their data to inspect conditions over Manila in a defined period of time. The following article uses
Sentinel-3 LST data with the GUI of
CopPhil Data Explorer