parameters: (string_graph, read_nicknames)
return_statement: return unitig_graph
docstring: Creates a unitig graph from a string graph. In essence, reimplements make_unitig_graph function
      in miniasm. Assumes that branching paths have already been removed from the string graph.
docstring_summary: Creates a unitig graph from a string graph. In essence, reimplements make_unitig_graph function
      in miniasm. Assumes that branching paths have already been removed from the string graph.
docstring_tokens: Creates a unitig graph from a string graph . In essence reimplements make_unitig_graph function in miniasm . Assumes that branching paths have already been removed from the string graph .
function: def merge_string_graph_segments_into_unitig_graph(string_graph, read_nicknames):
      """
      Creates a unitig graph from a string graph. In essence, reimplements make_unitig_graph function
      in miniasm. Assumes that branching paths have already been removed from the string graph.
      """
      log.log('', verbosity=2)
      unitig_sequences = []
      for component in string_graph.get_connected_components():
          segments_with_dead_ends = []
          for seg_name in component:
              pos_seg_name = seg_name + '+'
              neg_seg_name = seg_name + '-'
              if not string_graph.get_preceding_segments(pos_seg_name):
                  segments_with_dead_ends.append(pos_seg_name)
              if not string_graph.get_following_segments(pos_seg_name):
                  segments_with_dead_ends.append(neg_seg_name)
  
          # We should have found either two dead ends (for a linear unitig) or zero dead ends (for a
          # circular unitig).
          assert len(segments_with_dead_ends) == 2 or len(segments_with_dead_ends) == 0
          circular = len(segments_with_dead_ends) == 0
  
          # If the unitig is circular, then we could start anywhere, so we'll choose the biggest
          # segment (positive strand).
          if circular:
              start_seg_name = sorted(component,
                                      key=lambda x: string_graph.segments[x].get_length())[0] + '+'
  
          # If the unitig is linear, then we have two possible starting locations. For consistency,
          # we'll take the larger of the two.
          else:
              option_1 = string_graph.segments[get_unsigned_seg_name(segments_with_dead_ends[0])]
              option_2 = string_graph.segments[get_unsigned_seg_name(segments_with_dead_ends[1])]
              if option_1.get_length() >= option_2.get_length():
                  start_seg_name = segments_with_dead_ends[0]
              else:
                  start_seg_name = segments_with_dead_ends[1]
  
          # Now we can build the unitig sequence by following the graph outward from the starting
          # segment, always trimming overlaps from the end of segments.
          unitig_seq = ''
          current_seg = start_seg_name
          name_list = []
          while True:
              name_list.append(get_string_graph_segment_nickname(current_seg, read_nicknames))
              current_seq = string_graph.seq_from_signed_seg_name(current_seg)
              next_seg = string_graph.get_following_segments(current_seg)
              if circular:
                  assert len(next_seg) == 1  # no dead ends in circular unitigs
              if len(next_seg) == 0:  # no next segment means we've hit the end of a linear unitig
                  unitig_seq += current_seq
                  break
              else:
                  assert len(next_seg) == 1
                  overlap = string_graph.links[(current_seg, next_seg[0])].seg_1_overlap
                  if overlap == 0:  # I don't think this will happen...
                      unitig_seq += current_seq
                  else:
                      unitig_seq += current_seq[:-overlap]
              if circular and next_seg[0] == start_seg_name:  # don't loop endlessly in a circle
                  break
              current_seg = next_seg[0]
  
          arrow = ' ' + get_right_arrow() + ' '
          if circular:
              unitig_sequences.append((unitig_seq, 'circular'))
              log.log(bold('Circular unitig: ') + arrow.join(name_list), verbosity=2)
          else:
              unitig_sequences.append((unitig_seq, 'linear'))
              log.log(bold('Linear unitig: ') + arrow.join(name_list), verbosity=2)
          log.log('', verbosity=2)
  
      # Build and return the unitig graph using the sequences we just made.
      unitig_sequences = sorted(unitig_sequences, key=lambda x: len(x[0]), reverse=True)
      unitig_graph = StringGraph(None)
      for i, unitig_sequence in enumerate(unitig_sequences):
          unitig_seq, circular_or_linear = unitig_sequence
          unitig_name = str(i+1)
          pos_unitig_name = unitig_name + '+'
          unitig_graph.segments[unitig_name] = StringGraphSegment(unitig_name, unitig_seq)
          if circular_or_linear == 'circular':
              unitig_graph.add_link(pos_unitig_name, pos_unitig_name, 0, 0)
      return unitig_graph
