def phylogeny(sequences=None, project_dir=None, name=None, aln_file=None, tree_file=None,
        seq_field=None, name_field=None, aa=False, species='human', unrooted=False, ladderize=True,
        root=None, root_name=None, show_root_name=False, color_dict=None, color_function=None,
        order_dict=None, order_function=None, color_node_labels=False, label_colors=None,
        scale=None, branch_vert_margin=None, fontsize=12, show_names=True, show_scale=False,
        mirror=False, min_order_fraction=0.1, figname_prefix=None, figname_suffix=None,
        # linked_alignment=None, alignment_fontsize=11, alignment_height=50, alignment_width=50, 
        compact_alignment=False, scale_factor=1, rename_function=None, linewidth=1.0,
        delete_nodes=None, quiet=True):
    '''
    Generates a lineage phylogeny figure.

    Args:

        sequences (list(Sequence)): A list of ``Sequence`` objects from which a phylogeny
            will be calculated. Strictly speaking, they do not need to be ``Sequence`` objects,
            rather, any object that contains the sequence name as the ``id`` attribute (or
            by dictionary-style lookup using the provided ``name_field``) and contains the
            sequence as the ``sequence`` attribute (or by dictionary-stype lookup using the
            provided ``seq_field``).

        project_dir (str): directory into which all phylogeny files will be deposited,
            including alignment, tree and figure files.

        name (str): Name to be used for naming alignment, tree, and phylogeny files. If not
            provided, a random name will be generated.

        aln_file (str): if a multiple sequence alignment has already been calculated,
            passing the path to the alignment file (in FASTA format) will force Lineage.phylogeny()
            to use the supplied msa instead of computing a new one.

        tree_file (str): if a tree file has already been calculated, passing the path
            to the pre-computed tree file will force ``phylogeny()`` to use
            the supplied tree file instead of computing a new one. It is important to note that
            only sequence names will be parsed from the tree_file, so if ``order_function`` or
            ``color_function`` is also provided, ensure that these functions only require the
            sequence ID rather than the entire sequence.

        aa (bool): if True, use amino acid sequences to compute the phylogeny.
            Default is False.

        root (Sequence, str: The root can be provided either as a ``Sequence`` object (if ``sequences``
            are being provided) or as the name of a sequence that can be found either in
            ``sequences`` or in the provided ``aln_file`` or ``tree_file``. Note that if
            either ``aln_file`` or ``tree_file`` are provided, the root must be provided
            as the sequence name, not as a ``Sequence`` object (as the root sequence must
            already be included in either ``aln_file`` or ``tree_file``. If the root is not
            provided, the germline V-gene sequence of the

        color_dict (dict): Dictionary with sequence IDs as keys and colors (hex format) as values. If any
            sequence IDs are not found in the dict, they will be colored black. If neither ``color_dict`` nor
            ``color_function`` is provided, all leaves will be colored black.

        color_function (func): Function that that accepts a ``Sequence`` object and returns the color
            (as a hex code). If ``color_dict`` is also provided, ``color_function`` is ignored. Additionally,
            ``color_function`` will only be used if ``sequences`` are provided. If ``sequences`` are not provided
            (instead using ``aln_file` or ``tree_file``), ``color_dict`` must be used instead of ``color_function``.

        orders: a dictionary with sequence IDs as keys and orders (integers) as values.
            If not provided, only the leaf branches will be colored (if <colors> or
            <color_function> is provided).

        chain: build a phylogeny using the given chain ('heavy' or 'light').
            Default is 'heavy'.

        filter_function: function used to filter sequences (identity-based clustering, for
            example). The function should accept a list of Sequence objects and return
            a list of Sequence objects.

        just_pairs: if True, compute the phylogeny using only paired sequences.
            Default (False) will use all sequences of the appropriate chain, paired or not.

        scale (float): passed to ete3.TreeStyle() to set the scale of the tree figure. Increased
            scale results in a wider tree.

        branch_vert_margin (int): passed to ete3.TreeStyle() to set the branch_vertical_margin of
            the tree figure. Increased branch_vert_margin results in a taller tree.

        fontsize: size of the leaf labels. Default is 12.

        show_names: show names of leaf nodes. Options are True (show labels for all leaf nodes),
            False (don't show labels for any leaf nodes) or a list of sequence IDs for which
            labels should be shown. Default is True.

        mirror: flip the orientation of the tree. Default is to draw the tree from left to right.
            Setting mirror to True results in the tree being drawn from right to left.

        min_order_fraction: minimum fraction of downstream leaves requried to color a branch.
            When coloring non-leaf nodes, the earliest 'order' with at least <min_order_fraction>
            leaf nodes is used. Default is 0.1 (which corresponds to 10%).

        figname_prefix: by default, figures will be named <lineage_id>.pdf. If prefix='prefix_' and
            the lineage ID is 'ABC123', the figure file will be named 'prefix_ABC123.pdf'.

        figname_suffix: by default, figures will be named <lineage_id>.pdf. If suffix='_suffix' and
            the lineage ID is 'ABC123', the figure file will be named 'ABC123_suffix.pdf'.
    '''

    if project_dir is None:
        print('\nERROR: project_dir is required\n')
        sys.exit(1)
    else:
        project_dir = os.path.abspath(project_dir)

    # make a name if one isn't provided
    if name is None:
        name = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8))

    # if sequences are provided, need to process them
    if sequences is not None and all([arg is None for arg in [aln_file, tree_file]]):
        sequences = deepcopy(sequences)
        root = copy(root)

        # if custom seq_field is specified, copy to the .sequence attribute
        if seq_field is not None:
            if not all([seq_field in list(s.annotations.keys()) for s in sequences]):
                print('\nERROR: {} is not present in all of the supplied sequences.\n'.format(seq_field))
                sys.exit(1)
            for s in sequences:
                s.alignment_sequence = s[seq_field]
        else:
            for s in sequences:
                s.alignment_sequence = s.sequence

        # if custom name_field is specified, copy to the .id attribute
        if name_field is not None:
            if not all([name_field in list(s.annotations.keys()) for s in sequences]):
                print('\nERROR: {} is not present in all of the supplied sequences.\n'.format(name_field))
                sys.exit(1)
            for s in sequences:
                s.alignment_id = s[name_field]
        else:
            for s in sequences:
                s.alignment_id = s.id

        # parse the root sequence
        if unrooted:
            root = None
            root_name = None
        elif root is None:
            if not quiet:
                print('\nRoot sequence was was not provided. Using the germline V-gene.')
            if not all(['v_gene' in list(s.annotations.keys()) for s in sequences]):
                print('\nInput sequences to not appear to be AbStar annotated. Annotating now...')
                sequences = abstar.run(*[(s.id, s.sequence) for s in sequences])
                print('Done.')
            if not all(['full' in list(s['v_gene'].keys()) for s in sequences]):
                print('\nInput sequences to not appear to be AbStar annotated. Annotating now...')
                sequences = abstar.run(*[(s.id, s.sequence) for s in sequences])
                print('Done.')
            top_vgene = sorted(list(Counter([s['v_gene']['full'] for s in sequences]).items()),
                               key=lambda x: x[1],
                               reverse=True)[0][0]
            vgene = get_imgt_germlines(species, 'V', gene=top_vgene)
            if aa:
                root = Sequence(vgene.ungapped_aa_sequence, id=top_vgene)
            else:
                root = Sequence(vgene.ungapped_nt_sequence, id=top_vgene)
            root.alignment_id = root.id
            root.alignment_sequence = root.sequence
            if not quiet:
                print('Top V-gene: {}'.format(root.alignment_id))
                print(root.alignment_sequence)
        elif type(root) in STR_TYPES:
            root = [s for s in sequences if s.alignment_id == root][0]
            if not root:
                print('\nERROR: The name of the root sequence ({}) was not found in the list of input sequences.'.format(root))
                print('\n')
                sys.exit(1)
            sequences = [s for s in sequences if s.alignment_id != root.alignment_id]
        elif type(root) == Sequence:
            if seq_field is not None:
                if seq_field not in list(root.anotations.keys()):
                    print('\nERROR: {} is not present in the supplied root sequence.\n'.format(seq_field))
                    sys.exit(1)
                root.alignment_sequence = root[seq_field]
            if name_field is not None:
                if name_field not in list(root.anotations.keys()):
                    print('\nERROR: {} is not present in the supplied root sequence.\n'.format(name_field))
                    sys.exit(1)
                root.alignment_id = root[name_field]
            sequences = [s for s in sequences if s.alignment_id != root.alignment_id]
        else:
            print('\nERROR: If root is provided, it must be the name of a sequence \
            found in the supplied list of sequences or it must be a Sequence object.')
            print('\n')
            sys.exit(1)
        if not unrooted:
            if root_name is not None:
                root.alignment_id = root_name
            else:
                root_name = root.alignment_id
            sequences.append(root)

    # parse sequences from aln_file, if provided
    elif aln_file is not None:
        if not unrooted and type(root) not in STR_TYPES:
            print('\nERROR: If providing an aln_file, the name of the root sequence must \
            be provided (as a string) using the root keyword argument')
            print('\n')
            sys.exit(1)
        _sequences = []
        _root = None
        for rec in AlignIO.read(open(aln_file), 'fasta'):
            s = str(rec.seq).replace('-', '')
            if rec.id == root:
                _root = Sequence(s, rec.id)
                _root.alignment_id = _root.id
            else:
                _s = Sequence(s, id=rec.id)
                _s.alignment_id = rec.id
                _sequences.append(_s)
        if sequences is None:
            sequences = _sequences
        else:
            sequence_ids = [s.id for s in sequences]
            if any([_s.alignment_id not in sequence_ids for _s in _sequences]):
                print('\nWARNING: Sequences were found in the alignment file that were not included \
                      in the input sequence list. This may cause problems.')
            for s in sequences:
                s.alignment_id = s.id
                s.alignment_sequence = s.sequence
        if unrooted:
            root = None
            root_name = None
        else:
            if _root is None:
                print('\nERROR: The specified root ({}) was not found in the provided alignment file.'.format(root))
                print('\n')
                sys.exit(1)
            root = _root
            if root_name is not None:
                root.alignment_id = root_name
            else:
                root_name = root.alignment_id
            sequences = [s for s in sequences if all([s.alignment_id != name for name in [root.id, root.alignment_id]])]
            sequences.append(root)

    # parse sequences from tree_file, if provided
    elif tree_file is not None:
        if not unrooted and type(root) not in STR_TYPES:
            print('\nERROR: If providing a tree_file, the name of the root sequence must \
            be provided (as a string) using the root keyword argument')
            print('\n')
            sys.exit(1)
        _sequences = []
        _root = None
        tree = Phylo.read(open(tree_file), 'newick')
        for leaf in tree.get_terminals():
            s = ''
            if leaf.name == root:
                _root = Sequence(s, leaf.name)
                _root.alignment_id = _root.id
            else:
                _s = Sequence(s, id=leaf.name)
                _s.alignment_id = leaf.name
                _sequences.append(_s)
        if sequences is None:
            sequences = _sequences
        else:
            sequence_ids = [s.id for s in sequences]
            if any([_s.alignment_id not in sequence_ids for _s in _sequences]):
                print('\nWARNING: Sequences were found in the alignment file that were not included \
                      in the input sequence list. This may cause problems.')
            for s in sequences:
                s.alignment_id = s.id
                s.alignment_sequence = s.sequence
        if unrooted:
            root = None
            root_name = None
        elif _root is None:
            print('\nERROR: The specified root ({}) was not found in the provided tree file.'.format(root))
            print('\n')
            sys.exit(1)
        else:
            root = _root
            if root_name is not None:
                root.alignment_id = root_name
            else:
                root_name = root.alignment_id
            sequences = [s for s in sequences if all([s.alignment_id != name for name in [root.id, root.alignment_id]])]
            sequences.append(root)

    # set up colors and color ordering
    if order_dict is None:
        if order_function is not None:
            order_dict = {seq.alignment_id: order_function(seq) for seq in sequences}
    if color_dict is None:
        if color_function is not None:
            color_dict = {seq.alignment_id: color_function(seq) for seq in sequences}
    if color_dict is None:
        color_dict = {}

    # make msa (if necessary)
    if all([aln_file is None, tree_file is None]):
        aln_file = os.path.abspath(os.path.join(project_dir, '{}.aln'.format(name)))
        # muscle(seqs, aln_file, as_file=True)
        do_print = False if quiet else True
        if do_print:
            print('\n')
        seqs = [(s.alignment_id, s.alignment_sequence) for s in sequences]
        mafft(seqs, aln_file, as_file=True, print_stdout=do_print, print_stderr=do_print)

    # make treefile (if necessary)
    if tree_file is None:
        tree_file = os.path.abspath(os.path.join(project_dir, '{}.nw'.format(name)))
        fasttree(aln_file, tree_file, is_aa=aa, quiet=quiet)

    # make phylogeny
    prefix = '' if figname_prefix is None else figname_prefix
    suffix = '' if figname_suffix is None else figname_suffix
    fig_file = os.path.join(project_dir, '{}{}{}.pdf'.format(prefix, name, suffix))
    _make_tree_figure(tree_file,
                      fig_file,
                      color_dict,
                      order_dict,
                      None if root is None else root.alignment_id,
                      rename_function=rename_function,
                      show_names=show_names,
                      name_field=name_field,
                      branch_vert_margin=branch_vert_margin,
                      scale=scale,
                      color_node_labels=color_node_labels,
                      label_colors=label_colors,
                      show_root_name=show_root_name,
                      tree_orientation=1 if mirror else 0,
                      fontsize=fontsize,
                      min_order_fraction=min_order_fraction,
                    #   linked_alignment=linked_alignment,
                    #   alignment_fontsize=alignment_fontsize,
                    #   alignment_height=alignment_height,
                    #   alignment_width=alignment_width,
                      show_scale=show_scale,
                      compact_alignment=compact_alignment,
                      scale_factor=scale_factor,
                      linewidth=linewidth,
                      ladderize=ladderize,
                      delete_nodes=delete_nodes)
