plotly / dash-slicer

A volume slicer for Dash
https://dash.plotly.com/slicer
MIT License
24 stars 8 forks source link

Allow for negative spacing / stepsize #46

Open surchs opened 3 years ago

surchs commented 3 years ago

The spacing and origin arguments are used to allow the slices to be drawn in "scene space" rather than voxel space. This is a really useful feature. For example when displaying a brain volume, there is typically an affine matrix that translates voxel coordinates into some standard reference space (see e.g. here: https://nipy.org/nibabel/coordinate_systems.html).

One use case here would be to have a negative stepsize / spacing. I.e. walking along one volume axis would decrease the corresponding position in the standard / scene space. This is the case for example for some volume organizations of data in the MNI stereotaxic space, where the origin of the coordinate system (0, 0, 0) is by convention in the center of the brain (anterior commissure). Setting negative values for the origin works well, but at the moment, a negative spacing leads to odd behaviour of the slicers (outline traces are flipped outside, cross-linking positions doesn't seem to work correctly). edit: cross-linking positions is working with the sliders but does not work correctly when clicking.

import dash
from jupyter_dash import JupyterDash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State, ALL
from dash_slicer import VolumeSlicer

import imageio

app = JupyterDash(__name__)
server = app.server

vol = imageio.volread("imageio:stent.npz")
origin = [1000, -1000, 0]
spacing = [-1, 1, 1]

saggital_slicer = VolumeSlicer(app, vol, spacing=spacing, origin=origin, axis=0, scene_id="brain")
coronal_slicer = VolumeSlicer(app, vol, spacing=spacing, origin=origin, axis=1, scene_id="brain")
axial_slicer = VolumeSlicer(app, vol, spacing=spacing, origin=origin, axis=2, scene_id="brain")

slicer_list = []
for slicer in [saggital_slicer, coronal_slicer, axial_slicer]:
    slicer.graph.figure.update_layout(dragmode=False, plot_bgcolor="rgb(0, 0, 0)")
    slicer_list.append(html.Div([
        slicer.graph,
        html.Div(slicer.slider),#, style={"display": "none"}),
        *slicer.stores,
    ]))

style={
        "display": "grid",
        "gridTemplateColumns": "33% 33% 33%",
    }
app.layout = html.Div(style=style, children=slicer_list)

app.run_server(debug=True, dev_tools_props_check=False, mode="jupyterlab")

This is probably not a high priority feature but could be nice to have.

almarklein commented 3 years ago

A negative spacing would mean that the image is flipped for that axis, right? I don't think that is happening with the given example. I I don't think we can tell the image trace to flip the image, so we'd have to flip it server-side. This might be easier to look at once we had a go at #43, which is a bit similar in where changes would be needed.

surchs commented 3 years ago

Yeah, I think you are right. I will make an example later with an actual brain image where this is the case!