import os, copy
import glob
import numpy as np
import pandas as pd
import xarray as xr
import datetime as dt
#import netCDF4
#import h5py
import cartopy.crs as ccrs
import matplotlib as mpl
import matplotlib.pyplot as plt
#import colorcet as cc
#import panel as pn
#pn.extension()
opj = os.path.join
file='/data/satellite/enmap/L2A/Trasimeno/ENMAP01-____L1C-DT0000088121_20240817T102235Z_002_V010502_20250128T220420Z.nc'
file='/data/satellite/enmap/L2A/Trasimeno/ENMAP01-____L1C-DT0000082532_20240706T103357Z_002_V010502_20250128T220612Z.nc' #8121_20240817T102235Z_002_V010502_20250128T220420Z.nc'
img =xr.open_dataset(file)
img.load()
l2_prod = img
l2_prod
<xarray.Dataset> Size: 1GB
Dimensions: (wl: 92, y: 1221, x: 1295, yc: 62, xc: 65)
Coordinates:
* x (x) float64 10kB 2.47e+05 2.47e+05 ... 2.858e+05 2.858e+05
spatial_ref int64 8B 0
time datetime64[ns] 8B 2024-07-06T10:33:53.032721
* y (y) float64 10kB 4.796e+06 4.796e+06 ... 4.76e+06 4.76e+06
* wl (wl) float64 736B 418.4 424.0 ... 1.093e+03 1.105e+03
* xc (xc) float64 520B 2.473e+05 2.479e+05 ... 2.856e+05
* yc (yc) float64 496B 4.796e+06 4.795e+06 ... 4.76e+06
Data variables: (12/13)
Rrs (wl, y, x) float64 1GB nan nan nan nan ... nan nan nan nan
brdfg_full (y, x) float64 13MB nan nan nan nan ... nan nan nan nan
tcwv (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
tcwv_std (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
aot_ref (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
brdfg (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
... ...
brdfg_std (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
aot_ref_smoothed (yc, xc) float64 32kB nan nan nan nan ... nan nan nan nan
water_pix_prop (yc, xc) float64 32kB 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
pressure float64 8B 972.4
to3c float64 8B 0.006824
tno2c float64 8B 3.605e-06
Attributes: (12/41)
description: PRISMA L2A-hGRS cube data
L1C_product_name: ENMAP01-____L1C-DT0000082532_20240706T10...
acquisition_date: 2024-07-06 10:33:53.032721
vnir_index: [ 0 1 2 3 4 5 6 7 8 9...
swir_index: [ 79 81 84 86 88 90 93 95 97 99...
vnir_index_tokeep: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 ...
... ...
to3c: 0.006824255455285311
tno2c: 3.6045623801328475e-06
tch4c: 0.0098807318136096
psl: 1013
coef_abs_scat: 1.0
altitude: 0# get geographic information
str_epsg = str(l2_prod.rio.crs)
zone = str_epsg[-2:]
is_south = str_epsg[2] == 7
proj = ccrs.UTM(zone, is_south)
ncols=2
nrows=2
fig,axs = plt.subplots(nrows,ncols,figsize=(ncols*5.,5*nrows),subplot_kw={'projection': proj})
fig.subplots_adjust(bottom=0.08, top=0.9, left=0.086, right=0.98,
hspace=0.05, wspace=0.07,)
if (ncols == 1) & (nrows == 1):
axs = np.array([axs])
axs=axs.ravel()
[axi.set_axis_off() for axi in axs]
ax=axs[0]
l2_prod.Rrs.sel(wl=[665,560,470],method='nearest').plot.imshow(rgb='wl',robust=True,ax=ax)
ax=axs[1]
l2_prod.brdfg_full.plot.imshow(vmin=0,cmap=plt.cm.Grays_r,robust=True,cbar_kwargs={'shrink':0.45},ax=ax)
ax=axs[2]
l2_prod.aot_ref.plot.imshow(cmap=plt.cm.Spectral_r,cbar_kwargs={'shrink':0.45},robust=True,ax=ax)
ax=axs[3]
l2_prod.aot_ref_smoothed.plot.imshow(cmap=plt.cm.Spectral_r,cbar_kwargs={'shrink':0.45},robust=True,ax=ax)
<matplotlib.image.AxesImage at 0x7cb56700fe30>
Plot and interact#
import panel as pn
#hv.extension('bokeh')
pn.extension()
from grstbx import visual
v=visual.ViewSpectral(l2_prod.Rrs.isel(wl=range(0,63,5)) ,reproject=True)
print(v)
v.minmax=[0,0.1]
v.minmaxvalues=(0,0.04)
<grstbx.visual.ViewSpectral object at 0x7cb560c79cd0>
v.visu()
import geopandas as gpd
crs = img.rio.crs
poi_stream = v.poi_stream
geom = poi_stream.data
geom=gpd.points_from_xy(geom['x'],geom['y'])#,crs="EPSG3857")index=[0], c
geom =gpd.GeoDataFrame(crs=3857, geometry=geom).to_crs(crs)
Ndata = len(geom)
cmap = mpl.colors.LinearSegmentedColormap.from_list("",
['navy', "blue", 'lightskyblue',
"grey", 'forestgreen','yellowgreen',
"khaki", "gold",
'orangered', "firebrick", 'purple'])
norm = mpl.colors.Normalize(vmin=0.0,vmax=Ndata-1)
wl_range=slice(400,900)
alpha=0.5
lw=1.2
ms=1.5
fig,axs = plt.subplots(1,2,figsize=(15,5))#,sharey=True)
fig.subplots_adjust(hspace=0.05, wspace=0.25)
ax=axs[0]
indexes=np.dstack([geom.geometry.x,geom.geometry.y])[0]
for ii,index in enumerate(indexes):
color=cmap(norm(ii))
boa=l2_prod.Rrs.sel(x=index[0],y=index[1],method='nearest') +0.0025
boa.sel(wl=wl_range).plot(label='pnt-'+str(ii),marker='o',ms=ms,lw=lw,c=color,alpha=alpha,ax=ax)
boa.rolling(wl=3).mean().sel(wl=wl_range).plot(label='pnt-'+str(ii),marker='o',ms=ms,lw=lw,alpha=alpha,c=color,ax=axs[1])
if False:
toa=l1c_prod.Rtoa.sel(x=index[0],y=index[1],method='nearest')
toa.plot(ms=ms,lw=lw,c=color,alpha=alpha,ax=ax)
for ax in axs:
ax.set_ylabel(r'$R_{rs}\ (sr^{-1})\ or\ R_{TOA}\ (-)$')
ax.axhline(0,color='k')
ax.set_xlabel(r'$Wavelength\ (nm)$')
ax.set_title('')
ax.minorticks_on()
#prod.Twv_raster.mean(['x','y']).plot(marker='o',ms=2.5,lw=0.5)
axs[0].legend(fontsize=10)
/tmp/ipykernel_104314/3862006790.py:44: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
axs[0].legend(fontsize=10)
<matplotlib.legend.Legend at 0x7cb554549100>
import geopandas as gpd
crs = img.rio.crs
poi_stream = v.poi_stream
geom = poi_stream.data
geom=gpd.points_from_xy(geom['x'],geom['y'])#,crs="EPSG3857")index=[0], c
geom =gpd.GeoDataFrame(crs=3857, geometry=geom).to_crs(crs)
Ndata = len(geom)
cmap = mpl.colors.LinearSegmentedColormap.from_list("",
['navy', "blue", 'lightskyblue',
"grey", 'forestgreen','yellowgreen',
"khaki", "gold",
'orangered', "firebrick", 'purple'])
norm = mpl.colors.Normalize(vmin=0.0,vmax=Ndata-1)
wl_range=slice(400,1100)
alpha=0.5
lw=1.2
ms=1.5
fig,axs = plt.subplots(1,2,figsize=(15,5))#,sharey=True)
fig.subplots_adjust(hspace=0.05, wspace=0.25)
ax=axs[0]
indexes=np.dstack([geom.geometry.x,geom.geometry.y])[0]
for ii,index in enumerate(indexes):
color=cmap(norm(ii))
boa=l2_prod.Rrs.sel(x=index[0],y=index[1],method='nearest')
boa.plot(label='pnt-'+str(ii),marker='o',ms=ms,lw=lw,c=color,alpha=alpha,ax=ax)
boa.sel(wl=wl_range).plot(label='pnt-'+str(ii),marker='o',ms=ms,lw=lw,alpha=alpha,c=color,ax=axs[1])
if False:
toa=l1c_prod.Rtoa.sel(x=index[0],y=index[1],method='nearest')
toa.plot(ms=ms,lw=lw,c=color,alpha=alpha,ax=ax)
#toa.sel(wl=wl_range).plot(ms=ms,lw=lw,c=color,alpha=alpha,ax=axs[1])
#(0.04*prod.Tg_other).plot(marker='o',ms=2.5,lw=0.5,ax=axs[0])
#(0.04*prod.Tg_other).sel(wl=wl_range).plot(marker='o',color='k',ms=2.5,lw=0.5,ax=axs[1])
#(0.04*Twv).plot(marker='o',ms=2.5,lw=0.5,ax=axs[0])
#(0.04*Twv).sel(wl=wl_range).plot(marker='o',color='b',ms=2.5,lw=0.5,ax=axs[1])
for ax in axs:
ax.set_ylabel(r'$R_{rs}\ (sr^{-1})\ or\ R_{TOA}\ (-)$')
ax.axhline(0,color='k')
ax.set_xlabel(r'$Wavelength\ (nm)$')
ax.set_title('')
ax.minorticks_on()
#prod.Twv_raster.mean(['x','y']).plot(marker='o',ms=2.5,lw=0.5)
axs[0].legend(fontsize=10)
/tmp/ipykernel_104314/2529270420.py:53: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
axs[0].legend(fontsize=10)
<matplotlib.legend.Legend at 0x7cb4f2194200>
Holoviews tools#
from holoviews import streams
import holoviews as hv
import panel as pn
import param
hv.extension('bokeh')
from holoviews import opts
opts.defaults(
opts.GridSpace(shared_xaxis=True, shared_yaxis=True),
opts.Image(cmap='binary_r', width=800, height=700),
opts.Labels(text_color='white', text_font_size='8pt', text_align='left', text_baseline='bottom'),
opts.Path(color='white'),
opts.Spread(width=900),
opts.Overlay(show_legend=True))
# set the parameter for spectra extraction
hv.extension('bokeh')
pn.extension()
param = 'Rrs' #Rtoa'
#img = prod[['Rtoa','Ltoa']]
raster = img[param]#L2grs #masked[param]
#param = 'rho'
#raster = dc_l2c[param]
cmap='Spectral_r'
#cmap='RdBu_r'
third_dim = 'wl'
wl= raster.wl.data
Nwl = len(wl)
ds = hv.Dataset(raster.persist())
im= ds.to(hv.Image, ['x', 'y'], dynamic=True).opts(cmap= cmap,colorbar=True,clim=(0,0.041)).hist(bin_range=(0,0.01))
polys = hv.Polygons([])
box_stream = hv.streams.BoxEdit(source=polys)
dmap, dmap_std=[],[]
def roi_curves(data,ds=ds):
if not data or not any(len(d) for d in data.values()):
return hv.NdOverlay({0: hv.Curve([],'Wavelength (nm)', param)})
curves,envelope = {},{}
data = zip(data['x0'], data['x1'], data['y0'], data['y1'])
for i, (x0, x1, y0, y1) in enumerate(data):
selection = ds.select(x=(x0, x1), y=(y0, y1))
mean = selection.aggregate(third_dim, np.mean).data
std = selection.aggregate(third_dim, np.std).data
wl = mean.wl
curves[i]= hv.Curve((wl,mean[param]),'Wavelength (nm)', param)
return hv.NdOverlay(curves)
# a bit dirty to have two similar function, but holoviews does not like mixing Curve and Spread for the same stream
def roi_spreads(data,ds=ds):
if not data or not any(len(d) for d in data.values()):
return hv.NdOverlay({0: hv.Curve([],'Wavelength (nm)', param)})
curves,envelope = {},{}
data = zip(data['x0'], data['x1'], data['y0'], data['y1'])
for i, (x0, x1, y0, y1) in enumerate(data):
selection = ds.select(x=(x0, x1), y=(y0, y1))
mean = selection.aggregate(third_dim, np.mean).data
std = selection.aggregate(third_dim, np.std).data
wl = mean.wl
curves[i]= hv.Spread((wl,mean[param],std[param]))#.opts(fill_alpha=0.3)
return hv.NdOverlay(curves)
mean=hv.DynamicMap(roi_curves,streams=[box_stream])
std =hv.DynamicMap(roi_spreads, streams=[box_stream])
hlines = hv.HoloMap({wl[i]: hv.VLine(wl[i]) for i in range(Nwl)},third_dim )
hv.output(widget_location='top_left')
# visualize and play
graphs = ((mean* std *hlines).relabel(param))
layout = (im * polys +graphs ).opts(
opts.Curve(width=750,height=500, framewise=True,xlim=(400,1100)),
opts.Polygons(fill_alpha=0.2, color='green',line_color='black'),
opts.VLine(color='black')).cols(2)
layout