Skip to content

Commit 1284cca

Browse files
jourdainxhlulu
and
xhlulu
authored
Add picking support (#38)
* Update to [email protected] * update generated files * Update to [email protected] * update generated files * improve pyvista-terrain demo with picking * add support for multi-array fields * udpate generated files * Apply black to demos * Change default to None instead of empty array This ensures we are safe from mutations * npm run build * Bump version Co-authored-by: xhlulu <[email protected]>
1 parent daca5c1 commit 1284cca

28 files changed

+380
-98
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: dashVtk
22
Title: React based declarative usage of vtk.js for Dash
3-
Version: 0.0.6
3+
Version: 0.0.7
44
Description: React based declarative usage of vtk.js for Dash
55
Depends: R (>= 3.0.2)
66
Imports:

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "DashVtk"
33
uuid = "1b08a953-4be3-4667-9a23-818b1eccd4c7"
44
authors = ["Kitware Inc <[email protected]> and Plotly Technologies <[email protected]>"]
5-
version = "0.0.6"
5+
version = "0.0.7"
66

77
[deps]
88
Dash = "1b08a953-4be3-4667-9a23-3db579824955"

R/internal.R

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
.dashVtk_js_metadata <- function() {
22
deps_metadata <- list(`dash_vtk` = structure(list(name = "dash_vtk",
3-
version = "0.0.6", src = list(href = NULL,
3+
version = "0.0.7", src = list(href = NULL,
44
file = "deps"), meta = NULL,
55
script = 'dash_vtk.min.js',
66
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashVtk",
77
all_files = FALSE), class = "html_dependency"),
88
`dash_vtk` = structure(list(name = "dash_vtk",
9-
version = "0.0.6", src = list(href = NULL,
9+
version = "0.0.7", src = list(href = NULL,
1010
file = "deps"), meta = NULL,
1111
script = 'dash_vtk.min.js.map',
1212
stylesheet = NULL, head = NULL, attachment = NULL, package = "dashVtk",

R/vtkGeometryRepresentation.R

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# AUTO GENERATED FILE - DO NOT EDIT
22

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

5-
props <- list(children=children, id=id, actor=actor, mapper=mapper, property=property, colorMapPreset=colorMapPreset, colorDataRange=colorDataRange)
5+
props <- list(children=children, id=id, actor=actor, mapper=mapper, property=property, colorMapPreset=colorMapPreset, colorDataRange=colorDataRange, showCubeAxes=showCubeAxes, cubeAxesStyle=cubeAxesStyle)
66
if (length(props) > 0) {
77
props <- props[!vapply(props, is.null, logical(1))]
88
}
99
component <- list(
1010
props = props,
1111
type = 'GeometryRepresentation',
1212
namespace = 'dash_vtk',
13-
propNames = c('children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange'),
13+
propNames = c('children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle'),
1414
package = 'dashVtk'
1515
)
1616

R/vtkView.R

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# AUTO GENERATED FILE - DO NOT EDIT
22

3-
vtkView <- function(children=NULL, id=NULL, style=NULL, className=NULL, background=NULL, interactorSettings=NULL, cameraPosition=NULL, cameraViewUp=NULL, cameraParallelProjection=NULL, triggerRender=NULL, triggerResetCamera=NULL) {
3+
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) {
44

5-
props <- list(children=children, id=id, style=style, className=className, background=background, interactorSettings=interactorSettings, cameraPosition=cameraPosition, cameraViewUp=cameraViewUp, cameraParallelProjection=cameraParallelProjection, triggerRender=triggerRender, triggerResetCamera=triggerResetCamera)
5+
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)
66
if (length(props) > 0) {
77
props <- props[!vapply(props, is.null, logical(1))]
88
}
99
component <- list(
1010
props = props,
1111
type = 'View',
1212
namespace = 'dash_vtk',
13-
propNames = c('children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera'),
13+
propNames = c('children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo'),
1414
package = 'dashVtk'
1515
)
1616

dash_vtk/GeometryRepresentation.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ class GeometryRepresentation(Component):
2020
- mapper (dict; optional): Properties to set to the actor
2121
- property (dict; optional): Properties to set to the actor.property
2222
- colorMapPreset (string; default 'erdc_rainbow_bright'): Preset name for the lookup table color map
23-
- colorDataRange (list of numbers; default [0, 1]): Data range use for the colorMap"""
23+
- colorDataRange (list of numbers; default [0, 1]): Data range use for the colorMap
24+
- showCubeAxes (boolean; optional): Show/Hide Cube Axes for the given representation
25+
- cubeAxesStyle (dict; optional): Configure cube Axes style by overriding the set of properties defined
26+
https://github.com/Kitware/vtk-js/blob/HEAD/Sources/Rendering/Core/CubeAxesActor/index.js#L703-L719"""
2427
@_explicitize_args
25-
def __init__(self, children=None, id=Component.UNDEFINED, actor=Component.UNDEFINED, mapper=Component.UNDEFINED, property=Component.UNDEFINED, colorMapPreset=Component.UNDEFINED, colorDataRange=Component.UNDEFINED, **kwargs):
26-
self._prop_names = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange']
28+
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):
29+
self._prop_names = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle']
2730
self._type = 'GeometryRepresentation'
2831
self._namespace = 'dash_vtk'
2932
self._valid_wildcard_attributes = []
30-
self.available_properties = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange']
33+
self.available_properties = ['children', 'id', 'actor', 'mapper', 'property', 'colorMapPreset', 'colorDataRange', 'showCubeAxes', 'cubeAxesStyle']
3134
self.available_wildcard_properties = []
3235

3336
_explicit_args = kwargs.pop('_explicit_args')

dash_vtk/View.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,21 @@ class View(Component):
6262
- cameraViewUp (list; default [0, 1, 0]): Initial camera position from an object in [0,0,0]
6363
- cameraParallelProjection (boolean; default False): Use parallel projection (default: false)
6464
- triggerRender (number; default 0): Property use to trigger a render when changing.
65-
- triggerResetCamera (number; default 0): Property use to trigger a resetCamera when changing."""
65+
- triggerResetCamera (number; default 0): Property use to trigger a resetCamera when changing.
66+
- 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).
67+
- clickInfo (dict; optional): Read-only prop. To use this, make sure that `pickingModes` contains `click`.
68+
This prop is updated when an element in the map is clicked. This contains
69+
the picking info describing the object being clicked on.
70+
- hoverInfo (dict; optional): Read-only prop. To use this, make sure that `pickingModes` contains `hover`.
71+
This prop is updated when an element in the map is hovered. This contains
72+
the picking info describing the object being hovered."""
6673
@_explicitize_args
67-
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):
68-
self._prop_names = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera']
74+
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):
75+
self._prop_names = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo']
6976
self._type = 'View'
7077
self._namespace = 'dash_vtk'
7178
self._valid_wildcard_attributes = []
72-
self.available_properties = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera']
79+
self.available_properties = ['children', 'id', 'style', 'className', 'background', 'interactorSettings', 'cameraPosition', 'cameraViewUp', 'cameraParallelProjection', 'triggerRender', 'triggerResetCamera', 'pickingModes', 'clickInfo', 'hoverInfo']
7380
self.available_wildcard_properties = []
7481

7582
_explicit_args = kwargs.pop('_explicit_args')

dash_vtk/dash_vtk.min.js

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dash_vtk/dash_vtk.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dash_vtk/metadata.json

+38
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,20 @@
334334
"computed": false
335335
}
336336
},
337+
"showCubeAxes": {
338+
"type": {
339+
"name": "bool"
340+
},
341+
"required": false,
342+
"description": "Show/Hide Cube Axes for the given representation"
343+
},
344+
"cubeAxesStyle": {
345+
"type": {
346+
"name": "object"
347+
},
348+
"required": false,
349+
"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"
350+
},
337351
"children": {
338352
"type": {
339353
"name": "union",
@@ -1169,6 +1183,30 @@
11691183
"computed": false
11701184
}
11711185
},
1186+
"pickingModes": {
1187+
"type": {
1188+
"name": "arrayOf",
1189+
"value": {
1190+
"name": "string"
1191+
}
1192+
},
1193+
"required": false,
1194+
"description": "List of picking listeners to bind. The supported values are `click` and `hover`. By default it is disabled (empty array)."
1195+
},
1196+
"clickInfo": {
1197+
"type": {
1198+
"name": "object"
1199+
},
1200+
"required": false,
1201+
"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."
1202+
},
1203+
"hoverInfo": {
1204+
"type": {
1205+
"name": "object"
1206+
},
1207+
"required": false,
1208+
"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."
1209+
},
11721210
"children": {
11731211
"type": {
11741212
"name": "union",

dash_vtk/package-info.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dash_vtk",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"description": "React based declarative usage of vtk.js for Dash",
55
"repository": {
66
"type": "git",
@@ -25,7 +25,7 @@
2525
"license": "MIT",
2626
"dependencies": {
2727
"ramda": "^0.26.1",
28-
"react-vtk-js": "1.1.4"
28+
"react-vtk-js": "1.2.1"
2929
},
3030
"devDependencies": {
3131
"@babel/core": "^7.5.4",

dash_vtk/utils/vtk.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@
2424
}
2525

2626

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

32+
if point_arrays is None:
33+
point_arrays = []
34+
if cell_arrays is None:
35+
cell_arrays = []
36+
3237
# Make sure we have a polydata to export
3338
polydata = None
3439
if dataset.IsA('vtkPolyData'):
@@ -77,6 +82,42 @@ def to_mesh_state(dataset, field_to_keep=None):
7782
js_types = to_js_type[str(values.dtype)]
7883
location = 'PointData'
7984

85+
# other arrays (points)
86+
point_data = []
87+
for name in point_arrays:
88+
array = polydata.GetPointData().GetArray(name)
89+
if array:
90+
dataRange = array.GetRange(-1)
91+
nb_comp = array.GetNumberOfComponents()
92+
values = vtk_to_numpy(array).ravel()
93+
js_types = to_js_type[str(values.dtype)]
94+
point_data.append({
95+
'name': name,
96+
'values': values,
97+
'numberOfComponents': nb_comp,
98+
'type': js_types,
99+
'location': 'PointData',
100+
'dataRange': dataRange,
101+
})
102+
103+
# other arrays (cells)
104+
cell_data = []
105+
for name in point_arrays:
106+
array = polydata.GetCellData().GetArray(name)
107+
if array:
108+
dataRange = array.GetRange(-1)
109+
nb_comp = array.GetNumberOfComponents()
110+
values = vtk_to_numpy(array).ravel()
111+
js_types = to_js_type[str(values.dtype)]
112+
cell_data.append({
113+
'name': name,
114+
'values': values,
115+
'numberOfComponents': nb_comp,
116+
'type': js_types,
117+
'location': 'CellData',
118+
'dataRange': dataRange,
119+
})
120+
80121
state = {
81122
'mesh': {
82123
'points': points,
@@ -103,6 +144,11 @@ def to_mesh_state(dataset, field_to_keep=None):
103144
},
104145
})
105146

147+
if len(point_data):
148+
state.update({ 'pointArrays': point_data })
149+
if len(cell_data):
150+
state.update({ 'cellArrays': cell_data })
151+
106152
return state
107153

108154

demos/pyvista-terrain-following-mesh/app.py

+73-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from dash.dependencies import Input, Output, State
77

88
import random
9+
import json
910
import numpy as np
1011
import pyvista as pv
1112
from pyvista import examples
@@ -44,6 +45,7 @@ def updateWarp(factor=1):
4445

4546
vtk_view = dash_vtk.View(
4647
id="vtk-view",
48+
pickingModes=["hover"],
4749
children=[
4850
dash_vtk.GeometryRepresentation(
4951
id="vtk-representation",
@@ -68,8 +70,19 @@ def updateWarp(factor=1):
6870
],
6971
colorMapPreset="erdc_blue2green_muted",
7072
colorDataRange=color_range,
71-
property={"edgeVisibility": True,},
72-
)
73+
property={"edgeVisibility": True},
74+
showCubeAxes=True,
75+
cubeAxesStyle={"axisLabels": ["", "", "Altitude"]},
76+
),
77+
dash_vtk.GeometryRepresentation(
78+
id="pick-rep",
79+
actor={"visibility": False},
80+
children=[
81+
dash_vtk.Algorithm(
82+
id="pick-sphere", vtkClass="vtkSphereSource", state={"radius": 100},
83+
)
84+
],
85+
),
7386
],
7487
)
7588

@@ -96,31 +109,86 @@ def updateWarp(factor=1):
96109
value="erdc_rainbow_bright",
97110
),
98111
),
112+
dbc.Col(
113+
children=dcc.Checklist(
114+
id="toggle-cube-axes",
115+
options=[{"label": " Show axis grid", "value": "grid"},],
116+
value=[],
117+
labelStyle={"display": "inline-block"},
118+
),
119+
),
99120
],
100121
style={"height": "12%", "align-items": "center"},
101122
),
102123
html.Div(
103124
html.Div(vtk_view, style={"height": "100%", "width": "100%"}),
104125
style={"height": "88%"},
105126
),
127+
html.Pre(
128+
id="tooltip",
129+
style={
130+
"position": "absolute",
131+
"bottom": "25px",
132+
"left": "25px",
133+
"zIndex": 1,
134+
"color": "white",
135+
},
136+
),
106137
],
107138
)
108139

