# 1. How to work with satellite data in Python

This tutorial will show the steps to grab data in ERDDAP from Python, how to work with NetCDF files in Python and how to make some maps and time-series of sea surface temperature (SST) around the main Hawaiian islands.

This tutorial is also available as a [Jupyter notebook](https://github.com/melhawaii/python-satellite-course/blob/master/OW_Tutorial1.ipynb).

You will need to install the `urllib`, `xarray` and `NetCDF4` packages if you don't already have them.

## Downloading data in Python

Because ERDDAP includes RESTful services, you can download data listed on any ERDDAP platform from R using the URL structure.&#x20;

For example, the following page allows you to subset monthly SST data:\
\
Select your region and date range of interest, then select the '.nc' (NetCDF) file type and click on "Just Generate the URL".

![](https://2946503769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LylLNCSXaUER_FiqDSx%2F-LzF98xDP8aCnkTb_TTM%2F-LzF9qqbKZxTfVMPubXN%2Fimage.png?alt=media\&token=6c605a56-e9cb-4a98-9395-37a4088974f0)

In this specific example, the URL we generated is :

[https://oceanwatch.pifsc.noaa.gov/erddap/griddap/CRW\_sst\_v1\_0\_monthly.nc?analysed\_sst\[(2018-01-01T12:00:00Z):1:(2018-12-01T12:00:00Z)\]\[(17):1:(30)\]\[(195):1:(210)\]](https://oceanwatch.pifsc.noaa.gov/erddap/griddap/CRW_sst_v1_0_monthly.nc?analysed_sst\[\(2018-01-01T12:00:00Z\):1:\(2018-12-01T12:00:00Z\)]\[\(17\):1:\(30\)]\[\(195\):1:\(210\)])

You can also edit this URL manually.&#x20;

In Python, run the following to download the data using the generated URL :

`import urllib.request` \
\
`url="https://oceanwatch.pifsc.noaa.gov/erddap/griddap/CRW_sst_v1_0_monthly.nc?analysed_sst[(2018-01-01T12:00:00Z):1:(2018-12-01T12:00:00Z)][(17):1:(30)][(195):1:(210)]"` \
\
`urllib.request.urlretrieve(url, "sst.nc")`

## Importing the downloaded data in R <a href="#importing-the-downloaded-data-in-r" id="importing-the-downloaded-data-in-r"></a>

Now that we've downloaded the data locally, we can import it and extract our variables of interest:

The `xarray` package makes it very convenient to work with NetCDF files. Documentation is available here:\
[http://xarray.pydata.org/en/stable/why-xarray.html](http://xarray.pydata.org/en/stable/why-xarray.html)

`import xarray as xr` \
`import netCDF4 as nc`

* Open the file and load it as an `xarray` dataset:

`ds = xr.open_dataset('sst.nc',decode_cf=False)`

* examine the data structure:

`ds`

&#x20;`Dimensions: (latitude: 261, longitude: 301, time: 12)`\
`Coordinates:`\
&#x20;`*time          (time) float64 1.515e+09 1.517e+09 ... 1.541e+09 1.544e+09`\
&#x20;`*latitude      (latitude) float32 17.025 17.075 17.125 ... 29.975 30.025`\
&#x20;`*longitude     (longitude) float32 195.025 195.075 ... 209.975 210.025`\
`Data variables:` \
&#x20;  `analysed_sst  (time, latitude, longitude) float64 ...`\
`Attributes:`\
&#x20;  `acknowledgement:            NOAA Coral Reef Watch Program`\
&#x20;  `cdm_data_type:              Grid`\
&#x20;  `comment:                    This product is designed to improve on and re...`\
&#x20;  `contributor_name:           NOAA Coral Reef Watch program`\
&#x20;  `contributor_role:           Collecting source data and deriving products;...`\
&#x20;  `Conventions:                CF-1.6, ACDD-1.3, COARDS`\
&#x20;  `creator_email:              coralreefwatch@noaa.gov`\
&#x20;  `creator_institution:        NOAA/NESDIS/STAR Coral Reef Watch program`\
&#x20;  `creator_name:               NOAA Coral Reef Watch program`\
&#x20;  `creator_type:               group`\
&#x20;  `creator_url:                https://coralreefwatch.noaa.gov/`   \
&#x20;  `data_source:                NOAA Daily Global 5km Geo-Polar Blended Night...`\
&#x20;  `date_created:               2018-01-01T00:00:00Z`\
&#x20;  `date_issued:                2018-12-02T15:20:07Z`\
&#x20;  `date_metadata_modified:     2018-09-01T00:00:00Z`\
&#x20;  `date_modified:              2018-01-01T00:00:00Z`\
&#x20;  `Easternmost_Easting:        210.025`\
&#x20;  `geospatial_bounds:          "POLYGON((-90.0 360.0, 90.0 360.0, 90.0 0.0, ...`\
&#x20;  `geospatial_bounds_crs:      EPSG:32663`\
&#x20;  `geospatial_lat_max:         30.025`\
&#x20;  `geospatial_lat_min:         17.025`\
&#x20;  `geospatial_lat_resolution:  0.049999999999999996`\
&#x20;  `geospatial_lat_units:       degrees_north`\
&#x20;  `geospatial_lon_max:         210.025`\
&#x20;  `geospatial_lon_min:         195.025`\
&#x20;  `geospatial_lon_resolution:  0.05000000000000001`\
&#x20;  `geospatial_lon_units:       degrees_east`\
&#x20;  `history:                    Mon Mar  2 06:00:23 2020: ncatted -O -a geosp...`\
&#x20;  `id:                         CoralTemp-v1.0`\
&#x20;  `infoUrl:                    https://coralreefwatch.noaa.gov/satellite/ble...`\
&#x20;  `institution:                NOAA/NESDIS/STAR Coral Reef Watch program`\
&#x20;  `instrument:                 ATSR-1, ATSR-2, AATSR, AVHRR, AVHRR-2, AVHRR-...`\
&#x20;  `instrument_vocabulary:      NOAA NODC Ocean Archive System Instruments`\
&#x20;  `keywords:                   5km, analysed, analysed_sst, analysis, blende...`\
&#x20;  `keywords_vocabulary:        GCMD Science Keywords`\
&#x20;  `license:                    OSTIA Usage Statement (1985-2002): IMPORTANT ...`\
&#x20;  `metadata_link:              https://coralreefwatch.noaa.gov/satellite/ble...`\
&#x20;  `naming_authority:           gov.noaa.coralreefwatch`\
&#x20;  `NCO:                        4.3.7`\
&#x20;  `nco_openmp_thread_number:   1`\
&#x20;  `Northernmost_Northing:      30.025`\
&#x20;  `platform:                   Ships, drifting buoys, moored buoys, TOGA-TAO...`\
&#x20;  `platform_vocabulary:        NOAA NODC Ocean Archive System Platforms`\
&#x20;  `processing_level:           L4`\
&#x20;  `product_version:            1.0`\
&#x20;  `program:                    NOAA Coral Reef Watch program`\
&#x20;  `project:                    NOAA Coral Reef Watch program`\
&#x20;  `publisher_email:            coralreefwatch@noaa.gov`\
&#x20;  `publisher_institution:      NOAA/NESDIS/STAR Coral Reef Watch program`\
&#x20;  `publisher_name:             NOAA Coral Reef Watch program`\
&#x20;  `publisher_type:             group`\
&#x20;  `publisher_url:              https://coralreefwatch.noaa.gov/`   \
&#x20;  `references:                 Donlon, et al., 2011. The Operational Sea Sur...`\
&#x20;  `source:                     OSTIA Sea Surface Temperature Reanalysis (nig...`\
&#x20;  `sourceUrl:                  (local files)`\
&#x20;  `Southernmost_Northing:      17.025`\
&#x20;  `standard_name_vocabulary:   CF Standard Name Table v27`\
&#x20;  `summary:                    CoralTemp 5km gap-free analysed blended sea s...`\
&#x20;  `time_coverage_duration:     P1D`\
&#x20;  `time_coverage_end:          2018-12-01T12:00:00Z`\
&#x20;  `time_coverage_resolution:   P1D`\
&#x20;  `time_coverage_start:        2018-01-01T12:00:00Z`\
&#x20;  `title:                      Sea Surface Temperature, Coral Reef Watch, Co...`\
&#x20;  `Westernmost_Easting:        195.025`

* examine which coordinates and variables are included in the dataset:

`ds.coords`

`Coordinates:`\
&#x20; `*time       (time) float64 1.515e+09 1.517e+09 ... 1.541e+09 1.544e+09`\
&#x20; `*latitude   (latitude) float32 17.025 17.075 17.125 ... 29.925 29.975 30.025`\
&#x20; `*longitude  (longitude) float32 195.025 195.075 195.125 ... 209.975 210.025`

`ds.data_vars`

`Data variables:` \
&#x20;  `analysed_sst (time, latitude, longitude) float64 ...`

* examine the structure of `analysed_sst:`

`ds.analysed_sst.shape`

`(12, 261, 301)`

Our dataset is a 3-D array with 261 rows corresponding to latitudes and 301 columns corresponding to longitudes,  for each of the 12 time steps.

* get the dates for each time step:

`dates=nc.num2date(ds.time,ds.time.units)` \
`dates`

`array([datetime.datetime(2018, 1, 1, 12, 0),`\
`datetime.datetime(2018, 2, 1, 12, 0),`\
`datetime.datetime(2018, 3, 1, 12, 0),`\
`datetime.datetime(2018, 4, 1, 12, 0),`\
`datetime.datetime(2018, 5, 1, 12, 0),`\
`datetime.datetime(2018, 6, 1, 12, 0),`\
`datetime.datetime(2018, 7, 1, 12, 0),`\
`datetime.datetime(2018, 8, 1, 12, 0),`\
`datetime.datetime(2018, 9, 1, 12, 0),`\
`datetime.datetime(2018, 10, 1, 12, 0),`\
`datetime.datetime(2018, 11, 1, 12, 0),`\
`datetime.datetime(2018, 12, 1, 12, 0)], dtype=object)`

## Working with the extracted data

### Creating a map for one time step <a href="#creating-a-map-for-one-time-step" id="creating-a-map-for-one-time-step"></a>

Let's create a map of SST for January 2018 (our first time step).

`import pandas as pd` \
`import numpy as np` \
`from matplotlib import pyplot as plt` \
`from matplotlib.colors import LinearSegmentedColormap np.warnings.filterwarnings('ignore')`

* set some color breaks

`np.nanmin(ds.analysed_sst)`

`17.922142857142862`

`np.nanmax(ds.analysed_sst)`

`28.390645161290323`

`levs = np.arange(17.5, 28.5, 0.05)`&#x20;

* define a color palette

`jet=["blue", "#007FFF", "cyan","#7FFF7F", "yellow", "#FF7F00", "red", "#7F0000"]`&#x20;

* set color scale using the jet palette

`cm = LinearSegmentedColormap.from_list('my_jet', jet, N=len(levs))`

* plot the SST map

`plt.contourf(ds.longitude, ds.latitude, ds.analysed_sst[0,:,:], levs,cmap=cm)`&#x20;

* plot color scale

`plt.colorbar()`&#x20;

* example of how to add points to the map

`plt.scatter(range(202,206),np.repeat(26,4),c='black')`&#x20;

* example of how to add a contour line

`plt.contour(ds.longitude, ds.latitude, ds.analysed_sst[0,:,:],levels=20,linewidths=1)`&#x20;

* plot title

`plt.title("Monthly Sea Surface Temperature " + dates[0].strftime('%b %Y'))`\
`plt.show()`

![](https://2946503769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LylLNCSXaUER_FiqDSx%2F-M6Vws-ZJCwjzNd7d500%2F-M6VyJsTB4DbCXQRbiV3%2Fimage.png?alt=media\&token=68891f2f-dd7f-4cf8-bb6d-1f285e86afcd)

### Plotting a time series  <a href="#plotting-a-time-series" id="plotting-a-time-series"></a>

Let's pick the following box : 18-23N, 200-206E. We are going to generate a time series of mean SST within that box.

* first, let subset our data:

`lat_bnds, lon_bnds = [18, 23], [200, 206]`\
`da=ds.sel(latitude=slice(lat_bnds), longitude=slice(lon_bnds))`

* let's plot the subset:

![](https://2946503769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LylLNCSXaUER_FiqDSx%2F-M6Vws-ZJCwjzNd7d500%2F-M6Vy7JJO7GF0QIYJTFk%2Fimage.png?alt=media\&token=20b1f02f-4257-41bd-b78f-f390a8dad309)

* let's compute the monthly mean over the bounding region:

`res=np.mean(da.analysed_sst,axis=(1,2))`

* let's plot the time-series:

`plt.figure(figsize=(8,4))` \
`plt.scatter(dates,res)` \
`plt.ylabel('SST (ºC)')`

![](https://2946503769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LylLNCSXaUER_FiqDSx%2F-M6VyKe5s-8LGWYVgGKa%2F-M6Vyil4flw-T8qBxERX%2Fimage.png?alt=media\&token=b871dc9f-db53-4f5f-beb6-e264a6413127)

### Creating a map of average SST over a year <a href="#creating-a-map-of-average-sst-over-a-year" id="creating-a-map-of-average-sst-over-a-year"></a>

* let's compute the yearly mean for the region:

`mean_sst=np.mean(ds.analysed_sst,axis=0)`

* let's plot the map of the 2018 average SST in the region:

`plt.contourf(ds.longitude, ds.latitude, mean_sst, levs,cmap=cm)` \
`plt.colorbar()` \
`plt.title("Mean SST " + dates[0].strftime('%Y-%m')+' - '+dates[11].strftime('%Y-%m'))` \
`plt.show()`

![](https://2946503769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LylLNCSXaUER_FiqDSx%2F-M6VzH5HrFM6jrR2cs2O%2F-M6VzPOV2zHTqCK7zFTA%2Fimage.png?alt=media\&token=76a02597-8d0b-4b7b-8a9c-cd2491a9853a)
