[1]:
%matplotlib inline

import numpy as np
from scipy import constants
import matplotlib.pyplot as plt
[2]:
%load_ext autoreload
%autoreload 2

import s1etad
from s1etad import Sentinel1Etad, ECorrectionType

s1etad Python module: basic usage

Sentinel1Etad product

[3]:
filename = 'test/S1B_IW_ETA__AXDV_20190805T162509_20190805T162536_017453_020D3A_____.SAFE'
eta_ = Sentinel1Etad(filename)
[4]:
eta_
[4]:
Sentinel1Etad("test/S1B_IW_ETA__AXDV_20190805T162509_20190805T162536_017453_020D3A_____.SAFE")  # 0x7f8322328950
Sentinel-1 products list:
  S1B_IW_SLC__1ADV_20190805T162509_20190805T162536_017453_020D3A_A857.SAFE
Number of swaths: 3
Swath list: IW1, IW2, IW3
Grid sampling:
  x: 8.081406101630269e-07
  y: 0.028777788199999974
  unit: s
Grid spacing:
  x: 200.0
  y: 200.0
  unit: m
Processing settings:
  troposphericDelayCorrection: True
  ionosphericDelayCorrection: True
  solidEarthTideCorrection: True
  bistaticAzimuthCorrection: True
  dopplerShiftRangeCorrection: True
  FMMismatchAzimuthCorrection: True

Check which corrections have been enabled

[5]:
eta_.processing_setting()
[5]:
{'troposphericDelayCorrection': True,
 'ionosphericDelayCorrection': True,
 'solidEarthTideCorrection': True,
 'bistaticAzimuthCorrection': True,
 'dopplerShiftRangeCorrection': True,
 'FMMismatchAzimuthCorrection': True}

The burst catalogue

It is a pandas dataframe to allow easy filtering.

See also use cases in the “Use case 1: Selecting the bursts” section for a more complete explaination on the burst catalogue and the query mechanism.

[6]:
eta_.burst_catalogue.head()
[6]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
0 1 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:09.836779 2019-08-05 16:25:13.002336
1 4 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:12.570669 2019-08-05 16:25:15.736226
2 7 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:15.333337 2019-08-05 16:25:18.498893
3 10 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:18.096004 2019-08-05 16:25:21.261561
4 13 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:20.858672 2019-08-05 16:25:24.024229

Tip: the total number of bursts in a product can be retrieved as follows:

[7]:
print('Total number of bursts:', len(eta_.burst_catalogue))
Total number of bursts: 27

Swath objects

How many swaths are stored in a product?

[8]:
print('Number of swaths:', eta_.number_of_swath)
print('Swath list:', eta_.swath_list)
Number of swaths: 3
Swath list: ['IW1', 'IW2', 'IW3']

How to retieve a Sentinel1EtadSwath object

[9]:
swath = eta_['IW2']
[10]:
swath
[10]:
Sentinel1EtadSwath("/IW2")  0x7f8322b98590
Swaths ID: IW2
Number of bursts: 9
Burst list: [2, 5, 8, 11, 14, 17, 20, 23, 26]
Sampling start:
  x: 0.0003095178536924219
  y: 0.9208892223996372
  units: s
Sampling:
  x: 8.081406101630269e-07
  y: 0.028777788199999974
  units: s

Burst objects

[11]:
burst = swath[2]
[12]:
burst
[12]:
Sentinel1EtadBurst("/IW2/Burst0002")  0x7f8322b98e90
Swaths ID: IW2
Burst index: 2
Shape: (112, 523)
Sampling start:
  x: 0.0003095178536924219
  y: 0.9208892223996372
  units: s
Sampling:
  x: 8.081406101630269e-07
  y: 0.028777788199999974
  units: s

NOTE: one can only get bursts whose index is present in the “burst list” of the swath

[13]:
swath.burst_list
[13]:
[2, 5, 8, 11, 14, 17, 20, 23, 26]
[14]:
try:
    swath[1]
except IndexError as exc:
    print('ERROR: Ops someting went wrong:', repr(exc))
ERROR: Ops someting went wrong: IndexError('Burst0001 not found in /IW2')

String representation

Please note that the string representation of Sentinel1Etad object is a “one-line” string providing only basic information:

