code: def formula_to_string(formula):
      def _to_string(formula, root):
          # If there are no children, this is a variable node.
          label = formula.nodes[root]["label"]
          if not formula[root]:
              return label
          # Otherwise, this is an operator.
          children = formula[root]
          # If one child, the label must be a NOT operator.
          if len(children) == 1:
              child = nx.utils.arbitrary_element(children)
              return f"{label}({_to_string(formula, child)})"
          # NB "left" and "right" here are a little misleading: there is
          # no order on the children of a node. That's okay because the
          # Boolean AND and OR operators are symmetric. It just means that
          # the order of the operands cannot be predicted and hence the
          # function does not necessarily behave the same way on every
          # invocation.
          left, right = formula[root]
          left_subformula = _to_string(formula, left)
          right_subformula = _to_string(formula, right)
          return f"({left_subformula} {label} {right_subformula})"
  
      root = next(v for v, d in formula.in_degree() if d == 0)
      return _to_string(formula, root)
  
imports: import matplotlib.pyplot
  import networkx
label_desc: Use image node_id 2 for calling a global function with example usage: formula_to_string(formula) and returns: _to_string, str, left_subformula, str, label, str, right_subformula, str, label, label, str, _to_string, str