Skip to content
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

Re-rendering is broken when ImageData remains the same but child changes #27

Closed
xhluca opened this issue Feb 17, 2021 · 18 comments
Closed

Comments

@xhluca
Copy link
Collaborator

xhluca commented Feb 17, 2021

Bug

I built a set of radio buttons to alternate between different representations (volumes and algorithms). This is done through a callback. When the data (i.e. ImageData) remains the same, but the child PointData changes, dash-vtk will not correctly re-render the new view.

Here's a demo:

vtk-bug

Notice how going random -> progressive doesn't work, but random -> cone or cone -> progressive works. This is because cone uses a Algorithm instead of ImageData, so it would trigger a rerender.

Code

Show full code

import dash_vtk
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import numpy as np


def build_vtk_representation(field):
    return dash_vtk.VolumeRepresentation(
        [
            dash_vtk.VolumeController(),
            dash_vtk.ImageData(
                id="image-data",
                dimensions=[10, 10, 10],
                spacing=[1, 1, 1],
                origin=[0, 0, 0],
                children=dash_vtk.PointData(
                    dash_vtk.DataArray(registration="setScalars", values=field)
                ),
            ),
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)]),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10)),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]


app = dash.Dash(__name__)
server = app.server


app.layout = html.Div(
    style={"width": "100%", "height": "calc(90vh - 16px)"},
    children=[
        dcc.RadioItems(
            id="radio-items",
            options=[
                {"value": i, "label": x}
                for i, x in enumerate(["random", "progressive", "cone"])
            ],
            value=0,
        ),
        html.Br(),
        dash_vtk.View(id="vtk-view"),
        html.Div(id="output"),
    ],
)


@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()


if __name__ == "__main__":
    app.run_server(debug=True)

Here's a snippet:

def build_vtk_representation(field):
    return dash_vtk.VolumeRepresentation(
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ImageData(
                ...,
                children=dash_vtk.PointData(
                    dash_vtk.DataArray(registration="setScalars", values=field)
                ),
            ),
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)]),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10)),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]

app = dash.Dash(__name__)
server = app.server
app.layout = ...

@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()
@xhluca
Copy link
Collaborator Author

xhluca commented Feb 17, 2021

I was able to resolve it by explicitly assigning an id to VolumeRepresentation to force a re-rendering. Moreover, I'm not sure if this is the intended behavior, since it's not something very intuitive as I tend to leave id blank when I don't need to update that specific component (instead, I want to update its parent).

Show full code

import dash_vtk
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import numpy as np


def build_vtk_representation(field, _id):
    return dash_vtk.VolumeRepresentation(
        id=_id,
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ImageData(
                dimensions=[10, 10, 10],
                spacing=[1, 1, 1],
                origin=[0, 0, 0],
                children=dash_vtk.PointData(
                    dash_vtk.DataArray(registration="setScalars", values=field)
                ),
            ),
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)], _id="bar"),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10), _id="foo"),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]


app = dash.Dash(__name__)
server = app.server


app.layout = html.Div(
    style={"width": "100%", "height": "calc(90vh - 16px)"},
    children=[
        dcc.RadioItems(
            id="radio-items",
            options=[
                {"value": i, "label": x}
                for i, x in enumerate(["random", "progressive", "cone"])
            ],
            value=0,
        ),
        html.Br(),
        dash_vtk.View(id="vtk-view"),
        html.Div(id="output"),
    ],
)


@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()


if __name__ == "__main__":
    app.run_server(debug=True)

Snippet:

def build_vtk_representation(field, _id):
    return dash_vtk.VolumeRepresentation(
        id=_id,
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ImageData(
                dimensions=[10, 10, 10],
                spacing=[1, 1, 1],
                origin=[0, 0, 0],
                children=dash_vtk.PointData(
                    dash_vtk.DataArray(registration="setScalars", values=field)
                ),
            ),
        ]
    )

@jourdain
Copy link
Collaborator

