Skip to content

Add picking support #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: dashVtk
Title: React based declarative usage of vtk.js for Dash
Version: 0.0.6
Version: 0.0.7
Description: React based declarative usage of vtk.js for Dash
Depends: R (>= 3.0.2)
Imports:
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "DashVtk"
uuid = "1b08a953-4be3-4667-9a23-818b1eccd4c7"
authors = ["Kitware Inc <[email protected]> and Plotly Technologies <[email protected]>"]
version = "0.0.6"
version = "0.0.7"

[deps]
Dash = "1b08a953-4be3-4667-9a23-3db579824955"
Expand Down
4 changes: 2 additions & 2 deletions R/internal.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
.dashVtk_js_metadata <- function() {
deps_metadata <- list(`dash_vtk` = structure(list(name = "dash_vtk",
version = "0.0.6", src = list(href = NULL,
version = "0.0.7", src = list(href = NULL,
file = "deps"), meta = NULL,
script = 'dash_vtk.min.js',
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashVtk",
all_files = FALSE), class = "html_dependency"),
`dash_vtk` = structure(list(name = "dash_vtk",
version = "0.0.6", src = list(href = NULL,
version = "0.0.7", src = list(href = NULL,
file = "deps"), meta = NULL,
script = 'dash_vtk.min.js.map',
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashVtk",
Expand Down
6 changes: 3 additions & 3 deletions R/vtkGeometryRepresentation.R
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# AUTO GENERATED FILE - DO NOT EDIT

vtkGeometryRepresentation <- function(children=NULL, id=NULL, actor=NULL, mapper=NULL, property=NULL, colorMapPreset=NULL, colorDataRange=NULL) {
vtkGeometryRepresentation <- function(children=NULL, id=NULL, actor=NULL, mapper=NULL, property=NULL, colorMapPreset=NULL, colorDataRange=NULL, showCubeAxes=NULL, cubeAxesStyle=NULL) {

props <- list(children=children, id=id, actor=actor, mapper=mapper, property=property, colorMapPreset=colorMapPreset, colorDataRange=colorDataRange)
props <- list(children=children, id=id, actor=actor, mapper=mapper, property=property, colorMapPreset=colorMapPreset, colorDataRange=colorDataRange, showCubeAxes=showCubeAxes, cubeAxesStyle=cubeAxesStyle)
if (length(props) > 0) {
props <- props[!vapply(props, is.null, logical(1))]
}
component <- list(
props = props,
type = 'GeometryRepresentation',
namespace = 'dash_vtk',
propNames = c('children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange'),
propNames = c('children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle'),
package = 'dashVtk'
)

Expand Down
6 changes: 3 additions & 3 deletions R/vtkView.R
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# AUTO GENERATED FILE - DO NOT EDIT

vtkView <- function(children=NULL, id=NULL, style=NULL, className=NULL, background=NULL, interactorSettings=NULL, cameraPosition=NULL, cameraViewUp=NULL, cameraParallelProjection=NULL, triggerRender=NULL, triggerResetCamera=NULL) {
vtkView <- function(children=NULL, id=NULL, style=NULL, className=NULL, background=NULL, interactorSettings=NULL, cameraPosition=NULL, cameraViewUp=NULL, cameraParallelProjection=NULL, triggerRender=NULL, triggerResetCamera=NULL, pickingModes=NULL, clickInfo=NULL, hoverInfo=NULL) {

props <- list(children=children, id=id, style=style, className=className, background=background, interactorSettings=interactorSettings, cameraPosition=cameraPosition, cameraViewUp=cameraViewUp, cameraParallelProjection=cameraParallelProjection, triggerRender=triggerRender, triggerResetCamera=triggerResetCamera)
props <- list(children=children, id=id, style=style, className=className, background=background, interactorSettings=interactorSettings, cameraPosition=cameraPosition, cameraViewUp=cameraViewUp, cameraParallelProjection=cameraParallelProjection, triggerRender=triggerRender, triggerResetCamera=triggerResetCamera, pickingModes=pickingModes, clickInfo=clickInfo, hoverInfo=hoverInfo)
if (length(props) > 0) {
props <- props[!vapply(props, is.null, logical(1))]
}
component <- list(
props = props,
type = 'View',
namespace = 'dash_vtk',
propNames = c('children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera'),
propNames = c('children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo'),
package = 'dashVtk'
)

Expand Down
11 changes: 7 additions & 4 deletions dash_vtk/GeometryRepresentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ class GeometryRepresentation(Component):
- mapper (dict; optional): Properties to set to the actor
- property (dict; optional): Properties to set to the actor.property
- colorMapPreset (string; default 'erdc_rainbow_bright'): Preset name for the lookup table color map
- colorDataRange (list of numbers; default [0, 1]): Data range use for the colorMap"""
- colorDataRange (list of numbers; default [0, 1]): Data range use for the colorMap
- showCubeAxes (boolean; optional): Show/Hide Cube Axes for the given representation
- cubeAxesStyle (dict; optional): Configure cube Axes style by overriding the set of properties defined
https://github.com/Kitware/vtk-js/blob/HEAD/Sources/Rendering/Core/CubeAxesActor/index.js#L703-L719"""
@_explicitize_args
def __init__(self, children=None, id=Component.UNDEFINED, actor=Component.UNDEFINED, mapper=Component.UNDEFINED, property=Component.UNDEFINED, colorMapPreset=Component.UNDEFINED, colorDataRange=Component.UNDEFINED, **kwargs):
self._prop_names = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange']
def __init__(self, children=None, id=Component.UNDEFINED, actor=Component.UNDEFINED, mapper=Component.UNDEFINED, property=Component.UNDEFINED, colorMapPreset=Component.UNDEFINED, colorDataRange=Component.UNDEFINED, showCubeAxes=Component.UNDEFINED, cubeAxesStyle=Component.UNDEFINED, **kwargs):
self._prop_names = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle']
self._type = 'GeometryRepresentation'
self._namespace = 'dash_vtk'
self._valid_wildcard_attributes = []
self.available_properties = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange']
self.available_properties = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle']
self.available_wildcard_properties = []

_explicit_args = kwargs.pop('_explicit_args')
Expand Down
15 changes: 11 additions & 4 deletions dash_vtk/View.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,21 @@ class View(Component):
- cameraViewUp (list; default [0, 1, 0]): Initial camera position from an object in [0,0,0]
- cameraParallelProjection (boolean; default False): Use parallel projection (default: false)
- triggerRender (number; default 0): Property use to trigger a render when changing.
- triggerResetCamera (number; default 0): Property use to trigger a resetCamera when changing."""
- triggerResetCamera (number; default 0): Property use to trigger a resetCamera when changing.
- pickingModes (list of strings; optional): List of picking listeners to bind. The supported values are `click` and `hover`. By default it is disabled (empty array).
- clickInfo (dict; optional): Read-only prop. To use this, make sure that `pickingModes` contains `click`.
This prop is updated when an element in the map is clicked. This contains
the picking info describing the object being clicked on.
- hoverInfo (dict; optional): Read-only prop. To use this, make sure that `pickingModes` contains `hover`.
This prop is updated when an element in the map is hovered. This contains
the picking info describing the object being hovered."""
@_explicitize_args
def __init__(self, children=None, id=Component.UNDEFINED, style=Component.UNDEFINED, className=Component.UNDEFINED, background=Component.UNDEFINED, interactorSettings=Component.UNDEFINED, cameraPosition=Component.UNDEFINED, cameraViewUp=Component.UNDEFINED, cameraParallelProjection=Component.UNDEFINED, triggerRender=Component.UNDEFINED, triggerResetCamera=Component.UNDEFINED, **kwargs):
self._prop_names = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera']
def __init__(self, children=None, id=Component.UNDEFINED, style=Component.UNDEFINED, className=Component.UNDEFINED, background=Component.UNDEFINED, interactorSettings=Component.UNDEFINED, cameraPosition=Component.UNDEFINED, cameraViewUp=Component.UNDEFINED, cameraParallelProjection=Component.UNDEFINED, triggerRender=Component.UNDEFINED, triggerResetCamera=Component.UNDEFINED, pickingModes=Component.UNDEFINED, clickInfo=Component.UNDEFINED, hoverInfo=Component.UNDEFINED, **kwargs):
self._prop_names = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo']
self._type = 'View'
self._namespace = 'dash_vtk'
self._valid_wildcard_attributes = []
self.available_properties = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera']
self.available_properties = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo']
self.available_wildcard_properties = []

_explicit_args = kwargs.pop('_explicit_args')
Expand Down
14 changes: 7 additions & 7 deletions dash_vtk/dash_vtk.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dash_vtk/dash_vtk.min.js.map

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions dash_vtk/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,20 @@
"computed": false
}
},
"showCubeAxes": {
"type": {
"name": "bool"
},
"required": false,
"description": "Show/Hide Cube Axes for the given representation"
},
"cubeAxesStyle": {
"type": {
"name": "object"
},
"required": false,
"description": "Configure cube Axes style by overriding the set of properties defined\nhttps://github.com/Kitware/vtk-js/blob/HEAD/Sources/Rendering/Core/CubeAxesActor/index.js#L703-L719"
},
"children": {
"type": {
"name": "union",
Expand Down Expand Up @@ -1169,6 +1183,30 @@
"computed": false
}
},
"pickingModes": {
"type": {
"name": "arrayOf",
"value": {
"name": "string"
}
},
"required": false,
"description": "List of picking listeners to bind. The supported values are `click` and `hover`. By default it is disabled (empty array)."
},
"clickInfo": {
"type": {
"name": "object"
},
"required": false,
"description": "Read-only prop. To use this, make sure that `pickingModes` contains `click`.\nThis prop is updated when an element in the map is clicked. This contains\nthe picking info describing the object being clicked on."
},
"hoverInfo": {
"type": {
"name": "object"
},
"required": false,
"description": "Read-only prop. To use this, make sure that `pickingModes` contains `hover`.\nThis prop is updated when an element in the map is hovered. This contains\nthe picking info describing the object being hovered."
},
"children": {
"type": {
"name": "union",
Expand Down
4 changes: 2 additions & 2 deletions dash_vtk/package-info.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dash_vtk",
"version": "0.0.6",
"version": "0.0.7",
"description": "React based declarative usage of vtk.js for Dash",
"repository": {
"type": "git",
Expand All @@ -25,7 +25,7 @@
"license": "MIT",
"dependencies": {
"ramda": "^0.26.1",
"react-vtk-js": "1.1.4"
"react-vtk-js": "1.2.1"
},
"devDependencies": {
"@babel/core": "^7.5.4",
Expand Down
48 changes: 47 additions & 1 deletion dash_vtk/utils/vtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@
}


def to_mesh_state(dataset, field_to_keep=None):
def to_mesh_state(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None):
'''Expect any dataset and extract its surface into a dash_vtk.Mesh state property'''
if dataset is None:
return None

if point_arrays is None:
point_arrays = []
if cell_arrays is None:
cell_arrays = []

# Make sure we have a polydata to export
polydata = None
if dataset.IsA('vtkPolyData'):
Expand Down Expand Up @@ -77,6 +82,42 @@ def to_mesh_state(dataset, field_to_keep=None):
js_types = to_js_type[str(values.dtype)]
location = 'PointData'

# other arrays (points)
point_data = []
for name in point_arrays:
array = polydata.GetPointData().GetArray(name)
if array:
dataRange = array.GetRange(-1)
nb_comp = array.GetNumberOfComponents()
values = vtk_to_numpy(array).ravel()
js_types = to_js_type[str(values.dtype)]
point_data.append({
'name': name,
'values': values,
'numberOfComponents': nb_comp,
'type': js_types,
'location': 'PointData',
'dataRange': dataRange,
})

# other arrays (cells)
cell_data = []
for name in point_arrays:
array = polydata.GetCellData().GetArray(name)
if array:
dataRange = array.GetRange(-1)
nb_comp = array.GetNumberOfComponents()
values = vtk_to_numpy(array).ravel()
js_types = to_js_type[str(values.dtype)]
cell_data.append({
'name': name,
'values': values,
'numberOfComponents': nb_comp,
'type': js_types,
'location': 'CellData',
'dataRange': dataRange,
})

state = {
'mesh': {
'points': points,
Expand All @@ -103,6 +144,11 @@ def to_mesh_state(dataset, field_to_keep=None):
},
})

if len(point_data):
state.update({ 'pointArrays': point_data })
if len(cell_data):
state.update({ 'cellArrays': cell_data })

return state


Expand Down
78 changes: 73 additions & 5 deletions demos/pyvista-terrain-following-mesh/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dash.dependencies import Input, Output, State

import random
import json
import numpy as np
import pyvista as pv
from pyvista import examples
Expand Down Expand Up @@ -44,6 +45,7 @@ def updateWarp(factor=1):

vtk_view = dash_vtk.View(
id="vtk-view",
pickingModes=["hover"],
children=[
dash_vtk.GeometryRepresentation(
id="vtk-representation",
Expand All @@ -68,8 +70,19 @@ def updateWarp(factor=1):
],
colorMapPreset="erdc_blue2green_muted",
colorDataRange=color_range,
property={"edgeVisibility": True,},
)
property={"edgeVisibility": True},
showCubeAxes=True,
cubeAxesStyle={"axisLabels": ["", "", "Altitude"]},
),
dash_vtk.GeometryRepresentation(
id="pick-rep",
actor={"visibility": False},
children=[
dash_vtk.Algorithm(
id="pick-sphere", vtkClass="vtkSphereSource", state={"radius": 100},
)
],
),
],
)

Expand All @@ -96,31 +109,86 @@ def updateWarp(factor=1):
value="erdc_rainbow_bright",
),
),
dbc.Col(
children=dcc.Checklist(
id="toggle-cube-axes",
options=[{"label": " Show axis grid", "value": "grid"},],
value=[],
labelStyle={"display": "inline-block"},
),
),
],
style={"height": "12%", "align-items": "center"},
),
html.Div(
html.Div(vtk_view, style={"height": "100%", "width": "100%"}),
style={"height": "88%"},
),
html.Pre(
id="tooltip",
style={
"position": "absolute",
"bottom": "25px",
"left": "25px",
"zIndex": 1,
"color": "white",
},
),
],
)


@app.callback(
[
Output("vtk-representation", "showCubeAxes"),
Output("vtk-representation", "colorMapPreset"),
Output("vtk-representation", "colorDataRange"),
Output("vtk-polydata", "points"),
Output("vtk-polydata", "polys"),
Output("vtk-array", "values"),
Output("vtk-view", "triggerResetCamera"),
],
[Input("dropdown-preset", "value"), Input("scale-factor", "value")],
[
Input("dropdown-preset", "value"),
Input("scale-factor", "value"),
Input("toggle-cube-axes", "value"),
],
)
def updatePresetName(name, scale_factor):
def updatePresetName(name, scale_factor, cubeAxes):
points, polys, elevation, color_range = updateWarp(scale_factor)
return [name, color_range, points, polys, elevation, random.random()]
return [
"grid" in cubeAxes,
name,
color_range,
points,
polys,
elevation,
random.random(),
]


@app.callback(
[
Output("tooltip", "children"),
Output("pick-sphere", "state"),
Output("pick-rep", "actor"),
],
[Input("vtk-view", "clickInfo"), Input("vtk-view", "hoverInfo"),],
)
def onInfo(clickData, hoverData):
info = hoverData if hoverData else clickData
if info:
if (
"representationId" in info
and info["representationId"] == "vtk-representation"
):
return (
[json.dumps(info, indent=2)],
{"center": info["worldPosition"]},
{"visibility": True},
)
return dash.no_update, dash.no_update, dash.no_update
return [""], {}, {"visibility": False}


if __name__ == "__main__":
Expand Down
14 changes: 7 additions & 7 deletions deps/dash_vtk.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion deps/dash_vtk.min.js.map

Large diffs are not rendered by default.

Loading