Plot and interact

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>
../_images/5365cf96e30dc2368dfc559fcc306d2a70dcdf030b0d984894976a9fb7e99302.png

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>
../_images/837d76004fc66b11803501982b8932af9186934740e56ab7c2351e99e1c5c7d7.png
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>
../_images/837d76004fc66b11803501982b8932af9186934740e56ab7c2351e99e1c5c7d7.png

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