Hello,
I’m trying to make a plot where I have two sliders that filter on a single plot. The data is a video sequence that is generated from a ML model and is a 4-d tensor, where the dimensions are Epoch x Frame x Height x Width. Ideally, I want to have one slider over Epoch to see how each frame evolves as the ML model evolves, and another to see the animation play out.
I’m stuck with this so far:
# Epoch x Simulation Frame x Channel x Height x Width
# The first epoch is the sanity check, so we remove it.
render_comparison_per_epoch_np = np.stack(
self.render_comparison_per_epoch[1:])
# Epoch x Simulation Frame x Height x Width
render_comparison_per_epoch_np_one_channel = np.mean(
render_comparison_per_epoch_np, axis=2)
dimensions = render_comparison_per_epoch_np_one_channel.shape
dimensions_epoch = dimensions[0]
dimensions_frame = dimensions[1]
fig = go.Figure()
for epoch_index in range(dimensions_epoch):
for frame_index in range(dimensions_frame):
fig.add_trace(
go.Heatmap(
z=render_comparison_per_epoch_np_one_channel[
# Heatmap is flipped on the y-axis, so we flip it back.
epoch_index, frame_index, ::-1, :],
colorscale="Viridis",
showscale=False,
name=f"Epoch {epoch_index}"))
fig.data[0].visible = True # type: ignore
steps_epoch = []
steps_frame = []
for index_epoch in range(dimensions_epoch): # type: ignore
for index_frame in range(dimensions_frame): # type: ignore
step = dict(
method="update",
args=[
{
"visible": [False] * len(fig.data) # type: ignore
},
{
"title": f"Epoch {index_epoch}, Frame {index_frame}"
}
], # layout attribute
)
step["args"][0]["visible"][index_epoch * dimensions_epoch +
index_frame] = True
steps_epoch.append(step)
sliders = [
dict(
active=10,
currentvalue={"prefix": "Epoch: "},
pad={"t": 50},
steps=steps_epoch,
),
dict(
active=10,
currentvalue={"prefix": "Frame: "},
pad={"t": 150},
steps=steps_frame,
)
]
fig.update_layout(sliders=sliders,)
# Convert to html
fig.write_html("render_comparison.html")
wandb.log(
{"simulation_render_per_epoch": wandb.Html("render_comparison.html")})
I am stuck because I do not see a way to do the following:
- first slider specify which epoch to display, so ideally it creates an array of boolean where each index that corresponds to the epoch is set to True. Practically this means a contiguous region in the visible array is set to True
- second slider specify which frame to display, so a boolean array where the specified frame of each contiguous region is set to True
For example, if #epoch = 2 and #frame = 4, I’d have an array of 8 boolean values.
If I want to see the first epoch, the boolean array that the epoch slider generates would be: [True, True, True, True, False, False, False, False]
If I want to see the second frame, I’d have this array: [False, True, False, False, False, True, False, False]
Then to see the image that I want, I’d get the intersection: [False, True, False, False, False, False, False, False]
And use that as the value to the “visible” key.
Though that would require the slider to have some intermediate logic before displaying, which I do not know how to achieve.
Any ideas?