plot

Accurate and interative big data visualization
Note

Note that the plotting functions here make use of dynamic updates, which require a running Jupyter server. When viewed statically (as this documentation website), the plots will not update fully when you zoom.

import holoviews as hv
import numpy as np
import zarr
from holoviews import opts
from bokeh.models import WheelZoomTool
hv.extension('bokeh')

source

ras_plot

 ras_plot (data:str, post_proc:Callable=None, n_kdim:int=None,
           bounds:tuple=None, level_increase=0)

plot rendered stack of ras tiles.

Type Default Details
data str directory to the rendered ras pyramid
post_proc Callable None function for the post processing, can be None, ‘intf_0’, ‘intf_seq’, ‘intf_all’ or user-defined function
n_kdim int None number of key dimensions, can only be 0 or 1 or 2, ndim of raster dataset -2 by default
bounds tuple None bounding box (x0, y0, x_max, y_max)
level_increase int 0 amount of zoom level increase for more clear point show and faster responds time

Usage:

rslc_ = '../../data/rslc.zarr/'
rslc = zarr.open(rslc_,'r')[:]
intf_plot = ras_plot(np.angle(rslc[...,2]*rslc[...,0].conj()))
intf_plot = intf_plot.redim(x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))
intf_plot.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True,
                          invert_yaxis=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],active_tools=['wheel_zoom']))

ras_plot can also take stack of raster images. It will return DynamicMap with keys. Here we define a function to generate interferograms with the first SLC as reference:

def intf_0(data, xslice, yslice,i):
    return np.angle(data[yslice,xslice,0]*data[yslice,xslice,i].conj())
intf_plot = ras_plot(rslc,post_proc=intf_0, level_increase=0)

We have a set of convenient predefined post_proc functions, e.g., intf_0, intf_seq, intf_all. The above code equals to:

intf_plot = ras_plot(rslc,post_proc='intf_0', level_increase=0)

Add annotations:

dates = ["20210802", "20210816", "20210830", "20210913", "20211011", "20211025", "20220606", "20220620",
         "20220704", "20220718", "20220801", "20220815", "20220829", "20220912", "20220926", "20221010",
         "20221024",]
intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Interferogram', range=(0,16), value_format=(lambda i: dates[0]+'_'+dates[i])),
                            x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))

Specify plotting options and plot:

hv.output(widget_location='bottom')
intf_plot.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True,
                          invert_yaxis=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],active_tools=['wheel_zoom']))

Or the intensity:

def intensity(data, xslice, yslice,i):
    return np.log(np.abs(data[yslice,xslice,i])**2)

int_plot = ras_plot(rslc,post_proc=intensity)
int_plot = int_plot.redim(i=hv.Dimension('i', label='Intensity', range=(1,16), value_format=(lambda i: dates[i])),
                          x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Intensity'))
int_plot.opts(opts.Image(cmap='gray',width=600, height=600, colorbar=True,
                         invert_yaxis=True, default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                         active_tools=['wheel_zoom']))

We can also plot sequential interferograms. In this case, we only plot 26 interferograms.

def intf_seq(data, xslice, yslice,i):
    return np.angle(data[yslice,xslice,i]*data[yslice,xslice,i+1].conj())
intf_plot = ras_plot(rslc,post_proc=intf_seq)
# or
intf_plot = ras_plot(rslc,post_proc='intf_seq')

intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Interferogram', range=(0,15), value_format=(lambda i: dates[i]+'_'+dates[i+1])),
                            x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))
intf_plot.opts(opts.Image(cmap='colorwheel',width=600, height=600, colorbar=True,
                          invert_yaxis=True, default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                          active_tools=['wheel_zoom']))

The n_kdim don’t have to be data.ndim-2. Here is an example to show all interferograms.

def intf_all(data, xslice, yslice,i,j): # we have 2 kdims here
    return np.angle(data[yslice,xslice,i]*data[yslice,xslice,j].conj())
intf_plot = ras_plot(rslc,post_proc=intf_all,n_kdim=2,level_increase=0)
# or
intf_plot = ras_plot(rslc,post_proc='intf_all',n_kdim=2,level_increase=0)

Add annotations:

intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Reference Image', range=(0,16), value_format=(lambda i: dates[i])),
                            j=hv.Dimension('j', label='Secondary Image', range=(0,16), value_format=(lambda i: dates[i])),
                            x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))

Specify plotting options and plot:

hv.output(widget_location='bottom')
intf_plot.opts(opts.Image(cmap='colorwheel',frame_width=500, frame_height=600, colorbar=True,
                          invert_yaxis=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],active_tools=['wheel_zoom']))

source

pc_plot

 pc_plot (data:numpy.ndarray, y:numpy.ndarray, x:numpy.ndarray,
          ras_resolution:float=20, post_proc_pc:Callable=None,
          n_kdim:int=None, rtree=None, level_increase=0)

plot rendered point cloud pyramid on the fly

