bjlittle / geovista

Cartographic rendering and mesh analytics powered by PyVista

Home Page:https://geovista.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Hexadron grid

PBrockmann opened this issue · comments

I like to display a mesh of hexaedron cells with geovista to have all projections available.

Here is the mesh I can create and display with pyvista.

import numpy as np
import xarray as xr
import pyvista as pv

ds = xr.open_dataset("https://thredds-su.ipsl.fr/thredds/dodsC/ipsl_thredds/brocksce/ICO/ICO.79.1jour.native.1_19790101_19790101_1D_inca_ges.nc")

blon = ds['bounds_lon'].to_numpy()
blat = ds['bounds_lat'].to_numpy()
nvertex = blon.shape[-1]

blon = blon.reshape(-1, nvertex)
blat = blat.reshape(-1, nvertex)

arr = ds['bounds_lon'].to_numpy()
blon = arr.reshape(-1, arr.shape[-1])
arr = ds['bounds_lat'].to_numpy()
blat = arr.reshape(-1, arr.shape[-1])

deg2rad = np.pi/180.
x = np.cos(blat*deg2rad)*np.cos(blon*deg2rad)
y = np.cos(blat*deg2rad)*np.sin(blon*deg2rad)
z = np.sin(blat*deg2rad)

points = np.stack((x,y,z), axis=2).reshape(x.size, 3)
faces = np.arange(x.shape[0] * nvertex).reshape(x.shape[0], nvertex)
faces = np.insert(faces, 0, nvertex, axis=1)

points = np.stack((x,y,z), axis=2).reshape(x.size, 3)
faces = np.arange(x.shape[0] * nvertex).reshape(x.shape[0], nvertex)
faces = np.insert(faces, 0, nvertex, axis=1)

mesh = pv.PolyData(points, faces)

pl = pv.Plotter()
pl.add_mesh(mesh, show_edges=True)
pl.show()

screenshot

Now if I use geovista with this mesh that is in my understanding the same object as what gv.Transform.from_unstructured returns I do not get the expected projected mesh.

plotter = gv.GeoPlotter(crs="ESRI:54030")
plotter.add_mesh(mesh, show_edges=True)
plotter.view_xy()
plotter.add_axes()
plotter.show()

What do I have missed ?

Ok it works by using indeed gv.Transform.from_unstructured that defines additionnal parameters.

import numpy as np
import xarray as xr
import geovista as gv

ds = xr.open_dataset("https://thredds-su.ipsl.fr/thredds/dodsC/ipsl_thredds/brocksce/ICO/ICO.79.1jour.native.1_19790101_19790101_1D_inca_ges.nc")

blon = ds['bounds_lon'].to_numpy()
blat = ds['bounds_lat'].to_numpy()
nvertex = blon.shape[-1]

blon = blon.reshape(-1, nvertex)
blat = blat.reshape(-1, nvertex)

arr = ds['bounds_lon'].to_numpy()
blon = arr.reshape(-1, arr.shape[-1])
arr = ds['bounds_lat'].to_numpy()
blat = arr.reshape(-1, arr.shape[-1])

faces = np.arange(blon.shape[0] * nvertex).reshape(blon.shape[0], nvertex)

mesh = gv.Transform.from_unstructured(
   blon.ravel(),
   blat.ravel(), 
   connectivity = faces,
   data = ds['temp'][0,0]
)

then

plotter = gv.GeoPlotter(crs="ESRI:54030")
plotter.add_mesh(mesh, cmap="thermal", show_edges=True, edge_color="black")
plotter.add_coastlines(resolution="50m", color="black")
plotter.view_xy()
plotter.add_axes()
plotter.show()

screenshot (1)

@PBrockmann Neat! Love it!

The geovista.bridge is getting quite sophisticated, which means you can simply boil it down to the following...

import geovista as gv
import geovista.theme
import xarray as xr


ds = xr.open_dataset("ICO.79.1jour.native.1_19790101_19790101_1D_inca_ges.nc")

blon = ds['bounds_lon'].to_numpy()
blat = ds['bounds_lat'].to_numpy()
data = ds["ps"]

mesh = gv.Transform.from_unstructured(blon, blat, data=data[0].to_numpy())

pl = gv.GeoPlotter()
sargs = {"title": f"{data.long_name} / {data.units}", "shadow": True}
pl.add_mesh(mesh, show_edges=True, scalar_bar_args=sargs)
pl.add_coastlines()
pl.add_axes()
pl.show()

Which renders as:
image

Yes indeed much more simpler.
No need of faces connectivity either.

Nice !

I dream about being able to update efficiently the data for each time step. Or vertical levels. To produce a kind of animation. Using ipywidgets.
I have made some prototype with this idea available from: https://github.com/PBrockmann/LSCE_notebooks/blob/main/pyvista_DYNAMICO_orthographic_trame.ipynb

See also discussion from: pyvista/pyvista#2567

It would be nice to share experience on this.