def phylogeny ( sequences = None , project_dir = None , name = None , aln_file = None , tree_file = None , seq_field = None , name_field = None , aa = False , species = 'human' , unrooted = False , ladderize = True , root = None , root_name = None , show_root_name = False , color_dict = None , color_function = None , order_dict = None , order_function = None , color_node_labels = False , label_colors = None , scale = None , branch_vert_margin = None , fontsize = 12 , show_names = True , show_scale = False , mirror = False , min_order_fraction = 0.1 , figname_prefix = None , figname_suffix = None , compact_alignment = False , scale_factor = 1 , rename_function = None , linewidth = 1.0 , delete_nodes = None , quiet = True ) : if project_dir is None : print ( '\nERROR: project_dir is required\n' ) sys . exit ( 1 ) else : project_dir = os . path . abspath ( project_dir ) if name is None : name = '' . join ( random . choice ( string . ascii_uppercase + string . digits ) for _ in range ( 8 ) ) if sequences is not None and all ( [ arg is None for arg in [ aln_file , tree_file ] ] ) : sequences = deepcopy ( sequences ) root = copy ( root ) if seq_field is not None : if not all ( [ seq_field in list ( s . annotations . keys ( ) ) for s in sequences ] ) : print ( '\nERROR: {} is not present in all of the supplied sequences.\n' . format ( seq_field ) ) sys . exit ( 1 ) for s in sequences : s . alignment_sequence = s [ seq_field ] else : for s in sequences : s . alignment_sequence = s . sequence if name_field is not None : if not all ( [ name_field in list ( s . annotations . keys ( ) ) for s in sequences ] ) : print ( '\nERROR: {} is not present in all of the supplied sequences.\n' . format ( name_field ) ) sys . exit ( 1 ) for s in sequences : s . alignment_id = s [ name_field ] else : for s in sequences : s . alignment_id = s . id if unrooted : root = None root_name = None elif root is None : if not quiet : print ( '\nRoot sequence was was not provided. Using the germline V-gene.' ) if not all ( [ 'v_gene' in list ( s . annotations . keys ( ) ) for s in sequences ] ) : print ( '\nInput sequences to not appear to be AbStar annotated. Annotating now...' ) sequences = abstar . run ( * [ ( s . id , s . sequence ) for s in sequences ] ) print ( 'Done.' ) if not all ( [ 'full' in list ( s [ 'v_gene' ] . keys ( ) ) for s in sequences ] ) : print ( '\nInput sequences to not appear to be AbStar annotated. Annotating now...' ) sequences = abstar . run ( * [ ( s . id , s . sequence ) for s in sequences ] ) print ( 'Done.' ) top_vgene = sorted ( list ( Counter ( [ s [ 'v_gene' ] [ 'full' ] for s in sequences ] ) . items ( ) ) , key = lambda x : x [ 1 ] , reverse = True ) [ 0 ] [ 0 ] vgene = get_imgt_germlines ( species , 'V' , gene = top_vgene ) if aa : root = Sequence ( vgene . ungapped_aa_sequence , id = top_vgene ) else : root = Sequence ( vgene . ungapped_nt_sequence , id = top_vgene ) root . alignment_id = root . id root . alignment_sequence = root . sequence if not quiet : print ( 'Top V-gene: {}' . format ( root . alignment_id ) ) print ( root . alignment_sequence ) elif type ( root ) in STR_TYPES : root = [ s for s in sequences if s . alignment_id == root ] [ 0 ] if not root : print ( '\nERROR: The name of the root sequence ({}) was not found in the list of input sequences.' . format ( root ) ) print ( '\n' ) sys . exit ( 1 ) sequences = [ s for s in sequences if s . alignment_id != root . alignment_id ] elif type ( root ) == Sequence : if seq_field is not None : if seq_field not in list ( root . anotations . keys ( ) ) : print ( '\nERROR: {} is not present in the supplied root sequence.\n' . format ( seq_field ) ) sys . exit ( 1 ) root . alignment_sequence = root [ seq_field ] if name_field is not None : if name_field not in list ( root . anotations . keys ( ) ) : print ( '\nERROR: {} is not present in the supplied root sequence.\n' . format ( name_field ) ) sys . exit ( 1 ) root . alignment_id = root [ name_field ] sequences = [ s for s in sequences if s . alignment_id != root . alignment_id ] else : print ( '\nERROR: If root is provided, it must be the name of a sequence \
            found in the supplied list of sequences or it must be a Sequence object.' ) print ( '\n' ) sys . exit ( 1 ) if not unrooted : if root_name is not None : root . alignment_id = root_name else : root_name = root . alignment_id sequences . append ( root ) elif aln_file is not None : if not unrooted and type ( root ) not in STR_TYPES : print ( '\nERROR: If providing an aln_file, the name of the root sequence must \
            be provided (as a string) using the root keyword argument' ) print ( '\n' ) sys . exit ( 1 ) _sequences = [ ] _root = None for rec in AlignIO . read ( open ( aln_file ) , 'fasta' ) : s = str ( rec . seq ) . replace ( '-' , '' ) if rec . id == root : _root = Sequence ( s , rec . id ) _root . alignment_id = _root . id else : _s = Sequence ( s , id = rec . id ) _s . alignment_id = rec . id _sequences . append ( _s ) if sequences is None : sequences = _sequences else : sequence_ids = [ s . id for s in sequences ] if any ( [ _s . alignment_id not in sequence_ids for _s in _sequences ] ) : print ( '\nWARNING: Sequences were found in the alignment file that were not included \
                      in the input sequence list. This may cause problems.' ) for s in sequences : s . alignment_id = s . id s . alignment_sequence = s . sequence if unrooted : root = None root_name = None else : if _root is None : print ( '\nERROR: The specified root ({}) was not found in the provided alignment file.' . format ( root ) ) print ( '\n' ) sys . exit ( 1 ) root = _root if root_name is not None : root . alignment_id = root_name else : root_name = root . alignment_id sequences = [ s for s in sequences if all ( [ s . alignment_id != name for name in [ root . id , root . alignment_id ] ] ) ] sequences . append ( root ) elif tree_file is not None : if not unrooted and type ( root ) not in STR_TYPES : print ( '\nERROR: If providing a tree_file, the name of the root sequence must \
            be provided (as a string) using the root keyword argument' ) print ( '\n' ) sys . exit ( 1 ) _sequences = [ ] _root = None tree = Phylo . read ( open ( tree_file ) , 'newick' ) for leaf in tree . get_terminals ( ) : s = '' if leaf . name == root : _root = Sequence ( s , leaf . name ) _root . alignment_id = _root . id else : _s = Sequence ( s , id = leaf . name ) _s . alignment_id = leaf . name _sequences . append ( _s ) if sequences is None : sequences = _sequences else : sequence_ids = [ s . id for s in sequences ] if any ( [ _s . alignment_id not in sequence_ids for _s in _sequences ] ) : print ( '\nWARNING: Sequences were found in the alignment file that were not included \
                      in the input sequence list. This may cause problems.' ) for s in sequences : s . alignment_id = s . id s . alignment_sequence = s . sequence if unrooted : root = None root_name = None elif _root is None : print ( '\nERROR: The specified root ({}) was not found in the provided tree file.' . format ( root ) ) print ( '\n' ) sys . exit ( 1 ) else : root = _root if root_name is not None : root . alignment_id = root_name else : root_name = root . alignment_id sequences = [ s for s in sequences if all ( [ s . alignment_id != name for name in [ root . id , root . alignment_id ] ] ) ] sequences . append ( root ) if order_dict is None : if order_function is not None : order_dict = { seq . alignment_id : order_function ( seq ) for seq in sequences } if color_dict is None : if color_function is not None : color_dict = { seq . alignment_id : color_function ( seq ) for seq in sequences } if color_dict is None : color_dict = { } if all ( [ aln_file is None , tree_file is None ] ) : aln_file = os . path . abspath ( os . path . join ( project_dir , '{}.aln' . format ( name ) ) ) do_print = False if quiet else True if do_print : print ( '\n' ) seqs = [ ( s . alignment_id , s . alignment_sequence ) for s in sequences ] mafft ( seqs , aln_file , as_file = True , print_stdout = do_print , print_stderr = do_print ) if tree_file is None : tree_file = os . path . abspath ( os . path . join ( project_dir , '{}.nw' . format ( name ) ) ) fasttree ( aln_file , tree_file , is_aa = aa , quiet = quiet ) prefix = '' if figname_prefix is None else figname_prefix suffix = '' if figname_suffix is None else figname_suffix fig_file = os . path . join ( project_dir , '{}{}{}.pdf' . format ( prefix , name , suffix ) ) _make_tree_figure ( tree_file , fig_file , color_dict , order_dict , None if root is None else root . alignment_id , rename_function = rename_function , show_names = show_names , name_field = name_field , branch_vert_margin = branch_vert_margin , scale = scale , color_node_labels = color_node_labels , label_colors = label_colors , show_root_name = show_root_name , tree_orientation = 1 if mirror else 0 , fontsize = fontsize , min_order_fraction = min_order_fraction , show_scale = show_scale , compact_alignment = compact_alignment , scale_factor = scale_factor , linewidth = linewidth , ladderize = ladderize , delete_nodes = delete_nodes )