Type Default Details
data ndarray pc dataset
y ndarray y coordinate
x ndarray x coordinate
ras_resolution float 20 minimum resolution of rendered raster data in the pyramid
post_proc_pc Callable None function for the post processing
n_kdim int None number of key dimensions, can only be 0 or 1 or 2, ndim of point cloud dataset -1 by default
rtree NoneType None rtree, if not provide, will be automatically generated but may slow the program
level_increase int 0 amount of zoom level increase for more clear point show and faster responds time

pc_plot take the rendered point cloud dataset as the input and return a Holoviews DynamicMap. When the zoom level is -1, it plot the the raw point cloud data. When the zoom level is 0 or over 0, it plot the rasterized images. Just as ras_plot, it accept post processing functions for both point cloud data and raster data to be plot. It is the user’s duty to esure the post processing fuctions coincide with each other. It also accept n_kdim to set number of kdims for returned DynamicMap.

Here is an example to plot the amplitude dispersion index:

ps_can_adi = zarr.open('../CLI/ps/ps_can_adi.zarr/','r')[:]
ps_can_rslc = zarr.open('../CLI/ps/ps_can_rslc.zarr/','r')[:]
ps_can_x = zarr.open('../CLI/ps/ps_can_e.zarr/','r')[:]
ps_can_y = zarr.open('../CLI/ps/ps_can_n.zarr/','r')[:]
adi_plot = pc_plot(ps_can_adi,ps_can_y,ps_can_x,level_increase=1)

Add annotations:

adi_plot = adi_plot.redim(x=hv.Dimension('lon', label='Longitude'), y=hv.Dimension('lat',label='Latitude'),
                          z=hv.Dimension('adi',label='Amplitude Dispersion Index',range=(0,0.3))
                         )

Specify plotting options and plot:

adi_plot.opts(opts.Image(cmap='fire',width=600, height=400, colorbar=True,
                         # invert_yaxis=True, 
                         default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                         active_tools=['wheel_zoom']
                        ),
              opts.Points(color='adi', cmap='fire',width=600, height=400, colorbar=True,
                         # invert_yaxis=True, 
                         default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                         active_tools=['wheel_zoom']
                        )
             )

Add the optical image as the background:

hv.element.tiles.EsriImagery()*adi_plot

Note that, for displaying data over tiles, the data have to be projected to the Web Mercator Projection.

As ras_plot, pc_plot can also take stack of point cloud dataset. It will return DynamicMap with keys. Here we define a function to generate interferograms with the first SLC as reference:

def intf_0_pc(data,idx_array,i):
    return np.angle(data[idx_array,0]*data[idx_array,i].conj())
intf_plot = pc_plot(ps_can_rslc, ps_can_y, ps_can_x, post_proc_pc=intf_0_pc, level_increase=1)
# or
intf_plot = pc_plot(ps_can_rslc, ps_can_y, ps_can_x, post_proc_pc='intf_0', level_increase=1)

Add annotations:

dates = ["20210802", "20210816", "20210830", "20210913", "20211011", "20211025", "20220606", "20220620",
         "20220704", "20220718", "20220801", "20220815", "20220829", "20220912", "20220926", "20221010",
         "20221024",]
intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Interferogram', range=(0,16), value_format=(lambda i: dates[0]+'_'+dates[i])),
                            x=hv.Dimension('lon', label='Longitude'), y=hv.Dimension('lat',label='Latitude'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))

Specify plotting options and plot:

hv.output(widget_location='bottom')
intf_plot.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                          active_tools=['wheel_zoom']
                         ),
              opts.Points(color='Phase', cmap='colorwheel',width=600, height=400, colorbar=True,
                         # invert_yaxis=True, 
                         default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                         active_tools=['wheel_zoom']
                        )
              )

The n_kdim don’t have to be data.ndim-1. Here is an example to show all interferograms.

def intf_pc(data, idx,i,j): # we have 2 kdims here
    return np.angle(data[idx,i]*data[idx,j].conj())
intf_plot = pc_plot(ps_can_rslc, ps_can_y, ps_can_x, post_proc_pc=intf_pc,n_kdim=2,level_increase=0)
# or
intf_plot = pc_plot(ps_can_rslc, ps_can_y, ps_can_x, post_proc_pc='intf_all',n_kdim=2,level_increase=0)

Add annotations:

intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Reference Image', range=(0,16), value_format=(lambda i: dates[i])),
                            j=hv.Dimension('j', label='Secondary Image', range=(0,16), value_format=(lambda i: dates[i])),
                            x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))

Specify plotting options and plot:

hv.output(widget_location='bottom')
intf_plot.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                          active_tools=['wheel_zoom']
                         ),
              opts.Points(color='Phase', cmap='colorwheel',width=600, height=400, colorbar=True,
                         # invert_yaxis=True, 
                         default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
                         active_tools=['wheel_zoom']
                        )
              )