code: def generate_graph_specification(
      model_relations: dict, render_params: bool = False
  ) -> dict:
      """
      Convert model relations into data structure which can be readily
      converted into a network.
      """
      # group nodes by plate
      plate_groups = dict(model_relations["plate_sample"])
      plate_rvs = {rv for rvs in plate_groups.values() for rv in rvs}
      plate_groups[None] = [
          rv
          for rv in model_relations["sample_sample"]
          if rv not in plate_rvs
      ]  # RVs which are in no plate
  
      # get set of params
      params = set()
      if render_params:
          for rv, params_list in model_relations[
              "sample_param"
          ].items():
              for param in params_list:
                  params.add(param)
          plate_groups[None].extend(params)
  
      # retain node metadata
      node_data = {}
      for rv in model_relations["sample_sample"]:
          node_data[rv] = {
              "is_observed": rv in model_relations["observed"],
              "distribution": model_relations["sample_dist"][rv],
          }
  
      if render_params:
          for param, constraint in model_relations[
              "param_constraint"
          ].items():
              node_data[param] = {
                  "is_observed": False,
                  "constraint": constraint,
                  "distribution": None,
              }
  
      # infer plate structure
      # (when the order of plates cannot be determined from subset relations,
      # it follows the order in which plates appear in trace)
      plate_data = {}
      for plate1, plate2 in list(
          itertools.combinations(plate_groups, 2)
      ):
          if plate1 is None or plate2 is None:
              continue
  
          nodes1 = set(plate_groups[plate1])
          nodes2 = set(plate_groups[plate2])
          if nodes1 < nodes2:
              plate_data[plate1] = {"parent": plate2}
          elif nodes1 >= nodes2:
              plate_data[plate2] = {"parent": plate1}
          elif nodes1 & nodes2:
              raise NotImplementedError(
                  f"Overlapping non-nested plates {repr(plate1)},{repr(plate2)} "
                  "are not supported by render_model(). To help add support see "
                  "https://github.com/pyro-ppl/pyro/issues/2980"
              )
  
      for plate in plate_groups:
          if plate is None:
              continue
  
          if plate not in plate_data:
              plate_data[plate] = {"parent": None}
  
      # infer RV edges
      edge_list = []
      for target, source_list in model_relations[
          "sample_sample"
      ].items():
          edge_list.extend([(source, target) for source in source_list])
  
      if render_params:
          for target, source_list in model_relations[
              "sample_param"
          ].items():
              edge_list.extend(
                  [(source, target) for source in source_list]
              )
  
      return {
          "plate_groups": plate_groups,
          "plate_data": plate_data,
          "node_data": node_data,
          "edge_list": edge_list,
      }
  
imports: import itertools
  import os
  from collections import defaultdict
  from pathlib import Path
  from types import SimpleNamespace
  from typing import Callable, Collection, Dict, List, Optional, Union
  import torch
  import pyro
  import pyro.distributions
  import pyro.poutine
  from pyro.ops.provenance import ProvenanceTensor, detach_provenance, get_provenance
  from pyro.poutine.messenger import Messenger
  from pyro.poutine.util import site_is_subsample
label_desc: Use image node_id 6 for calling a global function with example usage: generate_graph_specification(model_relations, render_params) and returns: dict