[15]:
print('Product:', str(eta_))
print('Swath:', str(swath))
print('Burst:', str(burst))
Product: Sentinel1Etad("S1B_IW_ETA__AXDV_20190805T162509_20190805T162536_017453_020D3A_____.SAFE")
Swath: Sentinel1EtadSwath("/IW2")  0x7f8322b98590
Burst: Sentinel1EtadBurst("/IW2/Burst0002")  0x7f8322b98e90

Anyway in Jupyer environments a richer representation is also available:

[16]:
eta_
[16]:
Sentinel1Etad("test/S1B_IW_ETA__AXDV_20190805T162509_20190805T162536_017453_020D3A_____.SAFE")  # 0x7f8322328950
Sentinel-1 products list:
  S1B_IW_SLC__1ADV_20190805T162509_20190805T162536_017453_020D3A_A857.SAFE
Number of swaths: 3
Swath list: IW1, IW2, IW3
Grid sampling:
  x: 8.081406101630269e-07
  y: 0.028777788199999974
  unit: s
Grid spacing:
  x: 200.0
  y: 200.0
  unit: m
Processing settings:
  troposphericDelayCorrection: True
  ionosphericDelayCorrection: True
  solidEarthTideCorrection: True
  bistaticAzimuthCorrection: True
  dopplerShiftRangeCorrection: True
  FMMismatchAzimuthCorrection: True

Iteration

It is possible to iterate over products and swats in the same way one does it with any ather python container.

[17]:
for swath in eta_:
    print(swath)
    for burst in swath:
        print(burst.burst_index, burst.swath_id, burst)
    print()
Sentinel1EtadSwath("/IW1")  0x7f8322bad0d0
1 IW1 Sentinel1EtadBurst("/IW1/Burst0001")  0x7f8322bad6d0
4 IW1 Sentinel1EtadBurst("/IW1/Burst0004")  0x7f8322baa810
7 IW1 Sentinel1EtadBurst("/IW1/Burst0007")  0x7f8322baa8d0
10 IW1 Sentinel1EtadBurst("/IW1/Burst0010")  0x7f8322ba7d50
13 IW1 Sentinel1EtadBurst("/IW1/Burst0013")  0x7f8322bad890
16 IW1 Sentinel1EtadBurst("/IW1/Burst0016")  0x7f8322ba7e50
19 IW1 Sentinel1EtadBurst("/IW1/Burst0019")  0x7f8322ba70d0
22 IW1 Sentinel1EtadBurst("/IW1/Burst0022")  0x7f8322b98610
25 IW1 Sentinel1EtadBurst("/IW1/Burst0025")  0x7f8322b98990

Sentinel1EtadSwath("/IW2")  0x7f8322b98590
2 IW2 Sentinel1EtadBurst("/IW2/Burst0002")  0x7f8322b98e90
5 IW2 Sentinel1EtadBurst("/IW2/Burst0005")  0x7f8322ba7410
8 IW2 Sentinel1EtadBurst("/IW2/Burst0008")  0x7f8322ba7f50
11 IW2 Sentinel1EtadBurst("/IW2/Burst0011")  0x7f8322baa090
14 IW2 Sentinel1EtadBurst("/IW2/Burst0014")  0x7f8322ba7590
17 IW2 Sentinel1EtadBurst("/IW2/Burst0017")  0x7f8322ba7490
20 IW2 Sentinel1EtadBurst("/IW2/Burst0020")  0x7f8322baa310
23 IW2 Sentinel1EtadBurst("/IW2/Burst0023")  0x7f831e2185d0
26 IW2 Sentinel1EtadBurst("/IW2/Burst0026")  0x7f8322b25450

Sentinel1EtadSwath("/IW3")  0x7f8322b25810
3 IW3 Sentinel1EtadBurst("/IW3/Burst0003")  0x7f8322b90f50
6 IW3 Sentinel1EtadBurst("/IW3/Burst0006")  0x7f8320b51f90
9 IW3 Sentinel1EtadBurst("/IW3/Burst0009")  0x7f831e2467d0
12 IW3 Sentinel1EtadBurst("/IW3/Burst0012")  0x7f831e246550
15 IW3 Sentinel1EtadBurst("/IW3/Burst0015")  0x7f8322baaad0
18 IW3 Sentinel1EtadBurst("/IW3/Burst0018")  0x7f8322b98cd0
21 IW3 Sentinel1EtadBurst("/IW3/Burst0021")  0x7f8322b98f90
24 IW3 Sentinel1EtadBurst("/IW3/Burst0024")  0x7f8322b988d0
27 IW3 Sentinel1EtadBurst("/IW3/Burst0027")  0x7f8322ba7dd0

