class_docstr: Dynamic graph layout during computation
  
  This assigns (x, y) locations to all tasks quickly and dynamically as new
  tasks are added.  This scales to a few thousand nodes.
  
  It is commonly used with distributed/dashboard/components/scheduler.py::TaskGraph, which
  is rendered at /graph on the diagnostic dashboard.
code: def transition(self, key, start, finish, *args, **kwargs):
      if finish != "forgotten":
          self.state_updates.append((self.index[key], finish))
      else:
          self.visible_updates.append((self.index[key], "False"))
          task = self.scheduler.tasks[key]
          for dep in task.dependents:
              edge = (key, dep.key)
              self.visible_edge_updates.append(
                  (self.index_edge.pop(edge), "False")
              )
          for dep in task.dependencies:
              self.visible_edge_updates.append(
                  (self.index_edge.pop((dep.key, key)), "False")
              )
  
          try:
              del self.collision[(self.x[key], self.y[key])]
          except KeyError:
              pass
  
          for collection in [self.x, self.y, self.index]:
              del collection[key]
  
file_path: distributed/distributed/diagnostics/graph_layout.py
imports: from __future__ import annotations
  import uuid
  from distributed.diagnostics.plugin import SchedulerPlugin
  from distributed.utils import TupleComparable
label_desc: Use image node_id 3 for calling the GraphLayout obj's underlying member method code with example usage: obj.transition(key, start, finish) without return types