Coordinate extractor

This only seems to be working in Jupyter notebook classic. If in Jupyter lab:
  1. Help
  2. Launch classic Notebook

A quick notebook to extract coordinates from a file from drawing on the canvas.

This notebook has been tested on simple lat lon files, either convert your curvilinear coordinates to flat coordinates or modify the script

import xarray as xr
import holoviews as hv
from holoviews.selection import link_selections

import panel as pn
import param
hv.extension('bokeh')

Set varaible names

This should be the only things that HAVE to be changed for the script to work

filename = 'FILENAME_HERE'
x_coord = 'lon'
y_coord = 'lat'
var = 'variable_name'

Load the data

ds = xr.open_dataset(filename)
ds
<xarray.Dataset>
Dimensions:     (x: 182, y: 149)
Coordinates:
    nav_lon     (y, x) float64 105.0 107.0 109.0 111.0 ... 106.0 106.0 106.0
    nav_lat     (y, x) float64 -78.19 -78.19 -78.19 -78.19 ... 59.91 59.91 59.91
Dimensions without coordinates: x, y
Data variables:
    Bathymetry  (y, x) float64 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0
Attributes:
    CDI:                       Climate Data Interface version 1.7.2 (http://m...
    Conventions:               CF-1.6
    history:                   Mon Oct  7 16:29:46 2019: ncatted -a long_name...
    NCO:                       "4.6.0"
    nco_openmp_thread_number:  1
    CDO:                       Climate Data Operators version 1.7.2rc6 (http:...
# Sanitize coords

if len(ds[x_coord].dims) != len(ds[y_coord].dims):
    raise AttributeError(f"Unknown coordinate system different lengths for {x_coord}: {ds[x_coord].dims} and {y_coord}: {ds[y_coord].dims}")
    
if ds[x_coord].dims != ds[y_coord].dims:
    raise AttributeError(f"Too many coordinates{ds[x_coord].dims} and {ds[y_coord].dims}")
    
    
if len(ds[x_coord].dims) > 2:
    raise AttributeError(f"Coordinate too long {len(ds[y_coord].dims)}")
    
if len(ds[x_coord].dims) == 2:
    dims = list(ds[x_coord].dims)
    # Add the dimension into the coordinates this results in an ij indexing
    ds.coords[dims[0]] = ds[dims[0]]
    ds.coords[dims[1]] = ds[dims[1]]
    # Remove the curvilinear coordinates from the original coordinates
    ds = ds.reset_coords()
    x_coord = dims[1]
    y_coord = dims[0]

Create and load the tool

# We create 2 data sets for ease the pandas one is used to display and filter coords the xarray one is used to 
# generate the image, if we dont use a hv.Dataset the selection doesn't seem to work???
dataset_pandas = hv.Dataset(ds[var].to_dataframe().reset_index())
dataset = hv.Dataset(ds[var])

# Cretae the map
image = hv.Image(dataset, [x_coord, y_coord], var).opts(cmap='RdBu', width=700, aspect=2)

# Create the selection object this is what is used to capture the selection info
link = link_selections.instance()
plots = link(image)

# Update the table when the selection expression changes
@param.depends(link.param.selection_expr)
def selection_table(_):
    return hv.Table(dataset_pandas.select(link.selection_expr)).opts(width=900, height=200)

# Show it all together
app = pn.Column(plots, selection_table, height=600)
app
WARNING:param.OverlayPlot02112: Due to internal constraints, when aspect and width/height is set, the bokeh backend uses those values as frame_width/frame_height instead. This ensures the aspect is respected, but means that the plot might be slightly larger than anticipated. Set the frame_width/frame_height explicitly to suppress this warning.

Access the selected values outside of the tool

this is a pandas.DataFrame so you can call things like df.loc[x_coord, y_coord] to retrieve the coordinates these can then be passed back to xarray .sel to select along these coordinates

df = dataset_pandas.select(link.selection_expr).data
df
y x Bathymetry
0 0 0 0.0
1 0 1 0.0
2 0 2 0.0
3 0 3 0.0
4 0 4 0.0
... ... ... ...
27113 148 177 0.0
27114 148 178 0.0
27115 148 179 0.0
27116 148 180 0.0
27117 148 181 0.0

27118 rows × 3 columns