
Introduction
The development of Earth Observation and its technological infrastructure has increased considerably in the last decade. Many satellite constellations give open and handy access to their data and researchers can easily access it. For example, Google Earth Engine is a cloud infrastructure that gives access to data from many providers such as Modis, NOAA, ASTER, Lansat, and others, that you can explore and analyze straightforwardly. Give it a look in GEE. In case you want to use the API in Python you can do it with the geemap python library developed by Qiusheng Wu which has wonderful functionalities and can be used as it is in this tutorial.
The infrastructure models are running in near real-time so it is possible to get up-to-date data that helps monitor land and ocean. For this tutorial, we are going to work with the HYCOM dataset which contains a data-assimilative hybrid model that displays the Sea Surface Temperature and Salinity at the global level. The model contains depth values for each temporal layer so users can visualize the ocean at certain depths and dates. The Hybrid Coordinate Ocean Model has been part of many publications and the website contains a lot of documentation about the dataset. If you want to know more I recommend you to give a look at the official website.
App
Get access to the app in the next link:

Objective
What I want with this tutorial is to create an easy-to-use app that is able to display the Sea Surface Temperature at the global level. The features of the app should be:
- Selection of time
- Selection of depth
- Configuration of legend
Once the interaction is done we will deploy the app in the Streamlit cloud.
Data License
The HYCOM dataset is published as a Public Domain Mark 1.0. Users are able to copy, modify, and redistribute, even for commercial purposes. The distribution officially by HYCOM is US DOD Distribution A which expresses public release and unlimited distribution.
Coding tutorial
I hope you are familiar with Python programming before starting this tutorial. If not, then no worries just ask for help in this tutorial and I can suggest educational material. Generally, Python can be used nicely in Anaconda. I would recommend you have it and get familiar with package installation before starting. In any case, you will be able to deploy this app.
Libraries
Let’s start creating a python file and importing the needed libraries.
import json
from datetime import datetime, timedelta, date
import ee
import geemap.colormaps as cm
import geemap.foliumap as geemap
import streamlit as st
To make it work in Streamlit you might need to do GEE authentication with a key. The instruction about how to do it is already written in this clear and excellent tutorial by Mykola Kozyr.
Follow carefully the instructions given before and add your own credentials to the app.py file. It might look like this.
# ______ GEE Authenthication ______
# _____ STREAMLIT _______
# Secrets
json_data = st.secrets["json_data"]
service_account = st.secrets["service_account"]
# Preparing values
json_object = json.loads(json_data, strict=False)
json_object = json.dumps(json_object)
# Authorising the app
credentials = ee.ServiceAccountCredentials(service_account, key_data=json_object)
ee.Initialize(credentials)
Environment
To deploy in Streamlit you should add a requirements.txt
file that contains the needed packages for deployment. In this case, we will add requirements and an additional file packages.txt
Both files were taken from the gishub of geemap.
Add to the repo a requirements.txt
file with:
--find-links=https://girder.github.io/large_image_wheels GDAL
# cartopy
geemap
geopandas
ee
jupyter-server-proxy
leafmap
localtileserver
nbserverproxy
owslib
palettable
plotly
streamlit==1.12.2
streamlit-bokeh-events
streamlit-folium
tropycal
Also, an additional packages.txt
file with:
ffmpeg
gifsicle
build-essential
python3-dev
gdal-bin
libgdal-dev
libproj-dev
libgeos-dev
proj-bin
Layout configuration
Here we will add a title to the page, define a wide layout of Streamlit, and give tight limits to our canvas that will make the map looks nicer.
# _______________________ LAYOUT CONFIGURATION __________________________
st.set_page_config(page_title='SST monitor', layout="wide")
# shape the map
st.markdown(
f"""
<style>
.appview-container .main .block-container{{
padding-top: {3}rem;
padding-right: {2}rem;
padding-left: {0}rem;
padding-bottom: {0}rem;
}}
</style>
""",
unsafe_allow_html=True,
)
Sidebar configuration and parameters input
Here we will add aform
that will be used to input the parameters of the map such as depth and date. The current map is always displayed with the last available layer which is 2 days before the current date. Some comments in help are added.
Check the inline comments that describe the code.
## ___________________ SIDEBAR PARAMETERS ___________________________
st.sidebar.info('### ***Welcome***n###### ***Sea Surface Temperature (SST) monitor*** 🧐🌊🌡 ️')
form = st.sidebar.form('Ocean data')
with form:
# depths in slider
depth_options = [0, 2, 4, 6, 8, 10, 12, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 125, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1250, 1500, 2000, 2500, 3000, 4000, 5000]
depth = st.select_slider('Depth (m)', options = depth_options, value = 0, help = 'Depth in ocean to fetch temperature layer' )
# dates of sst
ocean_date = st.date_input('Date', min_value=datetime.strptime('1992-10-02', '%Y-%m-%d'), max_value = datetime.now(), help = 'Selected date of temperature to be displayed')
# conditions to get the available layer 2 days before today
if str(ocean_date) == str(date.today()):
ocean_date = ocean_date - timedelta(2)
if str(ocean_date) == str(date.today() - timedelta(1)):
ocean_date = ocean_date - timedelta(1)
# visualization threshold
min, max = st.slider('Min and Max (°C)', 0, 40, value=(10, 32), help='Threshold of visualization in Celsius')
# button to update visualization
update_depth = st.form_submit_button('Update')
Define map instance
In the map instance, we will add an ocean base map and call the ImageCollection, then we select the temperature layer from the first date in the collection. Take a look the image
variable.
To display the temperature correctly we use multiply and add. These parameters come by default in the GEE. Finally, we add the layer and a legend with a color bar. The depth and date will be displayed in the legend.
# __________________ MAP INSTANCE _________________
# add a map instance
Map = geemap.Map(zoom=3, center=(-10, -55))
Map.add_basemap('Esri.OceanBasemap') # "HYBRID"
# get the layer with current date
sst_thumb = ee.ImageCollection('HYCOM/sea_temp_salinity').filterDate(str(ocean_date)) #('2022-01-10', '2022-01-15')
# get fist date just in case, and select the depth, and transform the values
image = sst_thumb.limit(1, 'system:time_start', False).first().select(f'water_temp_{depth}').multiply(0.001).add(20)
vis_param = {'min': min,
'max': max, 'alpha': 0.4,
'palette': cm.palettes.jet,
}
# add image
Map.addLayer(image, vis_param)
# add color bar with depth and date info
Map.add_colorbar(vis_param, label = f'Sea Surface Temperature (C°) at {depth} depth on {ocean_date}', layer_name = f"SST at {depth} depth", discrete=False)
Map to Streamlit
Then, we send the map instance to Streamlit
# _______ DISPLAY ON STREAMLIT _______
Map.to_streamlit(height=600, responsive=True, scrolling=False)
Add extra information
We can add more information like the link to this tutorial, author, reference to the dataset, or any other extra info you want.
# _______ ADDITIONAL INFORMATION AND LINKS ________
st.sidebar.success('##### **Author and coding tutorial**n###### ***Bryan R. Vallejo***n##### ***[How to create a web app for ocean monitoring?](https://medium.com/@bryanvallejo16/monitoring-sea-surface-temperature-at-the-global-level-with-gee-1d7349c7da6)***n###### ***[Get ful access to more tutorials](https://bryanvallejo16.medium.com/membership)***')
st.sidebar.warning('##### **Dataset**n###### ***J. A. Cummings and O. M. Smedstad. 2013: Variational Data Assimilation for the Global Ocean. Data Assimilation for Atmospheric, Oceanic and Hydrologic Applications vol II, chapter 13, 303-343***n###### ***In [Google Earth Engine](https://developers.google.com/earth-engine/datasets/catalog/HYCOM_sea_temp_salinity#description)***')
st.sidebar.error('##### Notes: n###### ***The last STT layer availabe is 2 days before current date***')
st.sidebar.error('##### Related stories: n###### ***[Ocean currents seasonality in the Galapagos Islands, Ecuador](https://towardsdatascience.com/ocean-currents-seasonality-in-the-galapagos-islands-ecuador-9197f0b721c0)***n###### ***[Earth observation and biologging data for marine conservation](https://medium.com/gis4-wildlife-tracking/earth-observation-and-biologging-data-for-marine-conservation-989f2b3dc71d)***')
Limitation
The limitation we have for real-time ocean monitoring is that HYCOM has the last layer available for 2 days before the current date. Not really a limitation because 2 days are not a big difference for ocean temperature seasonality.
One common limitation is to display a global layer fast but thanks to geemap and its integration of folium it is possible to have fast and light visualization.
Future development
I imagine that future development might contain more features of the app for example adding more layers like salinity. If you have recommendations or needs for your own work do not hesitate to leave a comment.
Conclusion
The monitoring of the seasonalities of the ocean can be possible with a simple configuration of inputs and GEE. The development of the GEE API in python has made it possible to display easily and can support the monitoring of seasons. Also, it can be used for other purposes for example users can check which month has the best temperature for their next vacation beach.
Written by: