docs: def from_dict(cls, data: Dict, lambdas):
          """Builds a GrFN object from a set of extracted function data objects
          and an associated file of lambda functions.
  
          Args:
              cls: The class variable for object creation.
              data: A set of function data object that specify the wiring of a
                    GrFN object.
              lambdas: [Module] A python module containing actual python
                       functions to be computed during GrFN execution.
  
          Returns:
              A GroundedFunctionNetwork object.
  
          """
          functions = {d["name"]: d for d in data["functions"]}
          G = nx.DiGraph()
          scope_tree = nx.DiGraph()
  
          def add_variable_node(
              basename: str, parent: str, index: int, is_loop_index: bool = False
          ):
              G.add_node(
                  f"{parent}::{basename}_{index}",
                  type="variable",
                  color="maroon",
                  parent=parent,
                  label=f"{basename}_{index}",
                  basename=basename,
                  is_loop_index=is_loop_index,
                  padding=15,
                  value=None,
              )
  
          def find_correct_scope(cur_scope, var_name):
              if cur_scope.parent is None:
                  return cur_scope.name, -1
  
              new_scope = cur_scope.parent
  
              if var_name in new_scope.variables:
                  return new_scope.name, new_scope.variables[var_name]
              else:
                  return find_correct_scope(new_scope, var_name)
  
          def process_container(
              scope, loop_index_variable: Optional[str] = None
          ):
              for stmt in scope.body:
                  if "name" in stmt:
                      stmt_type = functions[stmt["name"]]["type"]
                      if stmt_type in ("assign", "condition", "decision"):
                          if stmt_type == "assign":
                              if "body" in functions[stmt["name"]]:
                                  stmt_type = "literal"
  
                          output = stmt["output"]
                          scope.variables[output["variable"]] = output["index"]
                          add_variable_node(
                              output["variable"], scope.name, output["index"]
                          )
                          G.add_edge(
                              stmt["name"],
                              f"{scope.name}::{output['variable']}_{output['index']}",
                          )
  
                          ordered_inputs = list()
                          for input in stmt.get("input", []):
                              parent = scope.name
                              index = input["index"]
                              base_name = input["variable"]
                              if (
                                  index == -1
                                  and base_name != loop_index_variable
                              ):
                                  parent, index = find_correct_scope(
                                      scope, base_name
                                  )
  
                              add_variable_node(
                                  base_name,
                                  parent,
                                  index,
                                  base_name == loop_index_variable,
                              )
                              node_name = f"{parent}::{base_name}_{index}"
                              ordered_inputs.append(node_name)
                              G.add_edge(node_name, stmt["name"])
  
                          G.add_node(
                              stmt["name"],
                              type="function",
                              lambda_fn=getattr(lambdas, stmt["name"]),
                              func_inputs=ordered_inputs,
                              shape="rectangle",
                              parent=scope.name,
                              label=stmt_type[0].upper(),
                              padding=10,
                          )
  
                      elif stmt_type == "loop_plate":
                          index_variable = functions[stmt["name"]][
                              "index_variable"
                          ]
                          scope_tree.add_node(stmt["name"], color="blue")
                          scope_tree.add_edge(scope.name, stmt["name"])
                          new_scope = ScopeNode(
                              functions[stmt["name"]], parent=scope
                          )
                          process_container(
                              new_scope, loop_index_variable=index_variable
                          )
                      else:
                          pass
                  elif "function" in stmt and stmt["function"] != "print":
                      scope_tree.add_node(stmt["function"], color="green")
                      scope_tree.add_edge(scope.name, stmt["function"])
                      new_scope = ScopeNode(
                          functions[stmt["function"]], parent=scope
                      )
                      process_container(new_scope)
  
          root = data["start"]
          scope_tree.add_node(root, color="green")
          cur_scope = ScopeNode(functions[root])
          process_container(cur_scope)
          return cls(G, scope_tree)