parameters: (edges, iterations=1000, force_strength=5.0, dampening=0.01,
          max_velocity=2.0, max_distance=50, is_3d=True)
return_statement: return nodes
docstring: Runs a force-directed-layout algorithm on the input graph.
  
      iterations - Number of FDL iterations to run in coordinate generation
      force_strength - Strength of Coulomb and Hooke forces
                       (edit this to scale the distance between nodes)
      dampening - Multiplier to reduce force applied to nodes
      max_velocity - Maximum distance a node can move in one step
      max_distance - The maximum distance considered for interactions
docstring_summary: Runs a force-directed-layout algorithm on the input graph.
docstring_tokens: Runs a force - directed - layout algorithm on the input graph .
function: def run(edges, iterations=1000, force_strength=5.0, dampening=0.01,
          max_velocity=2.0, max_distance=50, is_3d=True):
      """Runs a force-directed-layout algorithm on the input graph.
  
      iterations - Number of FDL iterations to run in coordinate generation
      force_strength - Strength of Coulomb and Hooke forces
                       (edit this to scale the distance between nodes)
      dampening - Multiplier to reduce force applied to nodes
      max_velocity - Maximum distance a node can move in one step
      max_distance - The maximum distance considered for interactions
      """
  
      # Get a list of node ids from the edge data
      nodes = set(e['source'] for e in edges) | set(e['target'] for e in edges)
  
      # Convert to a data-storing object and initialize some values
      d = 3 if is_3d else 2
      nodes = {n: {'velocity': [0.0] * d, 'force': [0.0] * d} for n in nodes}
  
      # Repeat n times (is there a more Pythonic way to do this?)
      for _ in repeat(None, iterations):
  
          # Add in Coulomb-esque node-node repulsive forces
          for node1, node2 in combinations(nodes.values(), 2):
              _coulomb(node1, node2, force_strength, max_distance)
  
          # And Hooke-esque edge spring forces
          for edge in edges:
              _hooke(nodes[edge['source']], nodes[edge['target']],
                     force_strength * edge.get('size', 1), max_distance)
  
          # Move by resultant force
          for node in nodes.values():
              # Constrain the force to the bounds specified by input parameter
              force = [_constrain(dampening * f, -max_velocity, max_velocity)
                       for f in node['force']]
              # Update velocities and reset force
              node['velocity'] = [v + dv
                                  for v, dv in zip(node['velocity'], force)]
              node['force'] = [0] * d
  
      # Clean and return
      for node in nodes.values():
          del node['force']
          node['location'] = node['velocity']
          del node['velocity']
          # Even if it's 2D, let's specify three dimensions
          if not is_3d:
              node['location'] += [0.0]
      return nodes
function_tokens: def run ( edges , iterations = 1000 , force_strength = 5.0 , dampening = 0.01 , max_velocity = 2.0 , max_distance = 50 , is_3d = True ) : # Get a list of node ids from the edge data nodes = set ( e [ 'source' ] for e in edges ) | set ( e [ 'target' ] for e in edges ) # Convert to a data-storing object and initialize some values d = 3 if is_3d else 2 nodes = { n : { 'velocity' : [ 0.0 ] * d , 'force' : [ 0.0 ] * d } for n in nodes } # Repeat n times (is there a more Pythonic way to do this?) for _ in repeat ( None , iterations ) : # Add in Coulomb-esque node-node repulsive forces for node1 , node2 in combinations ( nodes . values ( ) , 2 ) : _coulomb ( node1 , node2 , force_strength , max_distance ) # And Hooke-esque edge spring forces for edge in edges : _hooke ( nodes [ edge [ 'source' ] ] , nodes [ edge [ 'target' ] ] , force_strength * edge . get ( 'size' , 1 ) , max_distance ) # Move by resultant force for node in nodes . values ( ) : # Constrain the force to the bounds specified by input parameter force = [ _constrain ( dampening * f , - max_velocity , max_velocity ) for f in node [ 'force' ] ] # Update velocities and reset force node [ 'velocity' ] = [ v + dv for v , dv in zip ( node [ 'velocity' ] , force ) ] node [ 'force' ] = [ 0 ] * d # Clean and return for node in nodes . values ( ) : del node [ 'force' ] node [ 'location' ] = node [ 'velocity' ] del node [ 'velocity' ] # Even if it's 2D, let's specify three dimensions if not is_3d : node [ 'location' ] += [ 0.0 ] return nodes