jourdain commented Feb 17, 2021

Are you sure it is a rendering issue? When you rotate the camera, do you see the correct image?

  • Yes
  • No

If that is not the problem, it might be related to the way react (or dash) update the underneath structure. I might not detect the array swap and may need to trigger a modified() on the given dataArray.

@jourdain
Copy link
Collaborator

Also make sure you look at the console in case any error arise that could give us a clue.

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 17, 2021

When you rotate the camera, do you see the correct image?

Do you mean pan/zoom? After panning or zooming the view still hasn't correctly updated.

@jourdain
Copy link
Collaborator

Great, that means it is not a rendering issue...
Do you want me to investigate to see what could be going on?

@jourdain
Copy link
Collaborator

Thx for the console output. But in our case it does not help. We don't see any relevant issue related to the problem at hand.

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 18, 2021

I think it's worth investigating. I'm currently building an app where I'd dynamically change the image data and it makes it rather difficult. Even with the work around, the moment I try to make it more complex I get errors like this:

Show error

dash_renderer.v1_9_0m1611082207.dev.js:100499 TypeError: Cannot read property '0' of undefined
    at u (mat4.js:1)
    at Object.e.setCameraShaderParameters (ImageMapper.js:1)
    at Object.e.updateShaders (ImageMapper.js:1)
    at Object.e.renderPieceDraw (ImageMapper.js:1)
    at Object.e.renderPiece (ImageMapper.js:1)
    at Object.e.render (ImageMapper.js:1)
    at e.opaqueZBufferPass (ImageMapper.js:1)
    at Object.St.e.apply (ViewNode.js:1)
    at Object.St.e.traverse (ViewNode.js:1)
    at ImageSlice.js:1