Generates a lineage phylogeny figure.

    Args:

        sequences (list(Sequence)): A list of ``Sequence`` objects from which a phylogeny
            will be calculated. Strictly speaking, they do not need to be ``Sequence`` objects,
            rather, any object that contains the sequence name as the ``id`` attribute (or
            by dictionary-style lookup using the provided ``name_field``) and contains the
            sequence as the ``sequence`` attribute (or by dictionary-stype lookup using the
            provided ``seq_field``).

        project_dir (str): directory into which all phylogeny files will be deposited,
            including alignment, tree and figure files.

        name (str): Name to be used for naming alignment, tree, and phylogeny files. If not
            provided, a random name will be generated.

        aln_file (str): if a multiple sequence alignment has already been calculated,
            passing the path to the alignment file (in FASTA format) will force Lineage.phylogeny()
            to use the supplied msa instead of computing a new one.

        tree_file (str): if a tree file has already been calculated, passing the path
            to the pre-computed tree file will force ``phylogeny()`` to use
            the supplied tree file instead of computing a new one. It is important to note that
            only sequence names will be parsed from the tree_file, so if ``order_function`` or
            ``color_function`` is also provided, ensure that these functions only require the
            sequence ID rather than the entire sequence.

        aa (bool): if True, use amino acid sequences to compute the phylogeny.
            Default is False.

        root (Sequence, str: The root can be provided either as a ``Sequence`` object (if ``sequences``
            are being provided) or as the name of a sequence that can be found either in
            ``sequences`` or in the provided ``aln_file`` or ``tree_file``. Note that if
            either ``aln_file`` or ``tree_file`` are provided, the root must be provided
            as the sequence name, not as a ``Sequence`` object (as the root sequence must
            already be included in either ``aln_file`` or ``tree_file``. If the root is not
            provided, the germline V-gene sequence of the

        color_dict (dict): Dictionary with sequence IDs as keys and colors (hex format) as values. If any
            sequence IDs are not found in the dict, they will be colored black. If neither ``color_dict`` nor
            ``color_function`` is provided, all leaves will be colored black.

        color_function (func): Function that that accepts a ``Sequence`` object and returns the color
            (as a hex code). If ``color_dict`` is also provided, ``color_function`` is ignored. Additionally,
            ``color_function`` will only be used if ``sequences`` are provided. If ``sequences`` are not provided
            (instead using ``aln_file` or ``tree_file``), ``color_dict`` must be used instead of ``color_function``.

        orders: a dictionary with sequence IDs as keys and orders (integers) as values.
            If not provided, only the leaf branches will be colored (if <colors> or
            <color_function> is provided).

        chain: build a phylogeny using the given chain ('heavy' or 'light').
            Default is 'heavy'.

        filter_function: function used to filter sequences (identity-based clustering, for
            example). The function should accept a list of Sequence objects and return
            a list of Sequence objects.

        just_pairs: if True, compute the phylogeny using only paired sequences.
            Default (False) will use all sequences of the appropriate chain, paired or not.

        scale (float): passed to ete3.TreeStyle() to set the scale of the tree figure. Increased
            scale results in a wider tree.

        branch_vert_margin (int): passed to ete3.TreeStyle() to set the branch_vertical_margin of
            the tree figure. Increased branch_vert_margin results in a taller tree.

        fontsize: size of the leaf labels. Default is 12.

        show_names: show names of leaf nodes. Options are True (show labels for all leaf nodes),
            False (don't show labels for any leaf nodes) or a list of sequence IDs for which
            labels should be shown. Default is True.

        mirror: flip the orientation of the tree. Default is to draw the tree from left to right.
            Setting mirror to True results in the tree being drawn from right to left.

        min_order_fraction: minimum fraction of downstream leaves requried to color a branch.
            When coloring non-leaf nodes, the earliest 'order' with at least <min_order_fraction>
            leaf nodes is used. Default is 0.1 (which corresponds to 10%).

        figname_prefix: by default, figures will be named <lineage_id>.pdf. If prefix='prefix_' and
            the lineage ID is 'ABC123', the figure file will be named 'prefix_ABC123.pdf'.

        figname_suffix: by default, figures will be named <lineage_id>.pdf. If suffix='_suffix' and
            the lineage ID is 'ABC123', the figure file will be named 'ABC123_suffix.pdf'.