plot

Accurate and interative big data visualization
from matplotlib import pyplot as plt
import colorcet
import toml

Visualization of big data is hard.

For big raster image, ploting every pixels consumes too much time and memory and common picture format (e.g. png) do not support too big image. One common solution is to resample to a smaller image and plot it, which is the default option for common plot package (e.g. matplotlib). But it will reduce the resolution and prevent showing local features.

For big point cloud image, besides the time and memory consumming, the overlapping of rendered points is also a problem.

Here we provide the plot functions based on Holoviews and Datashader fix the problems. The point cloud is resampled to a small raster image and then plotted on the screen. The pixel size of the raster image is exactly matching the resolution of the screen to maximize the accuracy. The plot is interative and the resampling is dynamic, which means when you zoom in, a more precise raster image is automatically generated and plotted.

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 datashader as ds
import spatialpandas
import zarr
import numpy as np
from holoviews import opts
from bokeh.models import WheelZoomTool
hv.extension('bokeh')

source

ras_plot

 ras_plot (data:numpy.ndarray, bounds:tuple=None, level_increase=0)

plot in memory ras data.

Type Default Details
data ndarray 2D numpy array to be visualized
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
rslc_ = '../Tutorials/CLI/load_data/rslc.zarr/'
rslc = zarr.open(rslc_,'r')[...,0:3]
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']))

source

ras_stack_plot

 ras_stack_plot (data:str, bounds:tuple=None, level_increase=0)

plot rendered stack of ras tiles.

Type Default Details
data str 3D numpy array, (nlines, width, nimages)
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
rslc_ = '../Tutorials/CLI/load_data/rslc.zarr/'
rslc = zarr.open(rslc_,'r')[:]
dates_str = toml.load('../Tutorials/CLI/load_data/meta.toml')['dates']
intf_plot = ras_stack_plot(np.angle(rslc*rslc[...,[0]].conj()))
intf_plot = intf_plot.redim(i=hv.Dimension('i', label='Interferogram', range=(0,16), value_format=(lambda i: dates_str[i]+'_'+dates_str[0])),
                            x=hv.Dimension('r', label='Range'), y=hv.Dimension('az',label='Azimuth'), z=hv.Dimension('Phase',range=(-np.pi,np.pi)))
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']))

source

points

 points (data:pandas.core.frame.DataFrame, kdims:list, pdim:str,
         prange:tuple=None, aggregator=<class
         'datashader.reductions.first'>, use_hover:bool=True,
         vdims:list=None, google_earth:bool=False)

Interative visulization of a point cloud image.

Type Default Details
data DataFrame dataset to be plot
kdims list colomn name of Mercator coordinate in dataframe
pdim str column name of data to be plotted in dataframe
prange tuple None range of data to be plotted, it is interactively adjusted by default
aggregator type first aggregator for data rasterization
use_hover bool True use hover to show data
vdims list None column name of data showed on hover except kdims and pdim. These two are always showed.
google_earth bool False if use google earth imagery as the background

Here we plot interferogram after DS processing:

ds_ph_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_ph.zarr/'
ds_e_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_e.zarr/'
ds_n_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_n.zarr/'
ds_ph = zarr.open(ds_ph_,'r')[:]
ds_e = zarr.open(ds_e_,'r')[:]
ds_n = zarr.open(ds_n_,'r')[:]
# data = pd.DataFrame({'e':ds_e,'n':ds_n,'phase':np.angle(ds_ph[:,10]),'lon':ds_lon,'lat':ds_lat})
coordinates = spatialpandas.geometry.PointArray((ds_e, ds_n))
data = spatialpandas.GeoDataFrame({'geometry':coordinates,'phase':np.angle(ds_ph[:,10])})
plot = points(data,kdims=['e','n'],pdim='phase',prange=(-np.pi,np.pi),google_earth=True)

Make some options on the plot:

plot.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True, xlabel='Longitude', ylabel='Latitude'),
          opts.Points(marker='o',size=10,tools=['hover']))

source

points_stack

 points_stack (data:pandas.core.frame.DataFrame, kdims:list,
               pdata:pandas.core.frame.DataFrame, pdim:str,
               prange:tuple=None, aggregator=<class
               'datashader.reductions.first'>, use_hover:bool=True,
               vdims:list=None, google_earth:bool=False)

Interative visulization of a stack of point cloud images.

Type Default Details
data DataFrame common data in all plots
kdims list colomn name of Mercator coordinate in dataframe
pdata DataFrame data to be plotted as color
pdim str label of pdata
prange tuple None range of pdata, it is interactively adjusted by default
aggregator type first aggregator for data rasterization
use_hover bool True use hover to show other column
vdims list None column name of data showed on hover except kdims which are always showed.
google_earth bool False if use google earth imagery as the background
ds_ph_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_ph.zarr/'
ds_e_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_e.zarr/'
ds_n_ = '../Tutorials/CLI/ds_processing/hix/ds/ds_n.zarr/'
ds_ph = zarr.open(ds_ph_,'r')[:]
ds_e = zarr.open(ds_e_,'r')[:]
ds_n = zarr.open(ds_n_,'r')[:]

meta_file = '../CLI/raw/meta.toml'
with open(meta_file,'r') as f:
    meta_data = toml.load(f)
dates = meta_data['dates']
# data = pd.DataFrame({'e':ds_e,'n':ds_n,'lon':ds_lon,'lat':ds_lat,'idx':np.arange(len(ds_e))})
coordinates = spatialpandas.geometry.PointArray((ds_e, ds_n))
data = spatialpandas.GeoDataFrame({'geometry':coordinates,'idx':np.arange(len(ds_e))})
pdata = pd.DataFrame(np.angle(ds_ph),columns=dates)
plot_stack = points_stack(data,['e','n'],pdata,'phase',prange=(-np.pi,np.pi),vdims=['idx',],google_earth=True)
hv.output(widget_location='bottom',holomap='scrubber')
plot_stack.opts(opts.Image(cmap='colorwheel',width=600, height=400, colorbar=True, xlabel='Longitude', ylabel='Latitude'),
                opts.Points(marker='o',size=10))

Plot selected images simutaneously is also supported:

plot_stack.layout()[dates[0:4]].cols(2)