ipygany¶
ipygany is a library that allows client side GPU rendering. This is useful because the data is sotred on the server and manipulations of the visualisation are near realtime.
This example:
Imports a netcdf file using xarray
Converts the netcdf file to a pyvista structured mesh
Converts the pyvista mesh to ipygany mesh
Colors and warps the mesh
Shows the interaction
Imports¶
import pyvista as pv
import numpy as np
import xarray as xr
from ipygany import PolyMesh, Scene, IsoColor, WarpByScalar, ColorBar, colormaps
from ipywidgets import VBox, FloatSlider, FileUpload, Dropdown, jslink
Data upload¶
# Create file upload
# To load several files press shift with selecting -
#all the files have to be selected at the same time.
file_upload = FileUpload(multiple=False)
file_upload
ds = xr.open_dataset(file_upload.data[0])
ds
<xarray.Dataset> Dimensions: (lat: 180, lon: 360) Coordinates: * lon (lon) float64 -179.5 -178.5 -177.5 -176.5 ... 177.5 178.5 179.5 * lat (lat) float64 -89.5 -88.5 -87.5 -86.5 -85.5 ... 86.5 87.5 88.5 89.5 Data variables: TOPO (lat, lon) float32 187.9 179.5 420.2 ... -3.48e+03 -3.48e+03 Attributes: history: Created with add_noise.ncl -- 08.06.21 JBL
xarray.Dataset
- lat: 180
- lon: 360
- lon(lon)float64-179.5 -178.5 ... 178.5 179.5
- long_name :
- longitude
- units :
- degrees_east
- actual_range :
- [-180. 180.]
array([-179.5, -178.5, -177.5, ..., 177.5, 178.5, 179.5])
- lat(lat)float64-89.5 -88.5 -87.5 ... 88.5 89.5
- long_name :
- latitude
- units :
- degrees_north
- actual_range :
- [-90. 90.]
array([-89.5, -88.5, -87.5, -86.5, -85.5, -84.5, -83.5, -82.5, -81.5, -80.5, -79.5, -78.5, -77.5, -76.5, -75.5, -74.5, -73.5, -72.5, -71.5, -70.5, -69.5, -68.5, -67.5, -66.5, -65.5, -64.5, -63.5, -62.5, -61.5, -60.5, -59.5, -58.5, -57.5, -56.5, -55.5, -54.5, -53.5, -52.5, -51.5, -50.5, -49.5, -48.5, -47.5, -46.5, -45.5, -44.5, -43.5, -42.5, -41.5, -40.5, -39.5, -38.5, -37.5, -36.5, -35.5, -34.5, -33.5, -32.5, -31.5, -30.5, -29.5, -28.5, -27.5, -26.5, -25.5, -24.5, -23.5, -22.5, -21.5, -20.5, -19.5, -18.5, -17.5, -16.5, -15.5, -14.5, -13.5, -12.5, -11.5, -10.5, -9.5, -8.5, -7.5, -6.5, -5.5, -4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5, 19.5, 20.5, 21.5, 22.5, 23.5, 24.5, 25.5, 26.5, 27.5, 28.5, 29.5, 30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5, 70.5, 71.5, 72.5, 73.5, 74.5, 75.5, 76.5, 77.5, 78.5, 79.5, 80.5, 81.5, 82.5, 83.5, 84.5, 85.5, 86.5, 87.5, 88.5, 89.5])
- TOPO(lat, lon)float32...
- long_name :
- Added random noise with mean value = 0 m and standard deviation of 100 m
array([[ 187.87802, 179.5152 , 420.18768, ..., 347.60684, 239.41174, 328.91446], [ 235.72939, 183.35826, 130.25673, ..., 371.88663, 166.54791, 501.75983], [ 306.57602, 315.51505, 293.3875 , ..., 346.78452, 228.24268, 200.96342], ..., [-3480. , -3480. , -3480. , ..., -3480. , -3480. , -3480. ], [-3480. , -3480. , -3480. , ..., -3480. , -3480. , -3480. ], [-3480. , -3480. , -3480. , ..., -3480. , -3480. , -3480. ]], dtype=float32)
- history :
- Created with add_noise.ncl -- 08.06.21 JBL
Create pyvista structured mesh¶
xx, yy, zz = np.meshgrid(np.radians(ds['lon']),
np.radians(ds['lat']),
[0])
# Transform to spherical coordinates
radius = 6371.0e6
x = radius * np.cos(yy) * np.cos(xx)
y = radius * np.cos(yy) * np.sin(xx)
z = radius * np.sin(yy)
grid = pv.StructuredGrid(x, y, z)
# Add data to mesh
for var in ds.data_vars:
grid[var] = np.array(ds[var]).ravel(order='F')
Convert pyvista mesh to ipygany mesh¶
# Turn the PyVista mesh into a PolyMesh
mesh = PolyMesh.from_vtk(grid)
# Color the mesh
colored_mesh = IsoColor(mesh, min=ds.TOPO.min(), max=ds.TOPO.max())
# setup warping
warped_mesh = WarpByScalar(colored_mesh, input='TOPO', factor=0)
# Link a slider to the warp value
warp_slider = FloatSlider(min=0., max=10., value=0)
def on_slider_change(change):
warped_mesh.factor = change['new'] * -10000
warp_slider.observe(on_slider_change, 'value')
# Create a colorbar widget
colorbar = ColorBar(colored_mesh)
# Colormap choice widget
colormap = Dropdown(
options=colormaps,
description='colormap:'
)
jslink((colored_mesh, 'colormap'), (colormap, 'index'))
VBox((colormap, warp_slider, Scene([warped_mesh])))