dash-vtk: Re-rendering is broken when ImageData remains the same but child changes

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()

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 18

Most upvoted comments

Thanks I’m going to look at the ShareDataSet part…