function_tokens: def merge_string_graph_segments_into_unitig_graph ( string_graph , read_nicknames ) : log . log ( '' , verbosity = 2 ) unitig_sequences = [ ] for component in string_graph . get_connected_components ( ) : segments_with_dead_ends = [ ] for seg_name in component : pos_seg_name = seg_name + '+' neg_seg_name = seg_name + '-' if not string_graph . get_preceding_segments ( pos_seg_name ) : segments_with_dead_ends . append ( pos_seg_name ) if not string_graph . get_following_segments ( pos_seg_name ) : segments_with_dead_ends . append ( neg_seg_name ) # We should have found either two dead ends (for a linear unitig) or zero dead ends (for a # circular unitig). assert len ( segments_with_dead_ends ) == 2 or len ( segments_with_dead_ends ) == 0 circular = len ( segments_with_dead_ends ) == 0 # If the unitig is circular, then we could start anywhere, so we'll choose the biggest # segment (positive strand). if circular : start_seg_name = sorted ( component , key = lambda x : string_graph . segments [ x ] . get_length ( ) ) [ 0 ] + '+' # If the unitig is linear, then we have two possible starting locations. For consistency, # we'll take the larger of the two. else : option_1 = string_graph . segments [ get_unsigned_seg_name ( segments_with_dead_ends [ 0 ] ) ] option_2 = string_graph . segments [ get_unsigned_seg_name ( segments_with_dead_ends [ 1 ] ) ] if option_1 . get_length ( ) >= option_2 . get_length ( ) : start_seg_name = segments_with_dead_ends [ 0 ] else : start_seg_name = segments_with_dead_ends [ 1 ] # Now we can build the unitig sequence by following the graph outward from the starting # segment, always trimming overlaps from the end of segments. unitig_seq = '' current_seg = start_seg_name name_list = [ ] while True : name_list . append ( get_string_graph_segment_nickname ( current_seg , read_nicknames ) ) current_seq = string_graph . seq_from_signed_seg_name ( current_seg ) next_seg = string_graph . get_following_segments ( current_seg ) if circular : assert len ( next_seg ) == 1 # no dead ends in circular unitigs if len ( next_seg ) == 0 : # no next segment means we've hit the end of a linear unitig unitig_seq += current_seq break else : assert len ( next_seg ) == 1 overlap = string_graph . links [ ( current_seg , next_seg [ 0 ] ) ] . seg_1_overlap if overlap == 0 : # I don't think this will happen... unitig_seq += current_seq else : unitig_seq += current_seq [ : - overlap ] if circular and next_seg [ 0 ] == start_seg_name : # don't loop endlessly in a circle break current_seg = next_seg [ 0 ] arrow = ' ' + get_right_arrow ( ) + ' ' if circular : unitig_sequences . append ( ( unitig_seq , 'circular' ) ) log . log ( bold ( 'Circular unitig: ' ) + arrow . join ( name_list ) , verbosity = 2 ) else : unitig_sequences . append ( ( unitig_seq , 'linear' ) ) log . log ( bold ( 'Linear unitig: ' ) + arrow . join ( name_list ) , verbosity = 2 ) log . log ( '' , verbosity = 2 ) # Build and return the unitig graph using the sequences we just made. unitig_sequences = sorted ( unitig_sequences , key = lambda x : len ( x [ 0 ] ) , reverse = True ) unitig_graph = StringGraph ( None ) for i , unitig_sequence in enumerate ( unitig_sequences ) : unitig_seq , circular_or_linear = unitig_sequence unitig_name = str ( i + 1 ) pos_unitig_name = unitig_name + '+' unitig_graph . segments [ unitig_name ] = StringGraphSegment ( unitig_name , unitig_seq ) if circular_or_linear == 'circular' : unitig_graph . add_link ( pos_unitig_name , pos_unitig_name , 0 , 0 ) return unitig_graph