Skip to content

Commit

Permalink
feat(globe): enable globe as accessor
Browse files Browse the repository at this point in the history
  • Loading branch information
jourdain committed Dec 20, 2024
1 parent 8b554c9 commit c8510f8
Show file tree
Hide file tree
Showing 6 changed files with 410 additions and 138 deletions.
105 changes: 105 additions & 0 deletions examples/jupyter/xarray-globe.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d3e629af-a060-4f1e-b821-34114a7694b2",
"metadata": {},
"source": [
"## Load XArray data"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "0a67097d-b562-444a-8c2c-ea383d46fa48",
"metadata": {},
"outputs": [],
"source": [
"import xarray as xr\n",
"\n",
"ds = xr.tutorial.load_dataset(\"air_temperature\")"
]
},
{
"cell_type": "markdown",
"id": "2bb6f93d-0005-4734-9af1-3db0ace2533b",
"metadata": {},
"source": [
"## Show data using Pan3d slicer"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "9a0c47e0-a635-4c95-8bac-382c4e9ab264",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "13609393ee3f4604984a3bb6b11ae634",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HTML(value='<iframe id=\"pan3d_accessor_1_trame__template_main\" src=\"http://localhost:65515/index.html?ui=main&…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ds.pan3d.globe"
]
},
{
"cell_type": "markdown",
"id": "4f65f61f-a4ff-4664-bfc4-3758603b7a1b",
"metadata": {},
"source": [
"### Access to VTK source"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c848393f-0022-41c7-b82a-46789b9acc78",
"metadata": {},
"outputs": [],
"source": [
"print(\"Extents:\", ds.pan3d.globe.source.slice_extents)\n",
"print(\"Slice:\", ds.pan3d.globe.source.slices)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1d0b2248-047b-426b-8a9c-13f83d3915cd",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
77 changes: 65 additions & 12 deletions pan3d/explorers/globe.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
vtkRenderWindow,
)

# need this unused import to set interactor style
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
# VTK factory initialization
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa
import vtkmodules.vtkRenderingOpenGL2 # noqa

from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTerrain
from vtkmodules.vtkFiltersGeometry import vtkDataSetSurfaceFilter
from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
from vtkmodules.vtkCommonCore import vtkLookupTable
from vtkmodules.vtkCommonCore import vtkLookupTable, vtkObject

import json
import traceback
Expand All @@ -34,6 +37,9 @@

from pan3d.utils.globe import get_globe, get_globe_textures, get_continent_outlines

# Prevent view-up warning
vtkObject.GlobalWarningDisplayOff()


@TrameApp()
class GlobeViewer:
Expand All @@ -45,7 +51,7 @@ class GlobeViewer:
relevant data and visualizes it using VTK while interacting with the slice in 2D or 3D.
"""

def __init__(self, server=None, local_rendering=None):
def __init__(self, xarray=None, source=None, server=None, local_rendering=None):
"""Create an instance of the XArrayViewer class.
Parameters:
Expand All @@ -62,6 +68,9 @@ def __init__(self, server=None, local_rendering=None):
- `--wasm`: Use WASM for local rendering
- `--vtkjs`: Use vtk.js for local rendering
"""
self.xarray = xarray
self.source = source

self.server = get_server(server, client_type="vue3")
if self.server.hot_reload:
self.ctrl.on_server_reload.add(self._build_ui)
Expand Down Expand Up @@ -132,11 +141,10 @@ def _setup_vtk(self):

self.render_window.AddRenderer(self.renderer)
self.interactor.SetRenderWindow(self.render_window)
# Following line fixes the unused import problem for setting interaction style
(vtkInteractorStyleTrackballCamera)
self.interactor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()
self.interactor.SetInteractorStyle(vtkInteractorStyleTerrain())

self.source = vtkXArrayRectilinearSource()
if self.source is None:
self.source = vtkXArrayRectilinearSource(input=self.xarray)

self.globe = get_globe()
self.gmapper = vtkPolyDataMapper(input_data_object=self.globe)
Expand All @@ -162,6 +170,13 @@ def _setup_vtk(self):
)
self.actor = vtkActor(mapper=self.mapper, visibility=0)

# Camera
camera = self.renderer.GetActiveCamera()
camera.SetFocalPoint(0, 0, 0)
camera.SetPosition(0, -1, 0)
camera.SetViewUp(0, 0, 1)
self.renderer.ResetCamera()

self.interactor.Initialize()

axes_actor = vtkAxesActor()
Expand Down Expand Up @@ -210,6 +225,9 @@ def _build_ui(self, **kwargs):
self.render_window,
local_rendering=self.local_rendering,
widgets=[self.widget],
disable_style_toggle=True,
disable_roll=True,
disable_axis_align=True,
)

# Scalar bar
Expand Down Expand Up @@ -267,6 +285,7 @@ def _build_ui(self, **kwargs):

# Control panel
ControlPanel(
enable_data_selection=(self.source.input is None),
source=self.source,
toggle="control_expended",
load_dataset=self._load_dataset,
Expand Down Expand Up @@ -326,10 +345,23 @@ def _on_color_preset(

self.ctrl.view_update()

@change("opacity")
def _on_change_opacity(self, opacity, **_):
opacity = float(opacity)
self.actor.GetProperty().SetOpacity(opacity)
@change("opacity", "representation", "cell_size", "render_shadow")
def _on_change_opacity(
self, representation, opacity, cell_size, render_shadow, **_
):
property = self.actor.property
property.render_lines_as_tubes = render_shadow
property.render_points_as_spheres = render_shadow
property.line_width = cell_size
property.point_size = cell_size
property.opacity = float(opacity) if representation == 2 else 1
property.representation = representation

self.ctrl.view_update()

@change("bump_radius")
def _on_bump_radius_change(self, bump_radius, **_):
self.dglobe.bump_radius = bump_radius
self.ctrl.view_update()

@change("texture")
Expand All @@ -355,6 +387,16 @@ def _import_file_upload(self, files):
def _process_cli(self, **_):
args, _ = self.server.cli.parse_known_args()

# Skip if xarray provided
if self.source.input:
if not self.source.arrays:
self.source.arrays = self.source.available_arrays
self.ctrl.xr_update_info(self.source.input, self.source.available_arrays)
self.ctrl.source_update_rendering_panel(self.source)
self._update_rendering(reset_camera=True)
self.state.show_rendering = True
return

# import state
if args.import_state:
self._import_file_from_path(args.import_state)
Expand Down Expand Up @@ -411,6 +453,10 @@ def _load_dataset(self, source, id, order="C", config=None):
self.renderer.RemoveActor(self.actor)
self.actor.visibility = 0

# Make sure arrays are available
if not self.source.arrays:
self.source.arrays = self.source.available_arrays

# Extract UI
self.ctrl.xr_update_info(self.source.input, self.source.available_arrays)
self.ctrl.source_update_rendering_panel(self.source)
Expand Down Expand Up @@ -531,6 +577,13 @@ def save_dataset(self, file_path):
self.state.show_save_dialog = False
return asynchronous.create_task(self._save_dataset(file_path))

async def _async_display(self):
await self.ui.ready
self.ui._ipython_display_()

def _ipython_display_(self):
asynchronous.create_task(self._async_display())


# -----------------------------------------------------------------------------
# Main executable
Expand Down
13 changes: 12 additions & 1 deletion pan3d/filters/globe.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(self):
self.isData = False
self.radius = 6378
self.scale = 1.0
self._bump_radius = 10

def SetDataLayer(self, isData_):
if not self.isData == isData_:
Expand All @@ -38,6 +39,16 @@ def SetScalingFactor(self, scale_):
self.scale = float(scale_)
self.Modified()

@property
def bump_radius(self):
return self._bump_radius

@bump_radius.setter
def bump_radius(self, v):
if v != self._bump_radius:
self._bump_radius = v
self.Modified()

def RequestData(self, request, inInfo, outInfo):
inData = self.GetInputData(inInfo, 0, 0)
outData = self.GetOutputData(outInfo, 0)
Expand All @@ -52,7 +63,7 @@ def RequestData(self, request, inInfo, outInfo):
outWrap = dsa.WrapDataObject(outData)
try:
inPoints = np.array(outWrap.Points)
pRadius = (self.radius + 10) if self.isData else self.radius
pRadius = (self.radius + self._bump_radius) if self.isData else self.radius
outPoints = np.array(
list(map(lambda x: ProcessPoint(x, pRadius, self.scale), inPoints))
)
Expand Down
Loading

0 comments on commit c8510f8

Please sign in to comment.