109140

110141
@app.callback(
111142
[
143+
Output("vtk-representation", "showCubeAxes"),
112144
Output("vtk-representation", "colorMapPreset"),
113145
Output("vtk-representation", "colorDataRange"),
114146
Output("vtk-polydata", "points"),
115147
Output("vtk-polydata", "polys"),
116148
Output("vtk-array", "values"),
117149
Output("vtk-view", "triggerResetCamera"),
118150
],
119-
[Input("dropdown-preset", "value"), Input("scale-factor", "value")],
151+
[
152+
Input("dropdown-preset", "value"),
153+
Input("scale-factor", "value"),
154+
Input("toggle-cube-axes", "value"),
155+
],
120156
)
121-
def updatePresetName(name, scale_factor):
157+
def updatePresetName(name, scale_factor, cubeAxes):
122158
points, polys, elevation, color_range = updateWarp(scale_factor)
123-
return [name, color_range, points, polys, elevation, random.random()]
159+
return [
160+
"grid" in cubeAxes,
161+
name,
162+
color_range,
163+
points,
164+
polys,
165+
elevation,
166+
random.random(),
167+
]
168+
169+
170+
@app.callback(
171+
[
172+
Output("tooltip", "children"),
173+
Output("pick-sphere", "state"),
174+
Output("pick-rep", "actor"),
175+
],
176+
[Input("vtk-view", "clickInfo"), Input("vtk-view", "hoverInfo"),],
177+
)
178+
def onInfo(clickData, hoverData):
179+
info = hoverData if hoverData else clickData
180+
if info:
181+
if (
182+
"representationId" in info
183+
and info["representationId"] == "vtk-representation"
184+
):
185+
return (
186+
[json.dumps(info, indent=2)],
187+
{"center": info["worldPosition"]},
188+
{"visibility": True},
189+
)
190+
return dash.no_update, dash.no_update, dash.no_update
191+
return [""], {}, {"visibility": False}
124192

125193

126194
if __name__ == "__main__":

deps/dash_vtk.min.js

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deps/dash_vtk.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)