code: def build_pydot(self,G): # pragma: no cover
          
          import pydot
          node = pydot.Node(id(self), shape='trapezium', label=self.name)#, fontcolor='white', color='white')
          G.add_node(node)
          for _, o, _ in self.observers:
              label = o.name if hasattr(o, 'name') else str(o)
              observed_node = pydot.Node(id(o), label=label)
              if str(id(o)) not in G.obj_dict['nodes']: # pragma: no cover
                  G.add_node(observed_node)
              edge = pydot.Edge(str(id(self)), str(id(o)), color='darkorange2', arrowhead='vee')
              G.add_edge(edge)
  
          return node
docs: Build a pydot representation of this model. This needs pydot installed.
  
          Example Usage:
  
          np.random.seed(1000)
          X = np.random.normal(0,1,(20,2))
          beta = np.random.uniform(0,1,(2,1))
          Y = X.dot(beta)
          m = RidgeRegression(X, Y)
          G = m.build_pydot()
          G.write_png('example_hierarchy_layout.png')
  
          The output looks like:
  
          .. image:: example_hierarchy_layout.png
  
          Rectangles are parameterized objects (nodes or leafs of hierarchy).
  
          Trapezoids are param objects, which represent the arrays for parameters.
  
          Black arrows show parameter hierarchical dependence. The arrow points
          from parents towards children.
  
          Orange arrows show the observer pattern. Self references (here) are
          the references to the call to parameters changed and references upwards
          are the references to tell the parents they need to update.