PS Processing

In this tutorial, we demostrate how to do PS processing with the decorrelation CLI interface. The input data for PS processing is prepared in Load Data.

!ls ./load_data
e.zarr    lat.zarr  meta.toml  phi.zarr    rslc_pyramid  scratch
hgt.zarr  lon.zarr  n.zarr     range.zarr  rslc.zarr     theta.zarr

Amplitude dispersion index calculation

Here were calculate the amplitude dispersion index (ADI) which is used to identify persistent scatterers.

import zarr
import numpy as np
from matplotlib import pyplot as plt
import colorcet
import moraine.cli as mc
import moraine as mr
rslc = './load_data/rslc.zarr'
adi = './ps_processing/gix/ras_adi.zarr'
logger = mc.get_logger()
mc.amp_disp(rslc,adi)
2024-07-18 16:01:50 - log_args - INFO - running function: amp_disp
2024-07-18 16:01:50 - log_args - INFO - fetching args:
2024-07-18 16:01:50 - log_args - INFO - rslc = './load_data/rslc.zarr'
2024-07-18 16:01:50 - log_args - INFO - adi = './ps_processing/gix/ras_adi.zarr'
2024-07-18 16:01:50 - log_args - INFO - chunks = None
2024-07-18 16:01:50 - log_args - INFO - out_chunks = None
2024-07-18 16:01:50 - log_args - INFO - cuda = False
2024-07-18 16:01:50 - log_args - INFO - processes = None
2024-07-18 16:01:50 - log_args - INFO - n_workers = None
2024-07-18 16:01:50 - log_args - INFO - threads_per_worker = None
2024-07-18 16:01:50 - log_args - INFO - rmm_pool_size = 0.9
2024-07-18 16:01:50 - log_args - INFO - dask_cluster_arg = {}
2024-07-18 16:01:50 - log_args - INFO - fetching args done.
2024-07-18 16:01:50 - zarr_info - INFO - ./load_data/rslc.zarr zarray shape, chunks, dtype: (2500, 1834, 17), (1000, 1834, 1), complex64
2024-07-18 16:01:50 - amp_disp - INFO - starting dask local cluster.
2024-07-18 16:01:50 - amp_disp - INFO - dask local cluster started.
2024-07-18 16:01:50 - dask_cluster_info - INFO - dask cluster: LocalCluster(dashboard_link='http://10.211.48.7:8787/status', workers=1, threads=2, memory=256.00 GiB)
2024-07-18 16:01:50 - darr_info - INFO - rslc dask array shape, chunksize, dtype: (2500, 1834, 17), (1000, 1834, 17), complex64
2024-07-18 16:01:50 - amp_disp - INFO - calculate amplitude dispersion index.
2024-07-18 16:01:50 - amp_disp - INFO - got amplitude dispersion index.
2024-07-18 16:01:50 - darr_info - INFO - adi dask array shape, chunksize, dtype: (2500, 1834), (1000, 1834), float32
2024-07-18 16:01:50 - amp_disp - INFO - rechunking
2024-07-18 16:01:50 - darr_info - INFO - adi dask array shape, chunksize, dtype: (2500, 1834), (1000, 1834), float32
2024-07-18 16:01:50 - amp_disp - INFO - saving adi.
2024-07-18 16:01:50 - amp_disp - INFO - computing graph setted. doing all the computing.
2024-07-18 16:01:52 - amp_disp - INFO - computing finished. |  1.1s
2024-07-18 16:01:52 - amp_disp - INFO - dask cluster closed.

Then visualize the amplitude dispersion index. Since the data is small, we can visualize it with the API plot module moraine.plot. If you want to reduce the memory consumption, the CLI plot module moraine.cli.plot can be used. But the pyramid should be generated ahead.

adi_data = zarr.open(adi,'r')[:]
adi_plot = mr.ras_plot(adi_data)
import holoviews as hv
hv.extension('bokeh')
from bokeh.models import WheelZoomTool
from holoviews import opts
adi_plot = adi_plot.redim(x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('adi',range=(0,1)))
adi_plot.opts(opts.Image(cmap='viridis',width=600, height=600, colorbar=True,
                          invert_yaxis=True,
                          default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],active_tools=['wheel_zoom']))