How to iterate only on selected items

It is also possible to iterate on a sub-set of the products swaths (or a sub-set of the swath bursts):

[18]:
for swath in eta_.iter_swaths(['IW1', 'IW2']):  # no 'IW3'
    # list of bursts
    odd_bursts = [idx for idx in swath.burst_list if idx % 2 != 0]
    for burst in swath.iter_bursts(odd_bursts):
        print(f'{burst.burst_index:2} {burst.swath_id} {burst}')
 1 IW1 Sentinel1EtadBurst("/IW1/Burst0001")  0x7f8322bad6d0
 7 IW1 Sentinel1EtadBurst("/IW1/Burst0007")  0x7f8322baa8d0
13 IW1 Sentinel1EtadBurst("/IW1/Burst0013")  0x7f8322bad890
19 IW1 Sentinel1EtadBurst("/IW1/Burst0019")  0x7f8322ba70d0
25 IW1 Sentinel1EtadBurst("/IW1/Burst0025")  0x7f8322b98990
 5 IW2 Sentinel1EtadBurst("/IW2/Burst0005")  0x7f8322ba7410
11 IW2 Sentinel1EtadBurst("/IW2/Burst0011")  0x7f8322baa090
17 IW2 Sentinel1EtadBurst("/IW2/Burst0017")  0x7f8322ba7490
23 IW2 Sentinel1EtadBurst("/IW2/Burst0023")  0x7f831e2185d0

How to iterate on query results

The query mechanism is explained extensively in the following.

Queries can be performed using the Sentinel1Etad.query_burst method.

A simple example is a query for a specific swath:

[19]:
query_result = eta_.query_burst(swath='IW3')

for swath in eta_.iter_swaths(query_result):
    for burst in swath.iter_bursts(query_result):
        print(burst)
Sentinel1EtadBurst("/IW3/Burst0003")  0x7f8322b90f50
Sentinel1EtadBurst("/IW3/Burst0006")  0x7f8320b51f90
Sentinel1EtadBurst("/IW3/Burst0009")  0x7f831e2467d0
Sentinel1EtadBurst("/IW3/Burst0012")  0x7f831e246550
Sentinel1EtadBurst("/IW3/Burst0015")  0x7f8322baaad0
Sentinel1EtadBurst("/IW3/Burst0018")  0x7f8322b98cd0
Sentinel1EtadBurst("/IW3/Burst0021")  0x7f8322b98f90
Sentinel1EtadBurst("/IW3/Burst0024")  0x7f8322b988d0
Sentinel1EtadBurst("/IW3/Burst0027")  0x7f8322ba7dd0

Use cases for the Sentinel1Etad class

Use case 1 : Selecting the bursts

Selecting the burst by filtering in time

The availability of the burst catalogue, allows to perform queries and filter the burst by performing time selection using the first_time and last_time keywords of the query_burst method.

If no time is provided then all the burst are selected:

[20]:
df = eta_.query_burst()

print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 27
[20]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
0 1 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:09.836779 2019-08-05 16:25:13.002336
9 2 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:10.757668 2019-08-05 16:25:13.952003
18 3 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:11.736113 2019-08-05 16:25:14.930448
1 4 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:12.570669 2019-08-05 16:25:15.736226
10 5 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:13.520336 2019-08-05 16:25:16.714671

It is possible to reduce the selection by start time in this case the stop time is the last available burst:

[21]:
from dateutil import parser
first_time = parser.parse('2019-08-05T16:25:30.117898')

df = eta_.query_burst(first_time=first_time)

print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 4
[21]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
25 24 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:31.017231 2019-08-05 16:25:34.240344
8 25 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:31.880565 2019-08-05 16:25:35.046122
17 26 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:32.830232 2019-08-05 16:25:36.024566
26 27 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:33.779899 2019-08-05 16:25:36.974233

It is possible to reduce the selection by the stop time in this case the start time is the first available burst:

[22]:
last_time =  parser.parse('2019-08-05T16:25:20.117899')

df = eta_.query_burst(last_time=last_time)

print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 8
[22]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
0 1 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:09.836779 2019-08-05 16:25:13.002336
9 2 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:10.757668 2019-08-05 16:25:13.952003
18 3 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:11.736113 2019-08-05 16:25:14.930448
1 4 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:12.570669 2019-08-05 16:25:15.736226
10 5 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:13.520336 2019-08-05 16:25:16.714671

It is possible to reduce the selection by the start and stop time:

[23]:
first_time = parser.parse('2019-08-05T16:25:25.117898')
last_time =  parser.parse('2019-08-05T16:25:29.117899')

# query the catalogues for of all the swaths
df = eta_.query_burst(first_time=first_time, last_time=last_time)
print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 1
[23]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
23 18 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:25.520674 2019-08-05 16:25:28.715008

Selecting by swath (and time)

The time selection can be combined with a selection by swath using the swath keyword. If not used all the swath are used

[24]:
first_time = parser.parse('2019-08-05T16:25:00.117898')
last_time =  parser.parse('2019-08-05T16:25:40.117899')

# query the catalogue for a subset of the swaths
df = eta_.query_burst(first_time=first_time, last_time=last_time, swath='IW1')
print(f"Number of bursts: {len(df)}")
df
Number of bursts: 9
[24]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
0 1 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:09.836779 2019-08-05 16:25:13.002336
1 4 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:12.570669 2019-08-05 16:25:15.736226
2 7 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:15.333337 2019-08-05 16:25:18.498893
3 10 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:18.096004 2019-08-05 16:25:21.261561
4 13 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:20.858672 2019-08-05 16:25:24.024229
5 16 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:23.621340 2019-08-05 16:25:26.786896
6 19 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:26.355230 2019-08-05 16:25:29.549564
7 22 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:29.117897 2019-08-05 16:25:32.283454
8 25 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:31.880565 2019-08-05 16:25:35.046122

Query the catalogue for a subset of the swaths:

[25]:
first_time = parser.parse('2019-08-05T16:25:00.117898')
last_time =  parser.parse('2019-08-05T16:25:40.117899')

df = eta_.query_burst(first_time=first_time, last_time=last_time, swath=['IW1', 'IW2'])

print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 18
[25]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
0 1 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:09.836779 2019-08-05 16:25:13.002336
9 2 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:10.757668 2019-08-05 16:25:13.952003
1 4 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:12.570669 2019-08-05 16:25:15.736226
10 5 1 2 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW2 2019-08-05 16:25:13.520336 2019-08-05 16:25:16.714671
2 7 1 1 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW1 2019-08-05 16:25:15.333337 2019-08-05 16:25:18.498893

Selecting by Sentinel-1 product name (swath and time)

The time selection can be combined with a selection by swath using the product_name keyword.

[26]:
first_time = parser.parse('2019-08-05T16:25:00.117898')
last_time =  parser.parse('2019-08-05T16:25:40.117899')

product_name='S1B_IW_SLC__1SDV_20190805T162509_20190805T162536_017453_020D3A_AAAA.SAFE'
df = eta_.query_burst(first_time=first_time, last_time=last_time, product_name=product_name, swath=['IW3'])

print(f"Number of bursts: {len(df)}")
df.head()
Number of bursts: 9
[26]:
bIndex pIndex sIndex productID swathID azimuthTimeMin azimuthTimeMax
18 3 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:11.736113 2019-08-05 16:25:14.930448
19 6 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:14.470003 2019-08-05 16:25:17.693115
20 9 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:17.232671 2019-08-05 16:25:20.427005
21 12 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:19.995338 2019-08-05 16:25:23.189673
22 15 1 3 S1B_IW_SLC__1ADV_20190805T162509_20190805T1625... IW3 2019-08-05 16:25:22.758006 2019-08-05 16:25:25.952341

Use case 2 : Retrieving the corrections

The Sentinel1EtadBurst class allows to access the netcdf product to retrieve the corrections burst by burst.

The recommented way to retrieve a correction is:

s1etad.Sentinel1EtadBurst.get_correction(name, set_auto_mask=False,
                                         transpose=True, meter=False)

Available correction types are:

[27]:
s1etad.ECorrectionType.__members__
[27]:
mappingproxy({'TROPOSPHERIC': <ECorrectionType.TROPOSPHERIC: 'tropospheric'>,
              'IONOSPHERIC': <ECorrectionType.IONOSPHERIC: 'ionospheric'>,
              'GEODETIC': <ECorrectionType.GEODETIC: 'geodetic'>,
              'BISTATIC': <ECorrectionType.BISTATIC: 'bistatic'>,
              'DOPPLER': <ECorrectionType.DOPPLER: 'doppler'>,
              'FMRATE': <ECorrectionType.FMRATE: 'fmrate'>,
              'SUM': <ECorrectionType.SUM: 'sum'>})

Example:

[28]:
# correction = burst.get_correction('ionospheric')
#
# or equivalently
correction = burst.get_correction(s1etad.ECorrectionType.IONOSPHERIC, meter=True)
correction.keys()
[28]:
dict_keys(['x', 'unit', 'name'])
[29]:
az, rg = burst.get_burst_grid()
extent = [rg[0]*1e6, rg[-1]*1e6, az[0], az[-1]]

plt.figure()
plt.imshow(correction['x'], extent=extent, aspect='auto')
plt.xlabel('Range [$\mu s$]')
plt.ylabel('Azimuth [s]')
plt.grid()
plt.colorbar().set_label(f'[{correction["unit"]}]')
plt.title(f'{correction["name"]} correction (swath {burst.swath_id} burst {burst.burst_index})')
[29]:
Text(0.5, 1.0, 'ionospheric correction (swath IW3 burst 27)')
../_images/notebooks_s1etad-tutorial_63_1.png

In alternative, the following (deprecated) methods are available:

get_tropospheric_correction(set_auto_mask=False, transpose=True, meter=False)
get_ionospheric_correction(set_auto_mask=False, transpose=True, meter=False)
get_geodetic_correction(set_auto_mask=False, transpose=True, meter=False)
get_bistatic_correction(set_auto_mask=False, transpose=True, meter=False)
get_doppler_correction(set_auto_mask=False, transpose=True, meter=False)
get_fmrate_correction(set_auto_mask=False, transpose=True, meter=False)
get_sum_correction(set_auto_mask=False, transpose=True, meter=False)

Retrieving merged corrections

The Sentinel1Etad and Sentinel1EtadSwath classes provides methods to retrieve a specific correction for multiple bursts merged together for easy reperesentation purposes.

NOTE: the current implementation uses a very simple argorithm that iterates over selected bursts and stitches correction data together. In overlapping regions new data simpy overwrite the old ones. This is an easy algorithm and perfectly correct for atmospheric and geodetic correction. It is, instead, sub-optimal for stsyem corrections (bi-static, Doppler, FM Rate) which have different values in overlapping regions.

[30]:
# First select you burst
first_time = parser.parse('2019-08-05T16:25:00.117898')
last_time =  parser.parse('2019-08-05T16:25:40.117899')

# query the catalogue for a subset of the swaths
product_name='S1B_IW_SLC__1SDV_20190805T162509_20190805T162536_017453_020D3A_AAAA.SAFE'
df = eta_.query_burst(first_time=first_time, last_time=last_time, product_name=product_name)
# df = df[df.bIndex != 13]   # exclude burst n. 13 (IW1)) to test extended selection capabilities
# df = df[df.bIndex != 17]   # exclude burst n. 17 (IW2)) to test extended selection capabilities
# df = df[df.bIndex != 15]   # exclude burst n. 17 (IW3)) to test extended selection capabilities
[31]:
# common variables
dy = eta_.grid_spacing['y']
dx = eta_.grid_sampling['x'] * constants.c / 2
nswaths = len(df.swathID.unique())
vg = eta_.grid_spacing['y'] / eta_.grid_sampling['y']
vmin = 2.5
vmax = 3.5
to_km = 1. / 1000
[32]:
# iterate on swath to get de-bursted data (selected burst merged together)
fig, ax = plt.subplots(nrows=1, ncols=nswaths, figsize=[13, 8]) # , sharey='row')
for six, swath_ in enumerate(eta_.iter_swaths(df)):
    merged_correction = swath_.merge_correction(ECorrectionType.TROPOSPHERIC,
                                                selection=df, meter=True)
    merged_correction_data = merged_correction['x']

    ysize, xsize = merged_correction_data.shape
    x0 = merged_correction['first_slant_range_time'] * constants.c / 2  # [m]
    y0 = merged_correction['first_azimuth_time'] * vg                   # [m]
    x_axis = (x0 + np.arange(xsize) * dx) * to_km
    y_axis = (y0 + np.arange(ysize) * dy) * to_km

    extent=[x_axis[0], x_axis[-1], y_axis[0], y_axis[-1]]
    im = ax[six].imshow(merged_correction_data, origin='lower', extent=extent,
                        vmin=vmin, vmax=vmax, aspect='equal')
    ax[six].set_title(swath_.swath_id)
    ax[six].set_xlabel('Slant Range [km]')