error @ dash_renderer.v1_9_0m1611082207.dev.js:100499
combination @ dash_renderer.v1_9_0m1611082207.dev.js:90482
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:101004
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:101050
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90236
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
componentDidCatch @ dash_renderer.v1_9_0m1611082207.dev.js:97244
callback @ react-dom@16.v1_9_0m1611082192.14.0.js:20884
callCallback @ react-dom@16.v1_9_0m1611082192.14.0.js:12625
commitUpdateQueue @ react-dom@16.v1_9_0m1611082192.14.0.js:12646
commitLifeCycles @ react-dom@16.v1_9_0m1611082192.14.0.js:19993
commitLayoutEffects @ react-dom@16.v1_9_0m1611082192.14.0.js:22938
callCallback @ react-dom@16.v1_9_0m1611082192.14.0.js:182
invokeGuardedCallbackDev @ react-dom@16.v1_9_0m1611082192.14.0.js:231
invokeGuardedCallback @ react-dom@16.v1_9_0m1611082192.14.0.js:286
commitRootImpl @ react-dom@16.v1_9_0m1611082192.14.0.js:22676
unstable_runWithPriority @ react@16.v1_9_0m1611082192.14.0.js:2685
runWithPriority$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:11174
commitRoot @ react-dom@16.v1_9_0m1611082192.14.0.js:22516
finishSyncRender @ react-dom@16.v1_9_0m1611082192.14.0.js:21942
performSyncWorkOnRoot @ react-dom@16.v1_9_0m1611082192.14.0.js:21928
(anonymous) @ react-dom@16.v1_9_0m1611082192.14.0.js:11224
unstable_runWithPriority @ react@16.v1_9_0m1611082192.14.0.js:2685
runWithPriority$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:11174
flushSyncCallbackQueueImpl @ react-dom@16.v1_9_0m1611082192.14.0.js:11219
flushSyncCallbackQueue @ react-dom@16.v1_9_0m1611082192.14.0.js:11207
batchedUpdates$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:21997
notify @ dash_renderer.v1_9_0m1611082207.dev.js:88742
notifyNestedSubs @ dash_renderer.v1_9_0m1611082207.dev.js:88815
handleChangeWrapper @ dash_renderer.v1_9_0m1611082207.dev.js:88820
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90245
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
applyProps @ dash_renderer.v1_9_0m1611082207.dev.js:98695
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:98736
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:98723
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
observer @ dash_renderer.v1_9_0m1611082207.dev.js:98705
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:92653
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
StoreObserver.notify @ dash_renderer.v1_9_0m1611082207.dev.js:92651
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90245
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
_callee$ @ dash_renderer.v1_9_0m1611082207.dev.js:98923
tryCatch @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
invoke @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
t.<computed> @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:98858
_next @ dash_renderer.v1_9_0m1611082207.dev.js:98860
Promise.then (async)
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:98858
_next @ dash_renderer.v1_9_0m1611082207.dev.js:98860
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:98860
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:98860
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:98936
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
observer @ dash_renderer.v1_9_0m1611082207.dev.js:98894
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:92653
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
StoreObserver.notify @ dash_renderer.v1_9_0m1611082207.dev.js:92651
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90245
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
_callee2$ @ dash_renderer.v1_9_0m1611082207.dev.js:99172
tryCatch @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
invoke @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
t.<computed> @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:99094
_next @ dash_renderer.v1_9_0m1611082207.dev.js:99096
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:99096
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:99096
observer @ dash_renderer.v1_9_0m1611082207.dev.js:99239
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:92653
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
StoreObserver.notify @ dash_renderer.v1_9_0m1611082207.dev.js:92651
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90245
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
_callee$ @ dash_renderer.v1_9_0m1611082207.dev.js:99507
tryCatch @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
invoke @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
t.<computed> @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:99271
_next @ dash_renderer.v1_9_0m1611082207.dev.js:99273
Promise.then (async)
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:99271
_next @ dash_renderer.v1_9_0m1611082207.dev.js:99273
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:99273
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:99273
observer @ dash_renderer.v1_9_0m1611082207.dev.js:99522
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:92653
forEach @ dash_renderer.v1_9_0m1611082207.dev.js:71683
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:74149
f2 @ dash_renderer.v1_9_0m1611082207.dev.js:74400
StoreObserver.notify @ dash_renderer.v1_9_0m1611082207.dev.js:92651
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90245
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89995
dispatch @ dash_renderer.v1_9_0m1611082207.dev.js:90661
_callee$ @ dash_renderer.v1_9_0m1611082207.dev.js:95403
tryCatch @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
invoke @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
t.<computed> @ polyfill@7.v1_9_0m1611082192.8.7.min.js:1
asyncGeneratorStep @ dash_renderer.v1_9_0m1611082207.dev.js:95283
_next @ dash_renderer.v1_9_0m1611082207.dev.js:95285
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:95285
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:95285
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:95414
(anonymous) @ dash_renderer.v1_9_0m1611082207.dev.js:89992
setProps @ dash_renderer.v1_9_0m1611082207.dev.js:92845
onChange @ dash_bootstrap_components.v0_11_3m1613519456.min.js:31
callCallback @ react-dom@16.v1_9_0m1611082192.14.0.js:182
invokeGuardedCallbackDev @ react-dom@16.v1_9_0m1611082192.14.0.js:231
invokeGuardedCallback @ react-dom@16.v1_9_0m1611082192.14.0.js:286
invokeGuardedCallbackAndCatchFirstError @ react-dom@16.v1_9_0m1611082192.14.0.js:300
executeDispatch @ react-dom@16.v1_9_0m1611082192.14.0.js:383
executeDispatchesInOrder @ react-dom@16.v1_9_0m1611082192.14.0.js:408
executeDispatchesAndRelease @ react-dom@16.v1_9_0m1611082192.14.0.js:3401
executeDispatchesAndReleaseTopLevel @ react-dom@16.v1_9_0m1611082192.14.0.js:3410
forEachAccumulated @ react-dom@16.v1_9_0m1611082192.14.0.js:3380
runEventsInBatch @ react-dom@16.v1_9_0m1611082192.14.0.js:3427
runExtractedPluginEventsInBatch @ react-dom@16.v1_9_0m1611082192.14.0.js:3637
handleTopLevel @ react-dom@16.v1_9_0m1611082192.14.0.js:3681
batchedEventUpdates$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:22006
batchedEventUpdates @ react-dom@16.v1_9_0m1611082192.14.0.js:792
dispatchEventForLegacyPluginEventSystem @ react-dom@16.v1_9_0m1611082192.14.0.js:3691
attemptToDispatchEvent @ react-dom@16.v1_9_0m1611082192.14.0.js:4390
dispatchEvent @ react-dom@16.v1_9_0m1611082192.14.0.js:4312
unstable_runWithPriority @ react@16.v1_9_0m1611082192.14.0.js:2685
runWithPriority$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:11174
discreteUpdates$1 @ react-dom@16.v1_9_0m1611082192.14.0.js:22022
discreteUpdates @ react-dom@16.v1_9_0m1611082192.14.0.js:803
dispatchDiscreteEvent @ react-dom@16.v1_9_0m1611082192.14.0.js:4291
Show 110 more frames
VolumeController.js:1 Uncaught TypeError: Cannot read property 'getScalars' of undefined
    at Object.Kc.e.setupContent (VolumeController.js:1)
    at i.value (VolumeController.js:1)
    at VolumeController.js:1

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 18, 2021

An example of what I mean above: if you wrap the ImageData with "ShareDataset", the demo will immediately break:

See full code

import dash_vtk
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import numpy as np


def build_vtk_representation(field, _id):
    return dash_vtk.VolumeRepresentation(
        id=_id,
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ShareDataSet(
                dash_vtk.ImageData(
                    dimensions=[10, 10, 10],
                    spacing=[1, 1, 1],
                    origin=[0, 0, 0],
                    children=dash_vtk.PointData(
                        dash_vtk.DataArray(registration="setScalars", values=field)
                    ),
                ),
            )
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)], _id="bar"),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10), _id="foo"),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]


app = dash.Dash(__name__)
server = app.server


app.layout = html.Div(
    style={"width": "100%", "height": "calc(90vh - 16px)"},
    children=[
        dcc.RadioItems(
            id="radio-items",
            options=[
                {"value": i, "label": x}
                for i, x in enumerate(["random", "progressive", "cone"])
            ],
            value=0,
        ),
        html.Br(),
        dash_vtk.View(id="vtk-view"),
        html.Div(id="output"),
    ],
)


@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()


if __name__ == "__main__":
    app.run_server(debug=True)

def build_vtk_representation(field, _id):
    return dash_vtk.VolumeRepresentation(
        id=_id,
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ShareDataSet(
                dash_vtk.ImageData(
                    dimensions=[10, 10, 10],
                    spacing=[1, 1, 1],
                    origin=[0, 0, 0],
                    children=dash_vtk.PointData(
                        dash_vtk.DataArray(registration="setScalars", values=field)
                    ),
                ),
            )
        ]
    )

image

@jourdain
Copy link
Collaborator

Should be fixed in the latest master (updated dependency => npm i)

commit dc3a04d6a83f1b947da170b0db09a9114291bf53
Author: Sebastien Jourdain <sebastien.jourdain@kitware.com>
Date:   Thu Feb 18 14:46:51 2021 -0700

    fix(react-vtk-js): fix dynamic handling of DataArray update

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 18, 2021

@jourdain seems like it's now possible to alternate between two image data of the same representation, but we can't change the representation back-and-forth anymore.

See full code

import dash_vtk
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import numpy as np


def build_vtk_representation(field):
    return dash_vtk.VolumeRepresentation(
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ShareDataSet(
                dash_vtk.ImageData(
                    dimensions=[10, 10, 10],
                    spacing=[1, 1, 1],
                    origin=[0, 0, 0],
                    children=dash_vtk.PointData(
                        dash_vtk.DataArray(registration="setScalars", values=field)
                    ),
                ),
            )
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)]),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10)),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]


app = dash.Dash(__name__)
server = app.server


app.layout = html.Div(
    style={"width": "100%", "height": "calc(90vh - 16px)"},
    children=[
        dcc.RadioItems(
            id="radio-items",
            options=[
                {"value": i, "label": x}
                for i, x in enumerate(["random", "progressive", "cone"])
            ],
            value=0,
        ),
        html.Br(),
        dash_vtk.View(id="vtk-view"),
        html.Div(id="output"),
    ],
)


@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()


if __name__ == "__main__":
    app.run_server(debug=True)

vtk-bug-2

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 18, 2021

So seems like it works when I remove the sharedataset wrapper:

See full code

import dash_vtk
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import numpy as np


def build_vtk_representation(field):
    return dash_vtk.VolumeRepresentation(
        children=[
            dash_vtk.VolumeController(),
            dash_vtk.ImageData(
                dimensions=[10, 10, 10],
                spacing=[1, 1, 1],
                origin=[0, 0, 0],
                children=dash_vtk.PointData(
                    dash_vtk.DataArray(registration="setScalars", values=field)
                ),
            ),
        ]
    )


views = [
    build_vtk_representation([np.random.random() for i in range(10 * 10 * 10)]),
    build_vtk_representation(np.linspace(0, 1, num=10 * 10 * 10)),
    dash_vtk.GeometryRepresentation(
        [
            dash_vtk.Algorithm(
                vtkClass="vtkConeSource", state={"resolution": 64, "capping": False,},
            )
        ]
    ),
]


app = dash.Dash(__name__)
server = app.server


app.layout = html.Div(
    style={"width": "100%", "height": "calc(90vh - 16px)"},
    children=[
        dcc.RadioItems(
            id="radio-items",
            options=[
                {"value": i, "label": x}
                for i, x in enumerate(["random", "progressive", "cone"])
            ],
            value=0,
        ),
        html.Br(),
        dash_vtk.View(id="vtk-view"),
        html.Div(id="output"),
    ],
)


@app.callback(
    Output("vtk-view", "children"),
    Output("vtk-view", "triggerRender"),
    Input("radio-items", "value"),
)
def update_vtk_view(value):
    if value is None:
        return dash.no_update
    return views[value], np.random.random()


if __name__ == "__main__":
    app.run_server(debug=True)

@jourdain
Copy link
Collaborator

Thanks I'm going to look at the ShareDataSet part...

@jourdain
Copy link
Collaborator

So I've created a test with the ShareDataSet and seems that things works as expected as long as you don't change the representation. (Like you said)

But by design the ShareDataSet capture its children at mount time and it only register itself once with a given name... If the name of those ShareDataSet were different, it may actually work.

I'm still playing with different options but I wanted to share that now since I'm looking at it

@jourdain
Copy link
Collaborator

I'm waiting an update of vtk.js to go even further. But once available, I might be able to get things working...

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 19, 2021

Thanks for the update. I'm still experimenting around to see how to best approach this.

@jourdain
Copy link
Collaborator

There is a new react-vtk-js: "1.1.4" that we should update to. (I might not get to it today, feel free to do the update)
This will fix some webworker issue that you were not aware yet and cleanup other things.

The representation swap is still not working but the data swap is (even with the share dataset). In general, I'm not sure what is the idea of the rep swap.

@jourdain
Copy link
Collaborator

Actually I managed to do it and pushed it to master

commit 6e1d03320574ab0a292b50a0a284065726bcea95 (HEAD -> master, origin/master)
Author: Sebastien Jourdain <sebastien.jourdain@kitware.com>
Date:   Fri Feb 19 13:37:05 2021 -0700

    update to react-vtk-js 1.1.4

@xhluca
Copy link
Collaborator Author

xhluca commented Feb 19, 2021

Thanks!

@xhluca xhluca closed this as completed Feb 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants