import xsar
import glob
safe_list = glob.glob("/home/oarcher/SAFE/S1A*.SAFE")
print('about to get product information on %d SAFEs' % len(safe_list))
about to get product information on 44 SAFEs
df = xsar.product_info(safe_list)
df
ipf | platform | swath | product | pols | multi | meta | |
---|---|---|---|---|---|---|---|
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001313_20201123T001338_035368_0421EE_BF23.SAFE:IW | 3.31 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001108_20201123T001133_035368_0421EE_2218.SAFE:IW | 3.31 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001248_20201123T001313_035368_0421EE_A1E3.SAFE:IW | 3.31 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20170907T102951_20170907T103020_018268_01EB76_44BE.SAFE:IW | 2.84 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20200406T071419_20200406T071444_032003_03B25D_FFFF.SAFE:IW | 3.2 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
... | ... | ... | ... | ... | ... | ... | ... |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_EW_GRDM_1SDV_20201029T205631_20201029T205735_035016_0415BC_00C3.SAFE:EW | 3.31 | SENTINEL-1A | EW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001133_20201123T001158_035368_0421EE_707B.SAFE:IW | 3.31 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T000928_20201123T000953_035368_0421EE_3F2B.SAFE:IW | 3.31 | SENTINEL-1A | IW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_EW_GRDM_1SDV_20200316T020222_20200316T020322_031694_03A788_FFFF.SAFE:EW | 3.2 | SENTINEL-1A | EW | GRD | VV VH | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_EW_GRDM_1SDV_20191105T195834_20191105T195916_029780_03651B_4A35.SAFE:EW | 3.1 | SENTINEL-1A | EW | GRD | VV VH | False | single SentinelMeta object |
71 rows × 7 columns
Each line represent metadata information for all datasets founds in safe_list.
There are more dataset than paths, because some SAFEs can have multiple subdatasets (like WV or IW_SLC)
xsar.product_info
returns all datasets, including nested one and multi ones
the 'multi' columns allows to see witch safe are multi datasets
df[df['multi']]
ipf | platform | swath | product | pols | multi | meta | |
---|---|---|---|---|---|---|---|
SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_SLC__1SDV_20170907T102951_20170907T103021_018268_01EB76_AE7B.SAFE: | 2.84 | SENTINEL-1A | IW | SLC | VV VH | True | multi (3) SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE: | 2.7 | SENTINEL-1A | WV | SLC | VV | True | multi (24) SentinelMeta object |
a multi dataset cannot be directly opened as an xarray dataset with xsar.open_dataset. The user must provide a single dataset to xsar.open_dataset
Here are the openable WV datasets:
df[(df['swath'] == 'WV') & ~df['multi'] ]
ipf | platform | swath | product | pols | multi | meta | |
---|---|---|---|---|---|---|---|
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_001 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_010 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_011 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_012 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_013 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_014 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_015 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_016 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_017 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_018 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_019 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_002 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_020 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_021 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_022 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_023 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_024 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_003 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_004 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_005 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_006 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_007 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_008 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
SENTINEL1_DS:/home/oarcher/SAFE/S1A_WV_SLC__1SSV_20160510T101603_20160510T102143_011195_010EA1_7038.SAFE:WV_009 | 2.7 | SENTINEL-1A | WV | SLC | VV | False | single SentinelMeta object |
There are 3 ways to open a dataset with xsar.open_dataset
:
# those commands are equivatents:
ds1 = xsar.open_dataset('/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001313_20201123T001338_035368_0421EE_BF23.SAFE')
ds2 = xsar.open_dataset('SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001313_20201123T001338_035368_0421EE_BF23.SAFE:IW')
meta = df.loc['SENTINEL1_DS:/home/oarcher/SAFE/S1A_IW_GRDH_1SDV_20201123T001313_20201123T001338_035368_0421EE_BF23.SAFE:IW']['meta']
ds3 = xsar.open_dataset(meta)
with 'columns="spatial"' keyword, the dataframe has also 'time_range' and 'footprint' columns
df = xsar.product_info(safe_list,columns='spatial')
import geopandas as gpd
import matplotlib.pyplot as plt
fig,ax = fig, ax = plt.subplots(figsize=(20,20))
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
world_map = world.plot(color='white', edgecolor='black',ax=ax)
df.footprint.plot(ax=world_map)
<AxesSubplot:>
Dataset attributes are stored in ds1.attrs
, but those attributes must respect the CF convention to be properly dumped to disk.
So those attributes are numbers or strings, and are not easyly handable by the python programmer
# this is a string
ds3.attrs['footprint']
'POLYGON ((86.68592421893726 21.88782026084792, 84.26341868599728 22.31126646161592, 83.97503900505524 20.80381451549505, 86.37079841612797 20.37730344779156, 86.68592421893726 21.88782026084792))'
# and this is a shapely polygon
meta.footprint
meta has also some usefull methods
help(meta.ll2coords)
Help on method ll2coords in module xsar.sentinel1.Sentinel1: ll2coords(lon, lat) method of xsar.sentinel1.Sentinel1.SentinelMeta instance Get `(atracks, xtracks)` from `(lon, lat)` Parameters ---------- lon: np.array lat: np.array `lat` and `lon` must have the same shape. Returns ------- tuple of np.array (atracks, xtracks) Examples: _________ get nearest (atrack,xtrack) from (lon,lat) = (84.81, 21.32) in ds, with out of bounds check. ``` >>> (atrack, xtrack) = meta.ll2coords(lon, lat) >>> (atrack, xtrack) (9752.766349989339, 17852.571322887554) >>> try: ... # select the nearest valid pixel in ds ... ds_nearest = ds.sel(atrack=atrack,xtrack=xtrack,method='nearest',tolerance=1) ... (atrack, xtrack) = (ds_nearest.atrack.values.item() , ds_nearest.xtrack.values.item()) ... except KeyError: ... # out of bounds, because of `tolerance` keyword ... # if ds is resampled, tolerance should be computed from resolution/2 (for ex 5 for a resolution of 10) ... (atrack, xtrack) = (np.nan, np.nan) ``` Notes: ------ `atracks` and `xtracks` are float, with no out of bounds checks See Also: --------- self.coords2ll
# find (atrack,xtrack) from (lon,lat)
lon = 84.81
lat = 21.31
(atrack, xtrack) = meta.ll2coords(lon, lat)
(atrack, xtrack)
(9752.766349989339, 17852.571322887554)
# (atrack,xtrack) are float, so we are able to know the exact position, even at subpixel level
# to convert them to existing index, we can use .sel with 'nearest' method:
try:
ds_nearest = ds1.sel(atrack=atrack,xtrack=xtrack,method='nearest',tolerance=0.5)
(atrack, xtrack) = (ds_nearest.atrack.values.item() , ds_nearest.xtrack.values.item())
except:
# out of bounds
(atrack, xtrack) = (np.nan, np.nan)
(atrack, xtrack)
(9752.5, 17852.5)