Volume frames (4D slices)

Can this example be adapted to show 3D slices instead of 2D? I tried replacing Surface with Volume:

a, b, c = data.shape[1:]  # data.ndim == 4
X, Y, Z = np.mgrid[-1:1:a*1j, -1:1:b*1j, -1:1:c*1j]

fig = go.Figure(frames=[go.Frame(data=go.Volume(
    x=X.flatten(),
    y=Y.flatten(),
    z=Z.flatten(),
    value=data[k].flatten(),
    opacity=.25,
    surface_count=12,
    colorscale='jet',
    ), name=str(k)) for k in range(len(data))])

and Volume works fine on its own, but I get empty frames with above. (Cross-posted.)

@OverLordGoldDragon

The animation frames must update fig.data[0], but you did not define an initial volume as fig.data[0]. Moreover, the frames update only the attribute values that are changing from frame to frame.

import numpy as np
import plotly.graph_objects as go

vol4 =np.random.randint(0, 27, size=(6, 5, 7, 4))

a, b, c = vol4.shape[1:]
X, Y, Z = np.mgrid[-1:1:a*1j, -1:1:b*1j, -1:1:c*1j]

fig = go.Figure(go.Volume(x=X.flatten(),
                          y=Y.flatten(),
                          z=Z.flatten(),
                          value=vol4[0].flatten(),
                          opacity=.25,
                          surface_count=12,
                          colorscale='turbo',
                          colorbar_len=0.8
    ))

frames=[go.Frame(data=go.Volume(
                               value=vol4[k].flatten()), 
                 name=str(k)) for k in range(len(vol4))]
updatemenus = [dict(
        buttons = [
            dict(
                args = [None, {"frame": {"duration": 100, "redraw": True},
                                "fromcurrent": True, "transition": {"duration": 0}}],
                label = "Play",
                method = "animate"
                ),
            dict(
                 args = [[None], {"frame": {"duration": 0, "redraw": False},
                                  "mode": "immediate",
                                  "transition": {"duration": 0}}],
                label = "Pause",
                method = "animate"
                )
        ],
        direction = "left",
        pad = {"r": 10, "t": 87},
        showactive = False,
        type = "buttons",
        x = 0.21,
        xanchor = "right",
        y = -0.075,
        yanchor = "top"
    )] 

sliders = [dict(steps = [dict(method= 'animate',
                              args= [[f'{k}'],                           
                              dict(mode= 'immediate',
                                   frame= dict(duration=100, redraw=True),
                                   transition=dict(duration= 0))
                                 ],
                              label=f'{k+1}'
                             ) for k in range(len(vol4))], 
                active=0,
                transition= dict(duration= 0 ),
                x=0, # slider starting position  
                y=0, 
                currentvalue=dict(font=dict(size=12), 
                                  prefix='frame: ', 
                                  visible=True, 
                                  xanchor= 'center'
                                 ),  
                len=1.0) #slider length
           ]

fig.update_layout(width=700, height=700, updatemenus=updatemenus, sliders=sliders)
fig.update(frames=frames)

LE I updated button position in updatemenus, and defined the sliders.

1 Like

Excellent, thank you. Could you include the sliders? I can’t seem to easily adapt it from here.

@OverLordGoldDragon I updated the initial code.

1 Like

Thanks again. Would help others to include in standard examples.

(P.S. think it should be for k in range(len(vol4)) for sliders)

  Yes, you are right. I've corrected it.