Powered by AppSignal & Oban Pro

Object Constancy

06_object_constancy.livemd

Object Constancy

Mix.install([
  {:plotly_ex, "~> 0.3"},
  {:kino, "~> 0.18"}
])

Section

When bars/markers animate between frames, Plotly.js transitions each visual element by matching it to the same position in the data array. Without ids, elements are matched by array index — which can cause incorrect transitions when data is reordered.

Setting ids: on traces gives each element a stable identity across frames, ensuring each bar/marker smoothly transitions to its new value regardless of order.

alias Plotly.{Figure, Bar}

:rand.seed(:exsplus, {1, 2, 3})
categories = ~w[Alpha Beta Gamma Delta Epsilon]

# Frames with ids: each category tracks its own bar through reordering
frames_with_id =
  for step <- 1..5 do
    vals = Enum.map(categories, fn _ -> :rand.uniform(100) end)
    sorted = Enum.sort_by(Enum.zip(categories, vals), &elem(&1, 1), :desc)
    {sorted_c, sorted_v} = Enum.unzip(sorted)
    %{name: "step#{step}", data: [%{x: sorted_c, y: sorted_v, ids: sorted_c}]}
  end

Figure.new(
  data: [Bar.new(x: categories, y: [50, 60, 40, 80, 30], ids: categories)],
  layout: %{
    title: "Object Constancy via ids: — bars track their category through reordering",
    updatemenus: [%{
      type: "buttons",
      buttons: [%{
        label: "▶ Animate",
        method: "animate",
        args: [nil, %{frame: %{duration: 800}, transition: %{duration: 600, easing: "cubic-in-out"}}]
      }]
    }]
  },
  frames: frames_with_id
)
|> Plotly.show()