ax[0].set_ylabel('Azimuth [km]')

name = merged_correction['name']
unit = merged_correction['unit']

fig.suptitle(f'{name.title()} correction')
fig.colorbar(im, ax=ax[:].tolist(), label=f'[{unit}]')
[32]:
<matplotlib.colorbar.Colorbar at 0x7f8323d1ce10>
../_images/notebooks_s1etad-tutorial_69_1.png
[33]:
# get merged swaths
fig, ax = plt.subplots(figsize=[8, 8])
merged_correction = eta_.merge_correction(ECorrectionType.TROPOSPHERIC,
                                          selection=df, meter=True)
merged_correction_data = merged_correction['x']

ysize, xsize = merged_correction_data.shape
x_axis = np.arange(xsize) * dx * to_km
y_axis = np.arange(ysize) * dy * to_km

extent=[x_axis[0], x_axis[-1], y_axis[0], y_axis[-1]]
im = ax.imshow(merged_correction_data, origin='lower', extent=extent,
               vmin=vmin, vmax=vmax, aspect='equal')

ax.set_xlabel('Slant Range [km]')
ax.set_ylabel('Azimuth [km]')

name = merged_correction['name']
unit = merged_correction['unit']

ax.set_title(f'Merged swaths for {name} correction')
fig.colorbar(im, ax=ax, label=f'[{unit}]')
[33]:
<matplotlib.colorbar.Colorbar at 0x7f8326d9f2d0>
../_images/notebooks_s1etad-tutorial_70_1.png

Use case 3 : Retrieving the footprints

[34]:
import cartopy.crs as ccrs
from matplotlib import patches as mpatches
from shapely.geometry import MultiPolygon

def tile_extent(poly, margin=2):
    bb = list(poly.bounds)
    bb [1:3] = bb [2:0:-1]
    bb2 = np.asarray(bb) + [-margin, margin, -margin, margin]
    return bb2

# get the footprints of the selected bursts
polys = eta_.get_footprint(swath_list=['IW1', 'IW2', 'IW3'])

fig = plt.figure(figsize=[10, 8])
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
ax.set_extent(tile_extent(MultiPolygon(polys)))

# Put a background image on for nice sea rendering.
OFFLINE = False
if OFFLINE:
    import cartopy.feature as cfeature
    ax.stock_img()
    ax.add_feature(cfeature.LAND)
    ax.add_feature(cfeature.COASTLINE)
else:
    import cartopy.io.img_tiles as cimgt
    # stamen_terrain = cimgt.Stamen('terrain-background')  # need cartopy >= 0.18
    stamen_terrain = cimgt.StamenTerrain()
    ax.add_image(stamen_terrain, 6)  # up to 10
    ax.coastlines()

# plot footprints of all selected burst
# ax.add_geometries(polys, crs=ccrs.PlateCarree(), alpha=0.8)

# get the footprints of each swath and plot them with different colors
items = []
for swath, color in zip(eta_, ['red', 'green', 'blue']):
    polys = swath.get_footprint()
    item = ax.add_geometries(polys, crs=ccrs.PlateCarree(), alpha=0.5,
                             color=color)
    items.append(item)

handles = [
    mpatches.Patch(color=color, label=label)
    for color, label in zip(['red', 'green', 'blue'], eta_.swath_list)
]
plt.legend(handles=handles)
/Users/valentino/anaconda3/envs/p37/lib/python3.7/site-packages/ipykernel_launcher.py:28: DeprecationWarning: The StamenTerrain class was deprecated in v0.17. Please use Stamen('terrain-background') instead.
[34]:
<matplotlib.legend.Legend at 0x7f830a2faf10>
../_images/notebooks_s1etad-tutorial_72_2.png
[ ]: