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 update_graph(
      self,
      scheduler,
      *,
      dependencies=None,
      priority=None,
      tasks=None,
      **kwargs,
  ):
      stack = sorted(
          tasks,
          key=lambda k: TupleComparable(priority.get(k, 0)),
          reverse=True,
      )
      while stack:
          key = stack.pop()
          if key in self.x or key not in scheduler.tasks:
              continue
          deps = dependencies.get(key, ())
          if deps:
              if not all(dep in self.y for dep in deps):
                  stack.append(key)
                  stack.extend(
                      sorted(
                          deps,
                          key=lambda k: TupleComparable(
                              priority.get(k, 0)
                          ),
                          reverse=True,
                      )
                  )
                  continue
              else:
                  total_deps = sum(
                      len(scheduler.tasks[dep].dependents)
                      for dep in deps
                  )
                  y = sum(
                      self.y[dep]
                      * len(scheduler.tasks[dep].dependents)
                      / total_deps
                      for dep in deps
                  )
                  x = max(self.x[dep] for dep in deps) + 1
          else:
              x = 0
              y = self.next_y
              self.next_y += 1
  
          if (x, y) in self.collision:
              old_x, old_y = x, y
              x, y = self.collision[(x, y)]
              y += 0.1
              self.collision[old_x, old_y] = (x, y)
          else:
              self.collision[(x, y)] = (x, y)
  
          self.x[key] = x
          self.y[key] = y
          self.index[key] = self.next_index
          self.next_index = self.next_index + 1
          self.new.append(key)
          for dep in deps:
              edge = (dep, key)
              self.index_edge[edge] = self.next_edge_index
              self.next_edge_index += 1
              self.new_edges.append(edge)
  
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 2 for calling the GraphLayout obj's underlying member method code with example usage: obj.update_graph(scheduler) without return types