Then we can select PS candidates by setting a threshold to the amplitude dispersion index:

ps_can_gix = './ps_processing/gix/ps_can_gix.zarr'
mc.pc_logic_ras(adi, ps_can_gix, 'ras<0.3', chunks=20000)
2024-07-18 16:01:52 - log_args - INFO - running function: pc_logic_ras
2024-07-18 16:01:52 - log_args - INFO - fetching args:
2024-07-18 16:01:52 - log_args - INFO - ras = './ps_processing/gix/ras_adi.zarr'
2024-07-18 16:01:52 - log_args - INFO - gix = './ps_processing/gix/ps_can_gix.zarr'
2024-07-18 16:01:52 - log_args - INFO - operation = 'ras<0.3'
2024-07-18 16:01:52 - log_args - INFO - chunks = 20000
2024-07-18 16:01:52 - log_args - INFO - fetching args done.
2024-07-18 16:01:52 - zarr_info - INFO - ./ps_processing/gix/ras_adi.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float32
2024-07-18 16:01:52 - pc_logic_ras - INFO - loading ras into memory.
2024-07-18 16:01:52 - pc_logic_ras - INFO - select pc based on operation: ras<0.3
2024-07-18 16:01:52 - pc_logic_ras - INFO - number of selected pixels: 43201.
2024-07-18 16:01:52 - zarr_info - INFO - ./ps_processing/gix/ps_can_gix.zarr zarray shape, chunks, dtype: (43201, 2), (20000, 1), int32
2024-07-18 16:01:52 - pc_logic_ras - INFO - writing gix.
2024-07-18 16:01:52 - pc_logic_ras - INFO - write done.

Then we convert the ps candiates to hillbert coordinates:

mc.pc_hix('./ps_processing/gix/ps_can_gix.zarr/', './ps_processing/gix/ps_can_hix.zarr', shape=(2500, 1834))
ps_can_hix = './ps_processing/hix/ps_can_hix.zarr'
mc.pc_sort('./ps_processing/gix/ps_can_hix.zarr', ps_can_hix)
2024-07-18 16:01:52 - log_args - INFO - running function: pc_hix
2024-07-18 16:01:52 - log_args - INFO - fetching args:
2024-07-18 16:01:52 - log_args - INFO - gix = './ps_processing/gix/ps_can_gix.zarr/'
2024-07-18 16:01:52 - log_args - INFO - hix = './ps_processing/gix/ps_can_hix.zarr'
2024-07-18 16:01:52 - log_args - INFO - shape = (2500, 1834)
2024-07-18 16:01:52 - log_args - INFO - fetching args done.
2024-07-18 16:01:52 - zarr_info - INFO - ./ps_processing/gix/ps_can_gix.zarr/ zarray shape, chunks, dtype: (43201, 2), (20000, 1), int32
2024-07-18 16:01:52 - zarr_info - INFO - ./ps_processing/gix/ps_can_hix.zarr zarray shape, chunks, dtype: (43201,), (20000,), int64
2024-07-18 16:01:52 - pc_hix - INFO - calculating the hillbert index based on grid index
2024-07-18 16:01:53 - pc_hix - INFO - writing the hillbert index
2024-07-18 16:01:53 - pc_hix - INFO - done.
2024-07-18 16:01:53 - log_args - INFO - running function: pc_sort
2024-07-18 16:01:53 - log_args - INFO - fetching args:
2024-07-18 16:01:53 - log_args - INFO - idx_in = './ps_processing/gix/ps_can_hix.zarr'
2024-07-18 16:01:53 - log_args - INFO - idx = './ps_processing/hix/ps_can_hix.zarr'
2024-07-18 16:01:53 - log_args - INFO - pc_in = None
2024-07-18 16:01:53 - log_args - INFO - pc = None
2024-07-18 16:01:53 - log_args - INFO - shape = None
2024-07-18 16:01:53 - log_args - INFO - chunks = None
2024-07-18 16:01:53 - log_args - INFO - processes = False
2024-07-18 16:01:53 - log_args - INFO - n_workers = 1
2024-07-18 16:01:53 - log_args - INFO - threads_per_worker = 2
2024-07-18 16:01:53 - log_args - INFO - dask_cluster_arg = {}
2024-07-18 16:01:53 - log_args - INFO - fetching args done.
2024-07-18 16:01:53 - zarr_info - INFO - ./ps_processing/gix/ps_can_hix.zarr zarray shape, chunks, dtype: (43201,), (20000,), int64
2024-07-18 16:01:53 - pc_sort - INFO - loading idx_in and calculate the sorting indices.
2024-07-18 16:01:53 - pc_sort - INFO - output pc chunk size is 20000
2024-07-18 16:01:54 - pc_sort - INFO - write idx
2024-07-18 16:01:54 - zarr_info - INFO - idx zarray shape, chunks, dtype: (43201,), (20000,), int64
2024-07-18 16:01:54 - pc_sort - INFO - no point cloud data provided, exit.
ps_can_rslc = './ps_processing/hix/ps_can_rslc.zarr'
mc.ras2pc(ps_can_hix,
          [rslc,'./load_data/e.zarr','./load_data/n.zarr',
           './load_data/lon.zarr','./load_data/lat.zarr',
           './ps_processing/gix/ras_adi.zarr'],
          [ps_can_rslc, './ps_processing/hix/ps_can_e.zarr','./ps_processing/hix/ps_can_n.zarr',
           './ps_processing/hix/ps_can_lon.zarr', './ps_processing/hix/ps_can_lat.zarr',
           './ps_processing/hix/ps_can_adi.zarr',],
          threads_per_worker=32,
)
2024-07-18 16:01:54 - log_args - INFO - running function: ras2pc
2024-07-18 16:01:54 - log_args - INFO - fetching args:
2024-07-18 16:01:54 - log_args - INFO - idx = './ps_processing/hix/ps_can_hix.zarr'
2024-07-18 16:01:54 - log_args - INFO - ras = ['./load_data/rslc.zarr', './load_data/e.zarr', './load_data/n.zarr', './load_data/lon.zarr', './load_data/lat.zarr', './ps_processing/gix/ras_adi.zarr']
2024-07-18 16:01:54 - log_args - INFO - pc = ['./ps_processing/hix/ps_can_rslc.zarr', './ps_processing/hix/ps_can_e.zarr', './ps_processing/hix/ps_can_n.zarr', './ps_processing/hix/ps_can_lon.zarr', './ps_processing/hix/ps_can_lat.zarr', './ps_processing/hix/ps_can_adi.zarr']
2024-07-18 16:01:54 - log_args - INFO - chunks = None
2024-07-18 16:01:54 - log_args - INFO - processes = False
2024-07-18 16:01:54 - log_args - INFO - n_workers = 1
2024-07-18 16:01:54 - log_args - INFO - threads_per_worker = 32
2024-07-18 16:01:54 - log_args - INFO - dask_cluster_arg = {}
2024-07-18 16:01:54 - log_args - INFO - fetching args done.
2024-07-18 16:01:54 - zarr_info - INFO - ./ps_processing/hix/ps_can_hix.zarr zarray shape, chunks, dtype: (43201,), (20000,), int64
2024-07-18 16:01:54 - ras2pc - INFO - loading hix into memory and convert to gix
2024-07-18 16:01:55 - ras2pc - INFO - starting dask local cluster.
2024-07-18 16:01:55 - ras2pc - INFO - dask local cluster started.
2024-07-18 16:01:55 - dask_cluster_info - INFO - dask cluster: LocalCluster(dashboard_link='http://10.211.48.7:8787/status', workers=1, threads=32, memory=256.00 GiB)
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./load_data/rslc.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./load_data/rslc.zarr zarray shape, chunks, dtype: (2500, 1834, 17), (1000, 1834, 1), complex64
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834, 17), (2500, 1834, 1), complex64
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201, 17), (43201, 1), complex64
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201, 17), (20000, 1), complex64
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_rslc.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./load_data/e.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./load_data/e.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834), (2500, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (43201,), float64
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (20000,), float64
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_e.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./load_data/n.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./load_data/n.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834), (2500, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (43201,), float64
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (20000,), float64
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_n.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./load_data/lon.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./load_data/lon.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834), (2500, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (43201,), float64
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (20000,), float64
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_lon.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./load_data/lat.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./load_data/lat.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834), (2500, 1834), float64
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (43201,), float64
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (20000,), float64
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_lat.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - start to slice on ./ps_processing/gix/ras_adi.zarr
2024-07-18 16:01:55 - zarr_info - INFO - ./ps_processing/gix/ras_adi.zarr zarray shape, chunks, dtype: (2500, 1834), (1000, 1834), float32
2024-07-18 16:01:55 - darr_info - INFO - ras dask array shape, chunksize, dtype: (2500, 1834), (2500, 1834), float32
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (43201,), float32
2024-07-18 16:01:55 - ras2pc - INFO - rechunk pc data:
2024-07-18 16:01:55 - darr_info - INFO - pc dask array shape, chunksize, dtype: (43201,), (20000,), float32
2024-07-18 16:01:55 - ras2pc - INFO - saving to ./ps_processing/hix/ps_can_adi.zarr.
2024-07-18 16:01:55 - ras2pc - INFO - computing graph setted. doing all the computing.
2024-07-18 16:01:55 - ras2pc - INFO - computing finished.ed |  0.4s
2024-07-18 16:01:55 - ras2pc - INFO - dask cluster closed.

The point cloud data is sorted according to the hillbert index so they close points in the list are closed to each other in map.

visualize the PS

mc.pc_pyramid(
    './ps_processing/hix/ps_can_rslc.zarr',
    './ps_processing/hix/ps_can_rslc_pyramid',
    x = './ps_processing/hix/ps_can_e.zarr',
    y = './ps_processing/hix/ps_can_n.zarr/',
    ras_resolution = 20,
    threads_per_worker=17
)
2024-07-18 16:01:56 - log_args - INFO - running function: pc_pyramid
2024-07-18 16:01:56 - log_args - INFO - fetching args:
2024-07-18 16:01:56 - log_args - INFO - pc = './ps_processing/hix/ps_can_rslc.zarr'
2024-07-18 16:01:56 - log_args - INFO - out_dir = './ps_processing/hix/ps_can_rslc_pyramid'
2024-07-18 16:01:56 - log_args - INFO - x = './ps_processing/hix/ps_can_e.zarr'
2024-07-18 16:01:56 - log_args - INFO - y = './ps_processing/hix/ps_can_n.zarr/'
2024-07-18 16:01:56 - log_args - INFO - yx = None
2024-07-18 16:01:56 - log_args - INFO - ras_resolution = 20
2024-07-18 16:01:56 - log_args - INFO - ras_chunks = (256, 256)
2024-07-18 16:01:56 - log_args - INFO - pc_chunks = 65536
2024-07-18 16:01:56 - log_args - INFO - processes = False
2024-07-18 16:01:56 - log_args - INFO - n_workers = 1
2024-07-18 16:01:56 - log_args - INFO - threads_per_worker = 17
2024-07-18 16:01:56 - log_args - INFO - dask_cluster_arg = {}
2024-07-18 16:01:56 - log_args - INFO - fetching args done.
2024-07-18 16:01:56 - zarr_info - INFO - ./ps_processing/hix/ps_can_rslc.zarr zarray shape, chunks, dtype: (43201, 17), (20000, 1), complex64
2024-07-18 16:01:56 - pc_pyramid - INFO - rendering point cloud data coordinates:
2024-07-18 16:01:56 - pc_pyramid - INFO - rasterizing point cloud data to grid with bounds: [-16498455.50940282, 8649634.094942318, -16470215.50940282, 8674894.094942318].
2024-07-18 16:01:57 - pc_pyramid - INFO - dask local cluster started.
2024-07-18 16:01:57 - dask_cluster_info - INFO - dask cluster: LocalCluster(dashboard_link='http://10.211.48.7:8787/status', workers=1, threads=17, memory=256.00 GiB)
2024-07-18 16:01:57 - pc_pyramid - INFO - pc data coordinates rendering ends.
2024-07-18 16:01:57 - pc_pyramid - INFO - pc data rendering ends.
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 0 dask array shape, chunksize, dtype: (1264, 1413, 17), (256, 256, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 0 dask array shape, chunksize, dtype: (1264, 1413), (256, 256), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 1 dask array shape, chunksize, dtype: (632, 707, 17), (256, 256, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 1 dask array shape, chunksize, dtype: (632, 707), (256, 256), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 2 dask array shape, chunksize, dtype: (316, 354, 17), (256, 256, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 2 dask array shape, chunksize, dtype: (316, 354), (256, 256), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 3 dask array shape, chunksize, dtype: (158, 177, 17), (158, 177, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 3 dask array shape, chunksize, dtype: (158, 177), (158, 177), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 4 dask array shape, chunksize, dtype: (79, 89, 17), (79, 89, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 4 dask array shape, chunksize, dtype: (79, 89), (79, 89), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 5 dask array shape, chunksize, dtype: (40, 45, 17), (40, 45, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 5 dask array shape, chunksize, dtype: (40, 45), (40, 45), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 6 dask array shape, chunksize, dtype: (20, 23, 17), (20, 23, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 6 dask array shape, chunksize, dtype: (20, 23), (20, 23), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 7 dask array shape, chunksize, dtype: (10, 12, 17), (10, 12, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 7 dask array shape, chunksize, dtype: (10, 12), (10, 12), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 8 dask array shape, chunksize, dtype: (5, 6, 17), (5, 6, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 8 dask array shape, chunksize, dtype: (5, 6), (5, 6), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 9 dask array shape, chunksize, dtype: (3, 3, 17), (3, 3, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 9 dask array shape, chunksize, dtype: (3, 3), (3, 3), int64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc data at level 10 dask array shape, chunksize, dtype: (2, 2, 17), (2, 2, 1), complex64
2024-07-18 16:01:57 - darr_info - INFO - rasterized pc index at level 10 dask array shape, chunksize, dtype: (2, 2), (2, 2), int64
2024-07-18 16:01:57 - pc_pyramid - INFO - computing graph setted. doing all the computing.
/users/kangl/miniforge3/envs/work/lib/python3.10/site-packages/distributed/client.py:3162: UserWarning: Sending large graph of size 14.84 MiB.
This may cause some slowdown.
Consider scattering data ahead of time and using futures.
  warnings.warn(
2024-07-18 16:02:02 - pc_pyramid - INFO - computing finished.  4.8s
2024-07-18 16:02:02 - pc_pyramid - INFO - dask cluster closed.
intf_plot = mc.pc_plot('./ps_processing/hix/ps_can_rslc_pyramid/',post_proc_ras='intf_all', post_proc_pc='intf_all',level_increase=1)
import holoviews as hv
from bokeh.models import WheelZoomTool
hv.extension('bokeh')
import toml
with open('load_data/meta.toml','r') as f:
    dates = toml.load(f)['dates']
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('lon', label='Longitude'), y=hv.Dimension('lat',label='Latitude'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))
hv.output(widget_location='bottom')
hv.element.tiles.EsriImagery()*intf_plot.opts(
    hv.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']
    ),
    hv.opts.Points(
        color='Phase', cmap='colorwheel',width=600, height=400, colorbar=True,
        default_tools=['pan',WheelZoomTool(zoom_on_axis=False),'save','reset','hover'],
        active_tools=['wheel_zoom']
    ),
)