Instruction:
Given the following Python 3 function, write the documentation
def populate(self,
        size,
        names_library=None,
        reuse_names=False,
        random_branches=False,
        branch_range=(0, 1),
        support_range=(0, 1)):
        """
        Generates a random topology by populating current node.

        :argument None names_library: If provided, names library
          (list, set, dict, etc.) will be used to name nodes.

        :argument False reuse_names: If True, node names will not be
          necessarily unique, which makes the process a bit more
          efficient.

        :argument False random_branches: If True, branch distances and support
          values will be randomized.

        :argument (0,1) branch_range: If random_branches is True, this
        range of values will be used to generate random distances.

        :argument (0,1) support_range: If random_branches is True,
        this range of values will be used to generate random branch
        support values.

        """
        NewNode = self.__class__

        if len(self.children) > 1:
            connector = NewNode()
            for ch in self.get_children():
                ch.detach()
                connector.add_child(child = ch)
            root = NewNode()
            self.add_child(child = connector)
            self.add_child(child = root)
        else:
            root = self

        next_deq = deque([root])
        for i in range(size-1):
            if random.randint(0, 1):
                p = next_deq.pop()
            else:
                p = next_deq.popleft()

            c1 = p.add_child()
            c2 = p.add_child()
            next_deq.extend([c1, c2])
            if random_branches:
                c1.dist = random.uniform(*branch_range)
                c2.dist = random.uniform(*branch_range)
                c1.support = random.uniform(*branch_range)
                c2.support = random.uniform(*branch_range)
            else:
                c1.dist = 1.0
                c2.dist = 1.0
                c1.support = 1.0
                c2.support = 1.0

        # next contains leaf nodes
        charset = "abcdefghijklmnopqrstuvwxyz"
        if names_library:
            names_library = deque(names_library)
        else:
            avail_names = itertools.combinations_with_replacement(charset, 10)
        for n in next_deq:
            if names_library:
                if reuse_names:
                    tname = random.sample(names_library, 1)[0]
                else:
                    tname = names_library.pop()
            else:
                tname = ''.join(next(avail_names))
            n.name = tname

Response: Populates the current node with random nodes.


Instruction:
How would you code a function in Python 3 to
set the outgroup of this node.

Response:
def set_outgroup(self, outgroup):
        """
        Sets a descendant node as the outgroup of a tree.  This function
        can be used to root a tree or even an internal node.

        Parameters:
        -----------
        outgroup:
            a node instance within the same tree structure that will be
            used as a basal node.
        """
        outgroup = _translate_nodes(self, outgroup)

        if self == outgroup:
            ##return
            ## why raise an error for this?
            raise TreeError("Cannot set myself as outgroup")

        parent_outgroup = outgroup.up

        # Detects (sub)tree root
        n = outgroup
        while n.up is not self:
            n = n.up

        # If outgroup is a child from root, but with more than one
        # sister nodes, creates a new node to group them

        self.children.remove(n)
        if len(self.children) != 1:
            down_branch_connector = self.__class__()
            down_branch_connector.dist = 0.0
            down_branch_connector.support = n.support
            for ch in self.get_children():
                down_branch_connector.children.append(ch)
                ch.up = down_branch_connector
                self.children.remove(ch)
        else:
            down_branch_connector = self.children[0]

        # Connects down branch to myself or to outgroup
        quien_va_ser_padre = parent_outgroup
        if quien_va_ser_padre is not self:
            # Parent-child swapping
            quien_va_ser_hijo = quien_va_ser_padre.up
            quien_fue_padre = None
            buffered_dist = quien_va_ser_padre.dist
            buffered_support = quien_va_ser_padre.support

            while quien_va_ser_hijo is not self:
                quien_va_ser_padre.children.append(quien_va_ser_hijo)
                quien_va_ser_hijo.children.remove(quien_va_ser_padre)

                buffered_dist2 = quien_va_ser_hijo.dist
                buffered_support2 = quien_va_ser_hijo.support
                quien_va_ser_hijo.dist = buffered_dist
                quien_va_ser_hijo.support = buffered_support
                buffered_dist = buffered_dist2
                buffered_support = buffered_support2

                quien_va_ser_padre.up = quien_fue_padre
                quien_fue_padre = quien_va_ser_padre

                quien_va_ser_padre = quien_va_ser_hijo
                quien_va_ser_hijo = quien_va_ser_padre.up

            quien_va_ser_padre.children.append(down_branch_connector)
            down_branch_connector.up = quien_va_ser_padre
            quien_va_ser_padre.up = quien_fue_padre

            down_branch_connector.dist += buffered_dist
            outgroup2 = parent_outgroup
            parent_outgroup.children.remove(outgroup)
            outgroup2.dist = 0

        else:
            outgroup2 = down_branch_connector

        outgroup.up = self
        outgroup2.up = self
        # outgroup is always the first children. Some function my
        # trust on this fact, so do no change this.
        self.children = [outgroup,outgroup2]
        middist = (outgroup2.dist + outgroup.dist)/2
        outgroup.dist = middist
        outgroup2.dist = middist
        outgroup2.support = outgroup.support


Instruction:
Given the following Python 3 function, write the documentation
def unroot(self):
        if len(self.children)==2:
            if not self.children[0].is_leaf():
                self.children[0].delete()
            elif not self.children[1].is_leaf():
                self.children[1].delete()
            else:
                raise TreeError("Cannot unroot a tree with only two leaves")

Response: Unroots the current node.


Instruction:
How would you code a function in Python 3 to
return the ASCII representation of the tree.

Response:
def _asciiArt(self, char1='-', show_internal=True, compact=False, attributes=None):
        """
        Returns the ASCII representation of the tree.
        Code based on the PyCogent GPL project.
        """
        if not attributes:
            attributes = ["name"]

        # toytree edit:
        # removed six dependency for map with comprehension
        # node_name = ', '.join(map(str, [getattr(self, v) for v in attributes if hasattr(self, v)]))
        _attrlist = [getattr(self, v) for v in attributes if hasattr(self, v)]
        node_name = ", ".join([str(i) for i in _attrlist])

        LEN = max(3, len(node_name) if not self.children or show_internal else 3)
        PAD = ' ' * LEN
        PA = ' ' * (LEN-1)
        if not self.is_leaf():
            mids = []
            result = []
            for c in self.children:
                if len(self.children) == 1:
                    char2 = '/'
                elif c is self.children[0]:
                    char2 = '/'
                elif c is self.children[-1]:
                    char2 = '\\'
                else:
                    char2 = '-'
                (clines, mid) = c._asciiArt(char2, show_internal, compact, attributes)
                mids.append(mid+len(result))
                result.extend(clines)
                if not compact:
                    result.append('')
            if not compact:
                result.pop()
            (lo, hi, end) = (mids[0], mids[-1], len(result))
            prefixes = [PAD] * (lo+1) + [PA+'|'] * (hi-lo-1) + [PAD] * (end-hi)
            mid = int((lo + hi) / 2)
            prefixes[mid] = char1 + '-'*(LEN-2) + prefixes[mid][-1]
            result = [p+l for (p,l) in zip(prefixes, result)]
            if show_internal:
                stem = result[mid]
                result[mid] = stem[0] + node_name + stem[len(node_name)+1:]
            return (result, mid)
        else:
            return ([char1 + '-' + node_name], 0)


Instruction:
Write a Python 3 script to
return an ASCII representation of the tree.

Response:
def get_ascii(self, show_internal=True, compact=False, attributes=None):
        """
        Returns a string containing an ascii drawing of the tree.

        Parameters:
        -----------
        show_internal:
            include internal edge names.
        compact:
            use exactly one line per tip.
        attributes:
            A list of node attributes to shown in the ASCII representation.
        """
        (lines, mid) = self._asciiArt(show_internal=show_internal,
                                      compact=compact,
                                      attributes=attributes)
        return '\n'+'\n'.join(lines)


Instruction:
Can you write a function in Python 3 where it
sorts the branches of a given tree according to the size of each partition.

Response:
def ladderize(self, direction=0):
        """
        Sort the branches of a given tree (swapping children nodes)
        according to the size of each partition.
        """
        if not self.is_leaf():
            n2s = {}
            for n in self.get_children():
                s = n.ladderize(direction=direction)
                n2s[n] = s

            self.children.sort(key=lambda x: n2s[x])
            if direction == 1:
                self.children.reverse()
            size = sum(n2s.values())
        else:
            size = 1
        return size


Instruction:
How would you explain what the following Python 3 function does
def sort_descendants(self, attr="name"):
        node2content = self.get_cached_content(store_attr=attr, container_type=list)
        for n in self.traverse():
            if not n.is_leaf():
                n.children.sort(key=lambda x: str(sorted(node2content[x])))

Response: This function sorts the nodes in a given tree by node names considering node names.


Instruction:
Can you tell what is the following Python 3 function doing
def get_cached_content(self, store_attr=None, container_type=set, _store=None):
        if _store is None:
            _store = {}

        for ch in self.children:
            ch.get_cached_content(store_attr=store_attr,
                                  container_type=container_type,
                                  _store=_store)
        if self.children:
            val = container_type()
            for ch in self.children:
                if type(val) == list:
                    val.extend(_store[ch])
                if type(val) == set:
                    val.update(_store[ch])
            _store[self] = val
        else:
            if store_attr is None:
                val = self
            else:
                val = getattr(self, store_attr)
            _store[self] = container_type([val])
        return _store

Response: Returns a dictionary pointing to the preloaded content of each internal node under this tree.


Instruction:
Create a Python 3 function for
returning the robinson - foulds symmetric distance between two trees.

Response:
def robinson_foulds(self,
        t2,
        attr_t1="name",
        attr_t2="name",
        unrooted_trees=False,
        expand_polytomies=False,
        polytomy_size_limit=5,
        skip_large_polytomies=False,
        correct_by_polytomy_size=False,
        min_support_t1=0.0,
        min_support_t2=0.0):
        """
        Returns the Robinson-Foulds symmetric distance between current
        tree and a different tree instance.

        Parameters:
        -----------
        t2:
            reference tree
        attr_t1:
            Compare trees using a custom node attribute as a node name.
        attr_t2:
            Compare trees using a custom node attribute as a node name in target tree.
        attr_t2:
            If True, consider trees as unrooted.
        False expand_polytomies:
            If True, all polytomies in the reference and target tree will be
            expanded into all possible binary trees. Robinson-foulds distance
            will be calculated between all tree combinations and the minimum
            value will be returned.
            See also, :func:`NodeTree.expand_polytomy`.

        Returns:
        --------
        (rf, rf_max, common_attrs, names, edges_t1, edges_t2,
         discarded_edges_t1, discarded_edges_t2)
        """
        ref_t = self
        target_t = t2
        if not unrooted_trees and (len(ref_t.children) > 2 or len(target_t.children) > 2):
            raise TreeError("Unrooted tree found! You may want to activate the unrooted_trees flag.")

        if expand_polytomies and correct_by_polytomy_size:
            raise TreeError("expand_polytomies and correct_by_polytomy_size are mutually exclusive.")

        if expand_polytomies and unrooted_trees:
            raise TreeError("expand_polytomies and unrooted_trees arguments cannot be enabled at the same time")

        attrs_t1 = set([getattr(n, attr_t1) for n in ref_t.iter_leaves() if hasattr(n, attr_t1)])
        attrs_t2 = set([getattr(n, attr_t2) for n in target_t.iter_leaves() if hasattr(n, attr_t2)])
        common_attrs = attrs_t1 & attrs_t2
        # release mem
        attrs_t1, attrs_t2 = None, None

        # Check for duplicated items (is it necessary? can we optimize? what's the impact in performance?')
        size1 = len([True for n in ref_t.iter_leaves() if getattr(n, attr_t1, None) in common_attrs])
        size2 = len([True for n in target_t.iter_leaves() if getattr(n, attr_t2, None) in common_attrs])
        if size1 > len(common_attrs):
            raise TreeError('Duplicated items found in source tree')
        if size2 > len(common_attrs):
            raise TreeError('Duplicated items found in reference tree')

        if expand_polytomies:
            ref_trees = [
                TreeNode(nw) for nw in
                ref_t.expand_polytomies(
                    map_attr=attr_t1,
                    polytomy_size_limit=polytomy_size_limit,
                    skip_large_polytomies=skip_large_polytomies
                    )
                ]
            target_trees = [
                TreeNode(nw) for nw in
                target_t.expand_polytomies(
                    map_attr=attr_t2,
                    polytomy_size_limit=polytomy_size_limit,
                    skip_large_polytomies=skip_large_polytomies,
                    )
                ]
            attr_t1, attr_t2 = "name", "name"
        else:
            ref_trees = [ref_t]
            target_trees = [target_t]

        polytomy_correction = 0
        if correct_by_polytomy_size:
            corr1 = sum([0]+[len(n.children) - 2 for n in ref_t.traverse() if len(n.children) > 2])
            corr2 = sum([0]+[len(n.children) - 2 for n in target_t.traverse() if len(n.children) > 2])
            if corr1 and corr2:
                raise TreeError("Both trees contain polytomies! Try expand_polytomies=True instead")
            else:
                polytomy_correction = max([corr1, corr2])

        min_comparison = None
        for t1 in ref_trees:
            t1_content = t1.get_cached_content()
            t1_leaves = t1_content[t1]
            if unrooted_trees:
                edges1 = set([
                        tuple(sorted([tuple(sorted([getattr(n, attr_t1) for n in content if hasattr(n, attr_t1) and getattr(n, attr_t1) in common_attrs])),
                                      tuple(sorted([getattr(n, attr_t1) for n in t1_leaves-content if hasattr(n, attr_t1) and getattr(n, attr_t1) in common_attrs]))]))
                        for content in six.itervalues(t1_content)])
                edges1.discard(((),()))
            else:
                edges1 = set([
                        tuple(sorted([getattr(n, attr_t1) for n in content if hasattr(n, attr_t1) and getattr(n, attr_t1) in common_attrs]))
                        for content in six.itervalues(t1_content)])
                edges1.discard(())

            if min_support_t1:
                support_t1 = dict([
                        (tuple(sorted([getattr(n, attr_t1) for n in content if hasattr(n, attr_t1) and getattr(n, attr_t1) in common_attrs])), branch.support)
                        for branch, content in six.iteritems(t1_content)])

            for t2 in target_trees:
                t2_content = t2.get_cached_content()
                t2_leaves = t2_content[t2]
                if unrooted_trees:
                    edges2 = set([
                            tuple(sorted([
                                        tuple(sorted([getattr(n, attr_t2) for n in content if hasattr(n, attr_t2) and getattr(n, attr_t2) in common_attrs])),
                                        tuple(sorted([getattr(n, attr_t2) for n in t2_leaves-content if hasattr(n, attr_t2) and getattr(n, attr_t2) in common_attrs]))]))
                            for content in six.itervalues(t2_content)])
                    edges2.discard(((),()))
                else:
                    edges2 = set([
                            tuple(sorted([getattr(n, attr_t2) for n in content if hasattr(n, attr_t2) and getattr(n, attr_t2) in common_attrs]))
                            for content in six.itervalues(t2_content)])
                    edges2.discard(())

                if min_support_t2:
                    support_t2 = dict([
                        (tuple(sorted(([getattr(n, attr_t2) for n in content if hasattr(n, attr_t2) and getattr(n, attr_t2) in common_attrs]))), branch.support)
                        for branch, content in six.iteritems(t2_content)])

                # if a support value is passed as a constraint, discard lowly supported branches from the analysis
                discard_t1, discard_t2 = set(), set()
                if min_support_t1 and unrooted_trees:
                    discard_t1 = set([p for p in edges1 if support_t1.get(p[0], support_t1.get(p[1], 999999999)) < min_support_t1])
                elif min_support_t1:
                    discard_t1 = set([p for p in edges1 if support_t1[p] < min_support_t1])

                if min_support_t2 and unrooted_trees:
                    discard_t2 = set([p for p in edges2 if support_t2.get(p[0], support_t2.get(p[1], 999999999)) < min_support_t2])
                elif min_support_t2:
                    discard_t2 = set([p for p in edges2 if support_t2[p] < min_support_t2])

                #rf = len(edges1 ^ edges2) - (len(discard_t1) + len(discard_t2)) - polytomy_correction # poly_corr is 0 if the flag is not enabled
                #rf = len((edges1-discard_t1) ^ (edges2-discard_t2)) - polytomy_correction

                # the two root edges are never counted here, as they are always
                # present in both trees because of the common attr filters
                rf = len(((edges1 ^ edges2) - discard_t2) - discard_t1) - polytomy_correction

                if unrooted_trees:
                    # thought this may work, but it does not, still I don't see why
                    #max_parts = (len(common_attrs)*2) - 6 - len(discard_t1) - len(discard_t2)
                    max_parts = (len([p for p in edges1 - discard_t1 if len(p[0])>1 and len(p[1])>1]) +
                                 len([p for p in edges2 - discard_t2 if len(p[0])>1 and len(p[1])>1]))
                else:
                    # thought this may work, but it does not, still I don't see why
                    #max_parts = (len(common_attrs)*2) - 4 - len(discard_t1) - len(discard_t2)

                    # Otherwise we need to count the actual number of valid
                    # partitions in each tree -2 is to avoid counting the root
                    # partition of the two trees (only needed in rooted trees)
                    max_parts = (len([p for p in edges1 - discard_t1 if len(p)>1]) +
                                 len([p for p in edges2 - discard_t2 if len(p)>1])) - 2

                    # print max_parts

                if not min_comparison or min_comparison[0] > rf:
                    min_comparison = [rf, max_parts, common_attrs, edges1, edges2, discard_t1, discard_t2]

        return min_comparison


Instruction:
Can you tell what is the following Python 3 function doing
def iter_edges(self, cached_content=None):
        if not cached_content:
            cached_content = self.get_cached_content()
        all_leaves = cached_content[self]
        for n, side1 in six.iteritems(cached_content):
            yield (side1, all_leaves - side1)

Response: Iterate over the edges of a tree.


Instruction:
Can you implement a function in Python 3 that
returns the unique ID representing the topology of the current tree.

Response:
def get_topology_id(self, attr="name"):
        """
        Returns the unique ID representing the topology of the current tree.
        Two trees with the same topology will produce the same id. If trees are
        unrooted, make sure that the root node is not binary or use the
        tree.unroot() function before generating the topology id.

        This is useful to detect the number of unique topologies over a bunch
        of trees, without requiring full distance methods.

        The id is, by default, calculated based on the terminal node's names.
        Any other node attribute could be used instead.
        """
        edge_keys = []
        for s1, s2 in self.get_edges():
            k1 = sorted([getattr(e, attr) for e in s1])
            k2 = sorted([getattr(e, attr) for e in s2])
            edge_keys.append(sorted([k1, k2]))
        return md5(str(sorted(edge_keys)).encode('utf-8')).hexdigest()


Instruction:
Explain what the following Python 3 code does
def check_monophyly(self,
        values,
        target_attr,
        ignore_missing=False,
        unrooted=False):
        """
        Returns True if a given target attribute is monophyletic under
        this node for the provided set of values.

        If not all values are represented in the current tree
        structure, a ValueError exception will be raised to warn that
        strict monophyly could never be reached (this behaviour can be
        avoided by enabling the `ignore_missing` flag.

        Parameters:
        -----------
        values:
            a set of values for which monophyly is expected.

        target_attr:
            node attribute being used to check monophyly (i.e. species for
            species trees, names for gene family trees, or any custom feature
            present in the tree).

        ignore_missing:
            Avoid raising an Exception when missing attributes are found.

        unrooted:
            If True, tree will be treated as unrooted, thus allowing to find
            monophyly even when current outgroup is spliting a monophyletic group.

        Returns:
        --------
        the following tuple
        IsMonophyletic (boolean),
        clade type ('monophyletic', 'paraphyletic' or 'polyphyletic'),
        leaves breaking the monophyly (set)
        """
        if type(values) != set:

            values = set(values)

        # This is the only time I traverse the tree, then I use cached
        # leaf content
        n2leaves = self.get_cached_content()

        # Raise an error if requested attribute values are not even present
        if ignore_missing:
            found_values = set([getattr(n, target_attr) for n in n2leaves[self]])
            missing_values = values - found_values
            values = values & found_values

        # Locate leaves matching requested attribute values
        targets = set([leaf for leaf in n2leaves[self]
                   if getattr(leaf, target_attr) in values])
        if not ignore_missing:
            if values - set([getattr(leaf, target_attr) for leaf in targets]):
                raise ValueError('The monophyly of the provided values could never be reached, as not all of them exist in the tree.'
                                 ' Please check your target attribute and values, or set the ignore_missing flag to True')

        if unrooted:
            smallest = None
            for side1, side2 in self.iter_edges(cached_content=n2leaves):
                if targets.issubset(side1) and (not smallest or len(side1) < len(smallest)):
                    smallest = side1
                elif targets.issubset(side2) and (not smallest or len(side2) < len(smallest)):
                        smallest = side2
                if smallest is not None and len(smallest) == len(targets):
                    break
            foreign_leaves = smallest - targets
        else:
            # Check monophyly with get_common_ancestor. Note that this
            # step does not require traversing the tree again because
            # targets are node instances instead of node names, and
            # get_common_ancestor function is smart enough to detect it
            # and avoid unnecessary traversing.
            common = self.get_common_ancestor(targets)
            observed = n2leaves[common]
            foreign_leaves = set([leaf for leaf in observed
                              if getattr(leaf, target_attr) not in values])

        if not foreign_leaves:
            return True, "monophyletic", foreign_leaves
        else:
            # if the requested attribute is not monophyletic in this
            # node, let's differentiate between poly and paraphyly.
            poly_common = self.get_common_ancestor(foreign_leaves)
            # if the common ancestor of all foreign leaves is self
            # contained, we have a paraphyly. Otherwise, polyphyly.
            polyphyletic = [leaf for leaf in poly_common if
                            getattr(leaf, target_attr) in values]
            if polyphyletic:
                return False, "polyphyletic", foreign_leaves
            else:
                return False, "paraphyletic", foreign_leaves

Response: Checks that a given target attribute is monophyly under the current tree and returns True if it is monophyletic under the current tree.


Instruction:
Implement a Python 3 function for
returning a list of nodes that match the provided monophyly - isomorphic values.

Response:
def get_monophyletic(self, values, target_attr):
        """
        Returns a list of nodes matching the provided monophyly
        criteria. For a node to be considered a match, all
        `target_attr` values within and node, and exclusively them,
        should be grouped.

        :param values: a set of values for which monophyly is
            expected.

        :param target_attr: node attribute being used to check
            monophyly (i.e. species for species trees, names for gene
            family trees).
        """
        if type(values) != set:
            values = set(values)

        n2values = self.get_cached_content(store_attr=target_attr)

        is_monophyletic = lambda node: n2values[node] == values
        for match in self.iter_leaves(is_leaf_fn=is_monophyletic):
            if is_monophyletic(match):
                yield match


Instruction:
Implement a Python 3 function for
giving a tree with one or more polytomies, this functions returns the list of all trees (in newick format) resulting from the combination of all possible solutions of the multifurcated nodes. .. warning: Please note that the number of of possible binary trees grows exponentially with the number and size of polytomies. Using this function with large multifurcations is not feasible: polytomy size: 3 number of binary trees: 3 polytomy size: 4 number of binary trees: 15 polytomy size: 5 number of binary trees: 105 polytomy size: 6 number of binary trees: 945 polytomy size: 7 number of binary trees: 10395 polytomy size: 8 number of binary trees: 135135 polytomy size: 9 number of binary trees: 2027025 http://ajmonline.org/2010/darwin.php

Response:
def expand_polytomies(self,
        map_attr="name",
        polytomy_size_limit=5,
        skip_large_polytomies=False):
        """
        Given a tree with one or more polytomies, this functions returns the
        list of all trees (in newick format) resulting from the combination of
        all possible solutions of the multifurcated nodes.

        .. warning:

           Please note that the number of of possible binary trees grows
           exponentially with the number and size of polytomies. Using this
           function with large multifurcations is not feasible:

           polytomy size: 3 number of binary trees: 3
           polytomy size: 4 number of binary trees: 15
           polytomy size: 5 number of binary trees: 105
           polytomy size: 6 number of binary trees: 945
           polytomy size: 7 number of binary trees: 10395
           polytomy size: 8 number of binary trees: 135135
           polytomy size: 9 number of binary trees: 2027025

        http://ajmonline.org/2010/darwin.php
        """

        class TipTuple(tuple):
            pass

        def add_leaf(tree, label):
            yield (label, tree)
            if not isinstance(tree, TipTuple) and isinstance(tree, tuple):
                for left in add_leaf(tree[0], label):
                    yield (left, tree[1])
            for right in add_leaf(tree[1], label):
                yield (tree[0], right)

        def enum_unordered(labels):
            if len(labels) == 1:
                yield labels[0]
            else:
                for tree in enum_unordered(labels[1:]):
                    for new_tree in add_leaf(tree, labels[0]):
                        yield new_tree

        n2subtrees = {}
        for n in self.traverse("postorder"):
            if n.is_leaf():
                subtrees = [getattr(n, map_attr)]
            else:
                subtrees = []
                if len(n.children) > polytomy_size_limit:
                    if skip_large_polytomies:
                        for childtrees in itertools.product(*[n2subtrees[ch] for ch in n.children]):
                            subtrees.append(TipTuple(childtrees))
                    else:
                        raise TreeError("Found polytomy larger than current limit: %s" %n)
                else:
                    for childtrees in itertools.product(*[n2subtrees[ch] for ch in n.children]):
                        subtrees.extend([TipTuple(subtree) for subtree in enum_unordered(childtrees)])

            n2subtrees[n] = subtrees
        return ["%s;"%str(nw) for nw in n2subtrees[self]]


Instruction:
Can you tell what is the following Python 3 function doing
def resolve_polytomy(self,
        default_dist=0.0,
        default_support=0.0,
        recursive=True):
        """
        Resolve all polytomies under current node by creating an
        arbitrary dicotomic structure among the affected nodes. This
        function randomly modifies current tree topology and should
        only be used for compatibility reasons (i.e. programs
        rejecting multifurcated node in the newick representation).

        :param 0.0 default_dist: artificial branch distance of new
            nodes.

        :param 0.0 default_support: artificial branch support of new
            nodes.

        :param True recursive: Resolve any polytomy under this
             node. When False, only current node will be checked and fixed.
        """
        def _resolve(node):
            if len(node.children) > 2:
                children = list(node.children)
                node.children = []
                next_node = root = node
                for i in range(len(children) - 2):
                    next_node = next_node.add_child()
                    next_node.dist = default_dist
                    next_node.support = default_support

                next_node = root
                for ch in children:
                    next_node.add_child(ch)
                    if ch != children[-2]:
                        next_node = next_node.children[0]
        target = [self]
        if recursive:
            target.extend([n for n in self.get_descendants()])
        for n in target:
            _resolve(n)

Response: This function resolves all polytomies under current node by creating an arbitrary dicotomic structure among the affected nodes.


Instruction:
Implement a function in Python 3 to
remove all empty lines from the text.

Response:
def truncate_empty_lines(lines):
    """
    Removes all empty lines from above and below the text.

    We can't just use text.strip() because that would remove the leading
    space for the table.

    Parameters
    ----------
    lines : list of str

    Returns
    -------
    lines : list of str
        The text lines without empty lines above or below
    """
    while lines[0].rstrip() == '':
        lines.pop(0)
    while lines[len(lines) - 1].rstrip() == '':
        lines.pop(-1)
    return lines


Instruction:
Here you have a function in Python 3, explain what it does
def jstimestamp_slow(dte):
    '''Convert a date or datetime object into a javsacript timestamp'''
    year, month, day, hour, minute, second = dte.timetuple()[:6]
    days = date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
    hours = days*24 + hour
    minutes = hours*60 + minute
    seconds = minutes*60 + second
    if isinstance(dte,datetime):
        return 1000*seconds + 0.001*dte.microsecond
    else:
        return 1000*seconds

Response: Convert a date or datetime object into a javsacript timestamp


Instruction:
Can you tell what is the following Python 3 function doing
def jstimestamp(dte):
    '''Convert a date or datetime object into a javsacript timestamp.'''
    days = date(dte.year, dte.month, 1).toordinal() - _EPOCH_ORD + dte.day - 1
    hours = days*24

    if isinstance(dte,datetime):
        hours += dte.hour
        minutes = hours*60 + dte.minute
        seconds = minutes*60 + dte.second
        return 1000*seconds + int(0.001*dte.microsecond)
    else:
        return 3600000*hours

Response: Convert a date or datetime object into a javsacript timestamp.


Instruction:
How would you code a function in Python 3 to
convert a string or html file to an rst table string.

Response:
def html2rst(html_string, force_headers=False, center_cells=False,
             center_headers=False):
    """
    Convert a string or html file to an rst table string.

    Parameters
    ----------
    html_string : str
        Either the html string, or the filepath to the html
    force_headers : bool
        Make the first row become headers, whether or not they are
        headers in the html file.
    center_cells : bool
        Whether or not to center the contents of the cells
    center_headers : bool
        Whether or not to center the contents of the header cells

    Returns
    -------
    str
        The html table converted to an rst grid table

    Notes
    -----
    This function **requires** BeautifulSoup_ to work.

    Example
    -------
    >>> html_text = '''
    ...

    ...

    ...
    ...             Header 1
    ...
    ...
    ...             Header 2
    ...
    ...
    ...             Header 3
    ...
    ...

    ...
    ...
This is a paragraph

    ...
    ...
    ...

    ...
List item 1

    ...
List item 2

    ...

    ...
    ...
    ...

    ...
Ordered 1

    ...
Ordered 2

    ...

    ...
    ...

    ...

    ... '''
    >>> import dashtable
    >>> print(dashtable.html2rst(html_text))
    +---------------------+----------------+--------------+
    | Header 1            | Header 2       | Header 3     |
    +=====================+================+==============+
    | This is a paragraph | -  List item 1 | #. Ordered 1 |
    |                     | -  List item 2 | #. Ordered 2 |
    +---------------------+----------------+--------------+

    .. _BeautifulSoup: https://www.crummy.com/software/BeautifulSoup/
    """

    if os.path.isfile(html_string):
        file = open(html_string, 'r', encoding='utf-8')
        lines = file.readlines()
        file.close()
        html_string = ''.join(lines)

    table_data, spans, use_headers = html2data(
        html_string)

    if table_data == '':
        return ''
    if force_headers:
        use_headers = True

    return data2rst(table_data, spans, use_headers, center_cells, center_headers)


Instruction:
Write a Python 3 function for
creating a list of lists of rows and columns that will make up a span

Response:
def make_span(row, column, extra_rows, extra_columns):
    """
    Create a list of rows and columns that will make up a span

    Parameters
    ----------
    row : int
        The row of the first cell in the span
    column : int
        The column of the first cell in the span
    extra_rows : int
        The number of rows that make up the span
    extra_columns : int
        The number of columns that make up the span

    Returns
    -------
    span : list of lists of int
        A span is a list of [row, column] pairs that make up a span
    """
    span = [[row, column]]

    for r in range(row, row + extra_rows + 1):
        span.append([r, column])

    for c in range(column, column + extra_columns + 1):
        span.append([row, c])
    span.append([r, c])

    return span


Instruction:
Make a summary of the following Python 3 code
def make_cell(table, span, widths, heights, use_headers):
    width = get_span_char_width(span, widths)
    height = get_span_char_height(span, heights)
    text_row = span[0][0]
    text_column = span[0][1]
    text = table[text_row][text_column]

    lines = text.split("\n")
    for i in range(len(lines)):
        width_difference = width - len(lines[i])
        lines[i] = ''.join([lines[i], " " * width_difference])

    height_difference = height - len(lines)
    empty_lines = []
    for i in range(0, height_difference):
        empty_lines.append(" " * width)
    lines.extend(empty_lines)

    output = [
        ''.join(["+", (width * "-") + "+"])
    ]

    for i in range(0, height):
        output.append("|" + lines[i] + "|")

    if use_headers and span[0][0] == 0:
        symbol = "="
    else:
        symbol = "-"

    output.append(
        ''.join(["+", width * symbol, "+"])
    )

    text = "\n".join(output)

    row_count = get_span_row_count(span)
    column_count = get_span_column_count(span)

    cell = Cell(text, text_row, text_column, row_count, column_count)

    return cell

Response: Convert the contents of a span of a table to a grid table cell


Instruction:
Create a Python 3 function for
initializing the SQLAlchemy database.

Response:
def init_db(self, app, entry_point_group='invenio_db.models', **kwargs):
        """Initialize Flask-SQLAlchemy extension."""
        # Setup SQLAlchemy
        app.config.setdefault(
            'SQLALCHEMY_DATABASE_URI',
            'sqlite:///' + os.path.join(app.instance_path, app.name + '.db')
        )
        app.config.setdefault('SQLALCHEMY_ECHO', False)

        # Initialize Flask-SQLAlchemy extension.
        database = kwargs.get('db', db)
        database.init_app(app)

        # Initialize versioning support.
        self.init_versioning(app, database, kwargs.get('versioning_manager'))

        # Initialize model bases
        if entry_point_group:
            for base_entry in pkg_resources.iter_entry_points(
                    entry_point_group):
                base_entry.load()

        # All models should be loaded by now.
        sa.orm.configure_mappers()
        # Ensure that versioning classes have been built.
        if app.config['DB_VERSIONING']:
            manager = self.versioning_manager
            if manager.pending_classes:
                if not versioning_models_registered(manager, database.Model):
                    manager.builder.configure_versioned_classes()
            elif 'transaction' not in database.metadata.tables:
                manager.declarative_base = database.Model
                manager.create_transaction_model()
                manager.plugins.after_build_tx_class(manager)


Instruction:
How would you implement a function in Python 3 that
initializes the versioning support using SQLAlchemy - Continuum.

Response:
def init_versioning(self, app, database, versioning_manager=None):
        """Initialize the versioning support using SQLAlchemy-Continuum."""
        try:
            pkg_resources.get_distribution('sqlalchemy_continuum')
        except pkg_resources.DistributionNotFound:  # pragma: no cover
            default_versioning = False
        else:
            default_versioning = True

        app.config.setdefault('DB_VERSIONING', default_versioning)

        if not app.config['DB_VERSIONING']:
            return

        if not default_versioning:  # pragma: no cover
            raise RuntimeError(
                'Please install extra versioning support first by running '
                'pip install invenio-db[versioning].'
            )

        # Now we can import SQLAlchemy-Continuum.
        from sqlalchemy_continuum import make_versioned
        from sqlalchemy_continuum import versioning_manager as default_vm
        from sqlalchemy_continuum.plugins import FlaskPlugin

        # Try to guess user model class:
        if 'DB_VERSIONING_USER_MODEL' not in app.config:  # pragma: no cover
            try:
                pkg_resources.get_distribution('invenio_accounts')
            except pkg_resources.DistributionNotFound:
                user_cls = None
            else:
                user_cls = 'User'
        else:
            user_cls = app.config.get('DB_VERSIONING_USER_MODEL')

        plugins = [FlaskPlugin()] if user_cls else []

        # Call make_versioned() before your models are defined.
        self.versioning_manager = versioning_manager or default_vm
        make_versioned(
            user_cls=user_cls,
            manager=self.versioning_manager,
            plugins=plugins,
        )

        # Register models that have been loaded beforehand.
        builder = self.versioning_manager.builder

        for tbl in database.metadata.tables.values():
            builder.instrument_versioned_classes(
                database.mapper, get_class_by_table(database.Model, tbl)
            )


Instruction:
Can you write a function in Python 3 where it
converts an html string to data table

Response:
def extract_table(html_string, row_count, column_count):
    """
    Convert an html string to data table

    Parameters
    ----------
    html_string : str
    row_count : int
    column_count : int

    Returns
    -------
    data_table : list of lists of str
    """
    try:
        from bs4 import BeautifulSoup
        from bs4.element import Tag
    except ImportError:
        print("ERROR: You must have BeautifulSoup to use html2data")
        return

    #html_string = convertRichText(html_string)

    data_table = []
    for row in range(0, row_count):
        data_table.append([])
        for column in range(0, column_count):
            data_table[-1].append(None)

    soup = BeautifulSoup(html_string, 'html.parser')

    table = soup.find('table')

    if not table:
        return ''

    trs = table.findAll('tr')
    if len(trs) == 0:
        return [['']]

    for tr in range(len(trs)):
        ths = trs[tr].findAll('th')
        if len(ths) == 0:
            tds = trs[tr].findAll('td')
        else:
            tds = ths

        if len(tds) == 0:
            tds = []
            for i in range(0, column_count):
                tds.append(Tag("", name=""))

        for i in range(len(tds)):
            td = tds[i]
            row, column = find_unassigned_table_cell(data_table)

            r_span_count = 1
            c_span_count = 1

            if td.has_attr('rowspan'):
                r_span_count = int(td['rowspan'])
            if td.has_attr('colspan'):
                c_span_count = int(td['colspan'])

            for row_prime in range(row, row + r_span_count):
                for column_prime in range(column, column + c_span_count):
                    if row_prime == row and column_prime == column:

                        items = []
                        for item in td.contents:
                            items.append(str(item))
                        string = ''.join(items).strip()

                        text = restructify(string).rstrip()

                        data_table[row_prime][column_prime] = text
                    else:
                        data_table[row_prime][column_prime] = ""

            if i + 1 < column_count and i == len(tds) - 1:
                for x in range(len(tds), column_count):
                    if data_table[row][x] is None:
                        data_table[row][x] = ""
    for row in range(len(data_table)):
        for column in range(len(data_table[row])):
            if not data_table[row][column]:
                data_table[row][column] = ""

    return data_table


Instruction:
Implement a Python 3 function for
ensuring SQLite checks foreign key constraints.

Response:
def do_sqlite_connect(dbapi_connection, connection_record):
    """Ensure SQLite checks foreign key constraints.

    For further details see "Foreign key support" sections on
    https://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support
    """
    # Enable foreign key constraint checking
    cursor = dbapi_connection.cursor()
    cursor.execute('PRAGMA foreign_keys=ON')
    cursor.close()


Instruction:
Write a Python 3 function for
applying hacks defined on the SQLAlchemy object.

Response:
def apply_driver_hacks(self, app, info, options):
        """Call before engine creation."""
        # Don't forget to apply hacks defined on parent object.
        super(SQLAlchemy, self).apply_driver_hacks(app, info, options)

        if info.drivername == 'sqlite':
            connect_args = options.setdefault('connect_args', {})

            if 'isolation_level' not in connect_args:
                # disable pysqlite's emitting of the BEGIN statement entirely.
                # also stops it from emitting COMMIT before any DDL.
                connect_args['isolation_level'] = None

            if not event.contains(Engine, 'connect', do_sqlite_connect):
                event.listen(Engine, 'connect', do_sqlite_connect)
            if not event.contains(Engine, 'begin', do_sqlite_begin):
                event.listen(Engine, 'begin', do_sqlite_begin)

            from sqlite3 import register_adapter

            def adapt_proxy(proxy):
                """Get current object and try to adapt it again."""
                return proxy._get_current_object()

            register_adapter(LocalProxy, adapt_proxy)

        elif info.drivername == 'postgresql+psycopg2':  # pragma: no cover
            from psycopg2.extensions import adapt, register_adapter

            def adapt_proxy(proxy):
                """Get current object and try to adapt it again."""
                return adapt(proxy._get_current_object())

            register_adapter(LocalProxy, adapt_proxy)

        elif info.drivername == 'mysql+pymysql':  # pragma: no cover
            from pymysql import converters

            def escape_local_proxy(val, mapping):
                """Get current object and try to adapt it again."""
                return converters.escape_item(
                    val._get_current_object(),
                    self.engine.dialect.encoding,
                    mapping=mapping,
                )

            converters.conversions[LocalProxy] = escape_local_proxy
            converters.encoders[LocalProxy] = escape_local_proxy


Instruction:
How would you explain what the following Python 3 function does
def rolling(self, op):
        missing   = self.missing
        ismissing = self.ismissing
        window = self.window
        it = iter(self.iterable)
        queue = deque(islice(it, window))
        ol = self.skiplist((e for e in queue if e == e))
        yield op(ol,missing)
        for newelem in it:
            oldelem = queue.popleft()
            if not ismissing(oldelem):
                ol.remove(oldelem)
            queue.append(newelem)
            if not ismissing(newelem):
                ol.insert(newelem)
            yield op(ol, missing)

Response: Fast rolling operation with O ( log n ) updates where n is the window size


Instruction:
How would you explain what the following Python 3 function does
def get_span_column_count(span):
    columns = 1
    first_column = span[0][1]

    for i in range(len(span)):
        if span[i][1] > first_column:
            columns += 1
            first_column = span[i][1]

    return columns

Response: Returns the number of columns in a single column.


Instruction:
Create a Python 3 function to
return self as a dictionary with _underscore subdicts corrected.

Response:
def to_dict(self):
        "returns self as a dictionary with _underscore subdicts corrected."
        ndict = {}
        for key, val in self.__dict__.items():
            if key[0] == "_":
                ndict[key[1:]] = val
            else:
                ndict[key] = val
        return ndict


Instruction:
Implement a function in Python 3 to
return the total width of the column widths that make up the span plus the extra.

Response:
def get_span_char_width(span, column_widths):
    """
    Sum the widths of the columns that make up the span, plus the extra.

    Parameters
    ----------
    span : list of lists of int
        list of [row, column] pairs that make up the span
    column_widths : list of int
        The widths of the columns that make up the table

    Returns
    -------
    total_width : int
        The total width of the span
    """

    start_column = span[0][1]
    column_count = get_span_column_count(span)
    total_width = 0

    for i in range(start_column, start_column + column_count):
        total_width += column_widths[i]

    total_width += column_count - 1

    return total_width


Instruction:
Implement a function in Python 3 to
rebuild a model s EncryptedType properties when the SECRET_KEY is changed.

Response:
def rebuild_encrypted_properties(old_key, model, properties):
    """Rebuild a model's EncryptedType properties when the SECRET_KEY is changed.

    :param old_key: old SECRET_KEY.
    :param model: the affected db model.
    :param properties: list of properties to rebuild.
    """
    inspector = reflection.Inspector.from_engine(db.engine)
    primary_key_names = inspector.get_primary_keys(model.__tablename__)

    new_secret_key = current_app.secret_key
    db.session.expunge_all()
    try:
        with db.session.begin_nested():
            current_app.secret_key = old_key
            db_columns = []
            for primary_key in primary_key_names:
                db_columns.append(getattr(model, primary_key))
            for prop in properties:
                db_columns.append(getattr(model, prop))
            old_rows = db.session.query(*db_columns).all()
    except Exception as e:
        current_app.logger.error(
            'Exception occurred while reading encrypted properties. '
            'Try again before starting the server with the new secret key.')
        raise e
    finally:
        current_app.secret_key = new_secret_key
        db.session.expunge_all()

    for old_row in old_rows:
        primary_keys, old_entries = old_row[:len(primary_key_names)], \
                                    old_row[len(primary_key_names):]
        primary_key_fields = dict(zip(primary_key_names, primary_keys))
        update_values = dict(zip(properties, old_entries))
        model.query.filter_by(**primary_key_fields).\
            update(update_values)
    db.session.commit()


Instruction:
Implement a Python 3 function for
getting the name of the versioned model class.

Response:
def versioning_model_classname(manager, model):
    """Get the name of the versioned model class."""
    if manager.options.get('use_module_name', True):
        return '%s%sVersion' % (
            model.__module__.title().replace('.', ''), model.__name__)
    else:
        return '%sVersion' % (model.__name__,)


Instruction:
Here you have a function in Python 3, explain what it does
def versioning_models_registered(manager, base):
    declared_models = base._decl_class_registry.keys()
    return all(versioning_model_classname(manager, c) in declared_models
               for c in manager.pending_classes)

Response: Return True if all versioning models have been registered.


Instruction:
Can you generate the documentation for the following Python 3 function
def vector_to_symmetric(v):
    '''Convert an iterable into a symmetric matrix.'''
    np = len(v)
    N = (int(sqrt(1 + 8*np)) - 1)//2
    if N*(N+1)//2 != np:
        raise ValueError('Cannot convert vector to symmetric matrix')
    sym = ndarray((N,N))
    iterable = iter(v)
    for r in range(N):
        for c in range(r+1):
            sym[r,c] = sym[c,r] = iterable.next()
    return sym

Response: Convert an iterable into a symmetric matrix.


Instruction:
Can you tell what is the following Python 3 function doing
def cov(self, ddof=None, bias=0):
        '''The covariance matrix from the aggregate sample. It accepts an
        optional parameter for the degree of freedoms.

        :parameter ddof: If not ``None`` normalization is by (N - ddof), where N is
            the number of observations; this overrides the value implied by bias.
            The default value is None.
        '''
        N = self.n
        M = N if bias else N-1
        M = M if ddof is None else N-ddof
        return (self.sxx - outer(self.sx,self.sx)/N)/M

Response: The covariance matrix from the aggregate sample. It accepts an optional parameter for the degree of freedoms.


Instruction:
How would you code a function in Python 3 to
calculate the Calmar ratio for a Weiner process

Response:
def calmar(sharpe, T = 1.0):
    '''
    Calculate the Calmar ratio for a Weiner process

    @param sharpe:    Annualized Sharpe ratio
    @param T:         Time interval in years
    '''
    x = 0.5*T*sharpe*sharpe
    return x/qp(x)


Instruction:
Write a Python 3 function for
converting a table of data to a simple rst table.

Response:
def data2simplerst(table, spans=[[[0, 0]]], use_headers=True, headers_row=0):
    """
    Convert table data to a simple rst table

    Parameters
    ----------
    table : list of lists of str
        A table of strings.
    spans : list of lists of lists of int
        A list of spans. A span is a list of [Row, Column] pairs of
        table cells that are joined together.
    use_headers : bool, optional
        Whether or not to include headers in the table. A header is
        a cell that is underlined with "="
    headers_row : int
        The row that will be the headers. In a simple rst table, the
        headers do not need to be at the top.

    Returns
    -------
    str
        The simple rst table

    Example
    -------
    >>> table = [
    ...     ["Inputs", "", "Output"],
    ...     ["A", "B", "A or B"],
    ...     ["False", "False", "False"],
    ...     ["True", "False", "True"],
    ...     ["False", "True", "True"],
    ...     ["True", "True", "True"],
    ... ]
    >>> spans = [
    ...     [ [0, 0], [0, 1] ]
    ... ]
    >>> print(data2simplerst(table, spans, headers_row=1))
    ======  =====  ======
       Inputs      Output
    -------------  ------
      A       B    A or B
    ======  =====  ======
    False   False  False
     True   False   True
    False   True    True
     True   True    True
    ======  =====  ======
    """

    table = copy.deepcopy(table)

    table_ok = check_table(table)
    if not table_ok == "":
        return "ERROR: " + table_ok

    if not spans == [[[0, 0]]]:
        for span in spans:
            span_ok = check_span(span, table)
            if not span_ok == "":
                return "ERROR: " + span_ok

    table = ensure_table_strings(table)
    table = multis_2_mono(table)

    output = []

    column_widths = []
    for col in table[0]:
        column_widths.append(0)
    for row in range(len(table)):
        for column in range(len(table[row])):
            if len(table[row][column]) > column_widths[column]:
                column_widths[column] = len(table[row][column])

    underline = ''
    for col in column_widths:
        underline = ''.join([underline + col * '=', '  '])

    output.append(underline)

    for row in range(len(table)):
        string = ''
        column = 0

        while column < len(table[row]):
            span = get_span(spans, row, column)

            if (span and span[0] == [row, column] and
                    not table[row][column] == ''):
                span_col_count = get_span_column_count(span)

                end_col = column + span_col_count
                width = sum(column_widths[column:end_col])
                width += 2 * (span_col_count - 1)

                string += center_line(width, table[row][column]) + '  '

            elif table[row][column] == '':
                pass

            else:
                string += center_line(
                    column_widths[column], table[row][column]) + '  '

            column += 1

        output.append(string)

        if row == headers_row and use_headers:
            output.append(underline)

        else:
            if row_includes_spans(table, row, spans):
                new_underline = ''
                column = 0
                while column < len(table[row]):
                    span = get_span(spans, row, column)
                    if (span and span[0] == [row, column] and
                            not table[row][column] == ''):
                        span_col_count = get_span_column_count(span)

                        end_column = column + span_col_count
                        width = sum(column_widths[column:end_column])
                        width += 2 * (span_col_count - 1)

                        new_underline += (width * '-') + '  '

                    elif table[row][column] == '':
                        pass

                    else:
                        new_underline += (column_widths[column] * '-') + '  '
                    column += 1
                output.append(new_underline)

    for i in range(len(output)):
        output[i] = output[i].rstrip()

    output.append(underline)

    return '\n'.join(output)


Instruction:
Make a summary of the following Python 3 code
def add_links(converted_text, html):
    soup = BeautifulSoup(html, 'html.parser')

    link_exceptions = [
        'footnote-reference',
        'fn-backref',
        'citation-reference'
    ]

    footnotes = {}
    citations = {}
    backrefs = {}

    links = soup.find_all('a')
    for link in links:
        href = link.get('href')
        text = process_tag(link)
        classes = dict(link.attrs).get('class', '')

        if 'footnote-reference' in classes:
            footnotes[href] = '#' + link.get('id')

        elif 'citation-reference' in classes:
            text = process_tag(link)
            citations[text] = '#' + link.get('id')

        elif 'fn-backref' in classes:
            sibling = link.findNext('td')
            text = process_tag(sibling)
            backrefs[href] = text

        excepted_link = False
        for class_type in classes:
            if class_type in link_exceptions:
                excepted_link = True

        if not excepted_link:
            if text.endswith('_'):
                text = text[0:-1]
            if len(text.split(' ')) > 1:
                text = text[1:-1]
            converted_text += '.. _' + text + ': ' + href + '\n'

    if len(footnotes.keys()) > 0:
        converted_text += '\n'

    for key in footnotes.keys():
        text = backrefs[footnotes[key]]
        converted_text += '.. [' + key + '] ' + text + '\n'

    if len(citations.keys()) > 0:
        converted_text += '\n'

    for key in citations.keys():
        text = backrefs[citations[key]]
        converted_text += '.. ' + key[0:-1] + ' ' + text + '\n'

    return converted_text.rstrip()

Response: Add the links to the bottom of the text


Instruction:
How would you explain what the following Python 3 function does
def load(self, providers, symbols, start, end, logger, backend, **kwargs):
        '''Load symbols data.

        :keyword providers: Dictionary of registered data providers.
        :keyword symbols: list of symbols to load.
        :keyword start: start date.
        :keyword end: end date.
        :keyword logger: instance of :class:`logging.Logger` or ``None``.
        :keyword backend: :class:`dynts.TimeSeries` backend name.

        There is no need to override this function, just use one
        the three hooks available.
        '''
        # Preconditioning on dates
        logger = logger or logging.getLogger(self.__class__.__name__)
        start, end = self.dates(start, end)
        data = {}
        for sym in symbols:
            # Get ticker, field and provider
            symbol = self.parse_symbol(sym, providers)
            provider = symbol.provider
            if not provider:
                raise MissingDataProvider(
                    'data provider for %s not available' % sym
                )
            pre = self.preprocess(symbol, start, end, logger, backend, **kwargs)
            if pre.intervals:
                result = None
                for st, en in pre.intervals:
                    logger.info('Loading %s from %s. From %s to %s',
                                symbol.ticker, provider, st, en)
                    res = provider.load(symbol, st, en, logger, backend,
                                        **kwargs)
                    if result is None:
                        result = res
                    else:
                        result.update(res)
            else:
                result = pre.result
            # onresult hook
            result = self.onresult(symbol, result, logger, backend, **kwargs)
            data[sym] = result
        # last hook
        return self.onfinishload(data, logger, backend, **kwargs)

Response: Load symbols data from the given provider and list of symbols.


Instruction:
Write a Python 3 script for
parsing a symbol to obtain information regarding ticker field and provider. Must return an instance of SymbolData.

Response:
def parse_symbol(self, symbol, providers):
        '''Parse a symbol to obtain information regarding ticker,
        field and provider. Must return an instance of :attr:`symboldata`.

        :keyword symbol: string associated with market data to load.
        :keyword providers: dictionary of :class:`dynts.data.DataProvider`
                            instances available.

        For example::

            intc
            intc:open
            intc:volume:google
            intc:google

        are all valid inputs returning a :class:`SymbolData` instance with
        the following triplet of information::

            intc,None,yahoo
            intc,open,yahoo
            intc,volume,google
            intc,None,google

        assuming ``yahoo`` is the provider in
        :attr:`dynts.conf.Settings.default_provider`.

        This function is called before retrieving data.
        '''
        separator = settings.field_separator
        symbol = str(symbol)
        bits = symbol.split(separator)
        pnames = providers.keys()
        ticker = symbol
        provider = None
        field = None
        if len(bits) == 2:
            ticker = bits[0]
            if bits[1] in pnames:
                provider = bits[1]
            else:
                field = bits[1]
        elif len(bits) == 3:
            ticker = bits[0]
            if bits[1] in pnames:
                provider = bits[1]
                field = bits[2]
            elif bits[2] in pnames:
                provider = bits[2]
                field = bits[1]
            else:
                raise BadSymbol(
                        'Could not parse %s. Unrecognized provider.' % symbol)
        elif len(bits) > 3:
            raise BadSymbol('Could not parse %s.' % symbol)

        return self.symbol_for_ticker(ticker, field, provider, providers)


Instruction:
How would you explain what the following Python 3 function does
def symbol_for_ticker(self, ticker, field, provider, providers):
        '''Return an instance of *symboldata* containing
information about the data provider, the data provider ticker name
and the data provider field.'''
        provider = provider or settings.default_provider
        if provider:
            provider = providers.get(provider, None)
        return self.symboldata(ticker, field, provider)

Response:
Return an instance of *symboldata* containing the data provider ticker name
and the data provider field.


Instruction:
Explain what the following Python 3 code does
def preprocess(self, ticker, start, end, logger, backend, **kwargs):
        '''Preprocess **hook**. This is first loading hook and it is
**called before requesting data** from a dataprovider.
It must return an instance of :attr:`TimeSerieLoader.preprocessdata`.
By default it returns::

    self.preprocessdata(intervals = ((start,end),))

It could be overritten to modify the intervals.
If the intervals is ``None`` or an empty container,
the :func:`dynts.data.DataProvider.load` method won't be called,
otherwise it will be called as many times as the number of intervals
in the return tuple (by default once).
'''
        return self.preprocessdata(intervals = ((start, end),))

Response: Preprocess the data from a data provider.


Instruction:
Here you have a function in Python 3, explain what it does
def register(self, provider):
        '''Register a new data provider. *provider* must be an instance of
    DataProvider. If provider name is already available, it will be replaced.'''
        if isinstance(provider,type):
            provider = provider()
        self[provider.code] = provider

Response: Register a new data provider.


Instruction:
Explain what the following Python 3 code does
def parse(timeseries_expression, method=None, functions=None, debug=False):
    '''Function for parsing :ref:`timeseries expressions <dsl-script>`.
    If succesful, it returns an instance of :class:`dynts.dsl.Expr` which
    can be used to to populate timeseries or scatters once data is available.

    Parsing is implemented using the ply_ module,
    an implementation of lex and yacc parsing tools for Python.

    :parameter expression: A :ref:`timeseries expressions <dsl-script>` string.
    :parameter method: Not yet used.
    :parameter functions: dictionary of functions to use when parsing.
        If not provided the :data:`dynts.function_registry`
        will be used.

        Default ``None``.
    :parameter debug: debug flag for ply_.  Default ``False``.

    For examples and usage check the :ref:`dsl documentation <dsl>`.

    .. _ply: http://www.dabeaz.com/ply/
    '''
    if not parsefunc:
        raise ExpressionError('Could not parse. No parser installed.')
    functions = functions if functions is not None else function_registry
    expr_str = str(timeseries_expression).lower()
    return parsefunc(expr_str, functions, method, debug)

Response: Function for parsing a time series expression.


Instruction:
Make a summary of the following Python 3 code
def evaluate(expression, start=None, end=None, loader=None, logger=None,
             backend=None, **kwargs):
    '''Evaluate a timeseries ``expression`` into
    an instance of :class:`dynts.dsl.dslresult` which can be used
    to obtain timeseries and/or scatters.
    This is probably the most used function of the library.

    :parameter expression: A timeseries expression string or an instance
        of :class:`dynts.dsl.Expr` obtained using the :func:`~.parse`
        function.
    :parameter start: Start date or ``None``.
    :parameter end: End date or ``None``. If not provided today values is used.
    :parameter loader: Optional :class:`dynts.data.TimeSerieLoader`
        class or instance to use.

        Default ``None``.
    :parameter logger: Optional python logging instance, used if you required
        logging.

        Default ``None``.
    :parameter backend: :class:`dynts.TimeSeries` backend name or ``None``.

    The ``expression`` is parsed and the :class:`~.Symbol` are sent to the
    :class:`dynts.data.TimeSerieLoader` instance for retrieving
    actual timeseries data.
    It returns an instance of :class:`~.DSLResult`.

    Typical usage::

        >>> from dynts import api
        >>> r = api.evaluate('min(GS,window=30)')
        >>> r
        min(GS,window=30)
        >>> ts = r.ts()
    '''
    if isinstance(expression, str):
        expression = parse(expression)
    if not expression or expression.malformed():
        raise CouldNotParse(expression)
    symbols = expression.symbols()
    start = start if not start else todate(start)
    end = end if not end else todate(end)
    data = providers.load(symbols, start, end, loader=loader,
                          logger=logger, backend=backend, **kwargs)
    return DSLResult(expression, data, backend=backend)

Response: Evaluate a timeseries expression into a list of time series objects.


Instruction:
Can you generate the documentation for the following Python 3 function
def get_consensus_tree(self, cutoff=0.0, best_tree=None):
        if best_tree:
            raise NotImplementedError("best_tree option not yet supported.")
        cons = ConsensusTree(self.treelist, cutoff)
        cons.update()
        return cons.ttree

Response: Returns an extended majority rule consensus tree as a Toytree object.


Instruction:
Can you tell what is the following Python 3 function doing
def draw_tree_grid(self,
        nrows=None,
        ncols=None,
        start=0,
        fixed_order=False,
        shared_axis=False,
        **kwargs):
        """
        Draw a slice of x*y trees into a x,y grid non-overlapping.

        Parameters:
        -----------
        x (int):
            Number of grid cells in x dimension. Default=automatically set.
        y (int):
            Number of grid cells in y dimension. Default=automatically set.
        start (int):
            Starting index of tree slice from .treelist.
        kwargs (dict):
            Toytree .draw() arguments as a dictionary.
        """
        # return nothing if tree is empty
        if not self.treelist:
            print("Treelist is empty")
            return None, None

        # make a copy of the treelist so we don't modify the original
        if not fixed_order:
            treelist = self.copy().treelist
        else:
            if fixed_order is True:
                fixed_order = self.treelist[0].get_tip_labels()
            treelist = [
                ToyTree(i, fixed_order=fixed_order)
                for i in self.copy().treelist
            ]

        # apply kwargs styles to the individual tree styles
        for tree in treelist:
            tree.style.update(kwargs)

        # get reasonable values for x,y given treelist length
        if not (ncols or nrows):
            ncols = 5
            nrows = 1
        elif not (ncols and nrows):
            if ncols:
                if ncols == 1:
                    if self.ntrees <= 5:
                        nrows = self.ntrees
                    else:
                        nrows = 2
                else:
                    if self.ntrees <= 10:
                        nrows = 2
                    else:
                        nrows = 3

            if nrows:
                if nrows == 1:
                    if self.ntrees <= 5:
                        ncols = self.ntrees
                    else:
                        ncols = 5
                else:
                    if self.ntrees <= 10:
                        ncols = 5
                    else:
                        ncols = 3
        else:
            pass

        # Return TereGrid object for debugging
        draw = TreeGrid(treelist)
        if kwargs.get("debug"):
            return draw

        # Call update to draw plot. Kwargs still here for width, height, axes
        canvas, axes = draw.update(nrows, ncols, start, shared_axis, **kwargs)
        return canvas, axes

Response: Draw a slice of x * y trees into a x y grid.


Instruction:
Can you generate the documentation for the following Python 3 function
def draw_cloud_tree(self,
        axes=None,
        html=False,
        fixed_order=True,
        **kwargs):
        """
        Draw a series of trees overlapping each other in coordinate space.
        The order of tip_labels is fixed in cloud trees so that trees with
        discordant relationships can be seen in conflict. To change the tip
        order use the 'fixed_order' argument in toytree.mtree() when creating
        the MultiTree object.

        Parameters:
            axes (toyplot.Cartesian): toyplot Cartesian axes object.
            html (bool): whether to return the drawing as html (default=PNG).
            edge_styles: (list): option to enter a list of edge dictionaries.
            **kwargs (dict): styling options should be input as a dictionary.
        """
        # return nothing if tree is empty
        if not self.treelist:
            print("Treelist is empty")
            return None, None

        # return nothing if tree is empty
        if not self.all_tips_shared:
            print("All trees in treelist do not share the same tips")
            return None, None

        # make a copy of the treelist so we don't modify the original
        if not fixed_order:
            raise Exception(
                "fixed_order must be either True or a list with the tip order")

        # set fixed order on a copy of the tree list
        if isinstance(fixed_order, (list, tuple)):
            pass
        elif fixed_order is True:
            fixed_order = self.treelist[0].get_tip_labels()
        else:
            raise Exception(
                "fixed_order argument must be True or a list with the tip order")
        treelist = [
            ToyTree(i, fixed_order=fixed_order) for i in self.copy().treelist
        ]

        # give advice if user tries to enter tip_labels
        if kwargs.get("tip_labels"):
            print(TIP_LABELS_ADVICE)

        # set autorender format to png so we don't bog down notebooks
        try:
            changed_autoformat = False
            if not html:
                toyplot.config.autoformat = "png"
                changed_autoformat = True

            # dict of global cloud tree style
            mstyle = STYLES['m']

            # if trees in treelist already have some then we don't quash...
            mstyle.update(
                {i: j for (i, j) in kwargs.items() if
                (j is not None) & (i != "tip_labels")}
            )
            for tree in treelist:
                tree.style.update(mstyle)

            # Send a copy of MultiTree to init Drawing object.
            draw = CloudTree(treelist, **kwargs)

            # and create drawing
            if kwargs.get("debug"):
                return draw

            # allow user axes, and kwargs for width, height
            canvas, axes = draw.update(axes)
            return canvas, axes

        finally:
            if changed_autoformat:
                toyplot.config.autoformat = "html"

Response: Draw a series of trees overlapping each other in coordinate space.


Instruction:
How would you code a function in Python 3 to
hash ladderized tree topologies

Response:
def hash_trees(self):
        "hash ladderized tree topologies"
        observed = {}
        for idx, tree in enumerate(self.treelist):
            nwk = tree.write(tree_format=9)
            hashed = md5(nwk.encode("utf-8")).hexdigest()
            if hashed not in observed:
                observed[hashed] = idx
                self.treedict[idx] = 1
            else:
                idx = observed[hashed]
                self.treedict[idx] += 1


Instruction:
Can you generate a brief explanation for the following Python 3 code
def filter_clades(self):
        "Remove conflicting clades and those < cutoff to get majority rule"
        passed = []
        carrs = np.array([list(i[0]) for i in self.clade_counts], dtype=int)
        freqs = np.array([i[1] for i in self.clade_counts])

        for idx in range(carrs.shape[0]):
            conflict = False
            if freqs[idx] < self.cutoff:
                continue

            for pidx in passed:
                intersect = np.max(carrs[idx] + carrs[pidx]) > 1

                # is either one a subset of the other?
                subset_test0 = np.all(carrs[idx] - carrs[pidx] >= 0)
                subset_test1 = np.all(carrs[pidx] - carrs[idx] >= 0)
                if intersect:
                    if (not subset_test0) and (not subset_test1):
                        conflict = True

            if not conflict:
                passed.append(idx)

        rclades = []
        for idx in passed:
            rclades.append((carrs[idx], freqs[idx]))
        self.fclade_counts = rclades

Response: Remove conflicting clades and those < cutoff to get majority rule


Instruction:
Can you tell what is the following Python 3 function doing
def build_trees(self):
        "Build an unrooted consensus tree from filtered clade counts."

        # storage
        nodes = {}
        idxarr = np.arange(len(self.fclade_counts[0][0]))
        queue = []

        ## create dict of clade counts and set keys
        countdict = defaultdict(int)
        for clade, count in self.fclade_counts:
            mask = np.int_(list(clade)).astype(np.bool)
            ccx = idxarr[mask]
            queue.append((len(ccx), frozenset(ccx)))
            countdict[frozenset(ccx)] = count

        while queue:
            queue.sort()
            (clade_size, clade) = queue.pop(0)
            new_queue = []

            # search for ancestors of clade
            for (_, ancestor) in queue:
                if clade.issubset(ancestor):
                    # update ancestor such that, in the following example:
                    # ancestor == {1, 2, 3, 4}
                    # clade == {2, 3}
                    # new_ancestor == {1, {2, 3}, 4}
                    new_ancestor = (ancestor - clade) | frozenset([clade])
                    countdict[new_ancestor] = countdict.pop(ancestor)
                    ancestor = new_ancestor

                new_queue.append((len(ancestor), ancestor))

            # if the clade is a tip, then we have a name
            if clade_size == 1:
                name = list(clade)[0]
                name = self.namedict[name]
            else:
                name = None

            # the clade will not be in nodes if it is a tip
            children = [nodes.pop(c) for c in clade if c in nodes]
            node = TreeNode(name=name)
            for child in children:
                node.add_child(child)
            if not node.is_leaf():
                node.dist = int(round(100 * countdict[clade]))
                node.support = int(round(100 * countdict[clade]))
            else:
                node.dist = int(100)
                node.support = int(100)

            nodes[clade] = node
            queue = new_queue
        nodelist = list(nodes.values())
        tre = nodelist[0]

        #tre.unroot()
        ## return the tree and other trees if present
        self.ttree = ToyTree(tre.write(format=0))
        self.ttree._coords.update()
        self.nodelist = nodelist

Response: Build an unrooted consensus tree from filtered clade counts.


Instruction:
Write a Python 3 script for
comparing the phonetic representations of 2 words and return a boolean value.

Response:
def sounds_like(self, word1, word2):
        """Compare the phonetic representations of 2 words, and return a boolean value."""
        return self.phonetics(word1) == self.phonetics(word2)


Instruction:
Write a Python 3 function for
getting the similarity of the words in the sequence.

Response:
def distance(self, word1, word2, metric='levenshtein'):
        """Get the similarity of the words, using the supported distance metrics."""
        if metric in self.distances:
            distance_func = self.distances[metric]
            return distance_func(self.phonetics(word1), self.phonetics(word2))
        else:
            raise DistanceMetricError('Distance metric not supported! Choose from levenshtein, hamming.')


Instruction:
Given the following Python 3 function, write the documentation
def get_output_row_heights(table, spans):
    heights = []
    for row in table:
        heights.append(-1)

    for row in range(len(table)):
        for column in range(len(table[row])):
            text = table[row][column]
            span = get_span(spans, row, column)
            row_count = get_span_row_count(span)
            height = len(text.split('\n'))
            if row_count == 1 and height > heights[row]:
                heights[row] = height

    for row in range(len(table)):
        for column in range(len(table[row])):
            span = get_span(spans, row, column)
            row_count = get_span_row_count(span)
            if row_count > 1:
                text_row = span[0][0]
                text_column = span[0][1]

                end_row = text_row + row_count

                text = table[text_row][text_column]

                height = len(text.split('\n')) - (row_count - 1)

                add_row = 0
                while height > sum(heights[text_row:end_row]):
                    heights[text_row + add_row] += 1
                    if add_row + 1 < row_count:
                        add_row += 1
                    else:
                        add_row = 0
    return heights

Response: Get the heights of the rows of the output table.


Instruction:
Given the following Python 3 function, write the documentation
def smedian(olist,nobs):
    '''Generalised media for odd and even number of samples'''
    if nobs:
        rem = nobs % 2
        midpoint = nobs // 2
        me = olist[midpoint]
        if not rem:
            me = 0.5 * (me + olist[midpoint-1])
        return me
    else:
        return NaN

Response: Generalised media for odd and even number of samples


Instruction:
Create a Python 3 function for
applying a rolling mean function to an array.

Response:
def roll_mean(input, window):
    '''Apply a rolling mean function to an array.
This is a simple rolling aggregation.'''
    nobs, i, j, sum_x = 0,0,0,0.
    N = len(input)

    if window > N:
        raise ValueError('Out of bound')

    output = np.ndarray(N-window+1,dtype=input.dtype)

    for val in input[:window]:
        if val == val:
            nobs += 1
            sum_x += val

    output[j] = NaN if not nobs else sum_x / nobs

    for val in input[window:]:
        prev = input[j]
        if prev == prev:
            sum_x -= prev
            nobs -= 1

        if val == val:
            nobs += 1
            sum_x += val

        j += 1
        output[j] = NaN if not nobs else sum_x / nobs

    return output


Instruction:
Make a summary of the following Python 3 code
def roll_sd(input, window, scale = 1.0, ddof = 0):
    '''Apply a rolling standard deviation function
to an array. This is a simple rolling aggregation of squared
sums.'''
    nobs, i, j, sx, sxx = 0,0,0,0.,0.
    N = len(input)
    sqrt = np.sqrt

    if window > N:
        raise ValueError('Out of bound')

    output = np.ndarray(N-window+1,dtype=input.dtype)

    for val in input[:window]:
        if val == val:
            nobs += 1
            sx += val
            sxx += val*val

    nn = nobs - ddof
    output[j] = NaN if nn<=0 else sqrt(scale * (sxx - sx*sx/nobs) / nn)

    for val in input[window:]:
        prev = input[j]
        if prev == prev:
            sx -= prev
            sxx -= prev*prev
            nobs -= 1

        if val == val:
            nobs += 1
            sx += val
            sxx += val*val

        j += 1
        nn = nobs - ddof
        output[j] = NaN if nn<=0 else sqrt(scale * (sxx - sx*sx/nobs) / nn)

    return output

Response:
Apply a rolling standard deviation function
            to an array. This is a simple rolling aggregation of squared
Tuples.


Instruction:
Can you tell what is the following Python 3 function doing
def check_span(span, table):

    if not type(span) is list:
        return "Spans must be a list of lists"

    for pair in span:
        if not type(pair) is list:
            return "Spans must be a list of lists of int"
        if not len(pair) == 2:
            return "Spans must be a [Row, Column] pair of integers"

    total_rows = get_span_row_count(span)
    total_columns = get_span_column_count(span)

    if not len(span) == total_rows * total_columns:
        return ''.join(["Spans must be rectangular in shape. ",
                        str(span) + " is invalid"])

    if max(span, key=lambda x: x[0])[0] > len(table) - 1:
        return ' '.join(["One of the span's rows extends beyond the",
                         "bounds of the table:", str(span)])

    if max(span, key=lambda x: x[1])[1] > len(table[0]) - 1:
        return ' '.join(["One of the span's columns extends beyond the",
                         "bounds of the table:", str(span)])

    test_span = copy.deepcopy(span)

    checked = [test_span.pop(0)]

    while len(test_span) > 0:
        row = test_span[0][0]
        col = test_span[0][1]
        matched = False

        for i in range(len(checked)):
            if row == checked[i][0] and abs(col - checked[i][1]) == 1:
                matched = True

            elif abs(row - checked[i][0]) == 1 and col == checked[i][1]:
                matched = True

        if matched:
            checked.append(test_span.pop(0))

        else:
            checked.extend(test_span)
            return 'This span is not valid: ' + str(checked)

    return ""

Response: Checks that the given span is valid.


Instruction:
Explain what the following Python 3 code does
def merge_all_cells(cells):
    current = 0

    while len(cells) > 1:
        count = 0

        while count < len(cells):
            cell1 = cells[current]
            cell2 = cells[count]

            merge_direction = get_merge_direction(cell1, cell2)
            if not merge_direction == "NONE":
                merge_cells(cell1, cell2, merge_direction)

                if current > count:
                    current -= 1

                cells.pop(count)

            else:
                count += 1

        current += 1

        if current >= len(cells):
            current = 0

    return cells[0].text

Response: Loop through list of cells and piece them together one by one.


Instruction:
Can you generate the documentation for the following Python 3 function
def bpp2newick(bppnewick):
    "converts bpp newick format to normal newick"
    regex1 = re.compile(r" #[-+]?[0-9]*\.?[0-9]*[:]")
    regex2 = re.compile(r" #[-+]?[0-9]*\.?[0-9]*[;]")
    regex3 = re.compile(r": ")
    new = regex1.sub(":", bppnewick)
    new = regex2.sub(";", new)
    new = regex3.sub(":", new)
    return new

Response: converts bpp newick format to normal newick


Instruction:
Write a Python 3 function for
using to produce balanced trees returns a tip node from the smaller clade

Response:
def return_small_clade(treenode):
    "used to produce balanced trees, returns a tip node from the smaller clade"
    node = treenode
    while 1:
        if node.children:
            c1, c2 = node.children
            node = sorted([c1, c2], key=lambda x: len(x.get_leaves()))[0]
        else:
            return node


Instruction:
How would you explain what the following Python 3 function does
def fuzzy_match_tipnames(ttree, names, wildcard, regex, mrca=True, mono=True):
    # require arguments
    if not any([names, wildcard, regex]):
        raise ToytreeError(
            "must enter an outgroup, wildcard selector, or regex pattern")

    # get list of **nodes** from {list, wildcard, or regex}
    tips = []
    if names:
        if isinstance(names, (str, int)):
            names = [names]
        notfound = [i for i in names if i not in ttree.get_tip_labels()]
        if any(notfound):
            raise ToytreeError(
                "Sample {} is not in the tree".format(notfound))
        tips = [i for i in ttree.treenode.get_leaves() if i.name in names]

    # use regex to match tipnames
    elif regex:
        tips = [
            i for i in ttree.treenode.get_leaves() if re.match(regex, i.name)
        ]
        if not any(tips):
            raise ToytreeError("No Samples matched the regular expression")

    # use wildcard substring matching
    elif wildcard:
        tips = [i for i in ttree.treenode.get_leaves() if wildcard in i.name]
        if not any(tips):
            raise ToytreeError("No Samples matched the wildcard")

    # build list of **tipnames** from matched nodes
    if not tips:
        raise ToytreeError("no matching tipnames")
    tipnames = [i.name for i in tips]

    # if a single tipname matched no need to check for monophyly
    if len(tips) == 1:
        if mrca:
            return tips[0]
        else:
            return tipnames

    # if multiple nodes matched, check if they're monophyletic
    mbool, mtype, mnames = (
        ttree.treenode.check_monophyly(
            tipnames, "name", ignore_missing=True)
    )

    # get mrca node
    node = ttree.treenode.get_common_ancestor(tips)

    # raise an error if required to be monophyletic but not
    if mono:
        if not mbool:
            raise ToytreeError(
                "Taxon list cannot be paraphyletic")

    # return tips or nodes
    if not mrca:
        return tipnames
    else:
        return node

Response: This function returns a list of internal mrca nodes that match the given list of tipnames.


Instruction:
Can you generate the documentation for the following Python 3 function
def node_scale_root_height(self, treeheight=1):
        # make tree height = 1 * treeheight
        ctree = self._ttree.copy()
        _height = ctree.treenode.height
        for node in ctree.treenode.traverse():
            node.dist = (node.dist / _height) * treeheight
        ctree._coords.update()
        return ctree

Response:
Returns a toytree with all nodes scaled so that the root
        height equals the value entered for treeheight.


Instruction:
Can you implement a function in Python 3 that
returns a toytree copy with node heights modified while retaining the same topology but not necessarily node branching order.

Response:
def node_slider(self, seed=None):
        """
        Returns a toytree copy with node heights modified while retaining
        the same topology but not necessarily node branching order.
        Node heights are moved up or down uniformly between their parent
        and highest child node heights in 'levelorder' from root to tips.
        The total tree height is retained at 1.0, only relative edge
        lengths change.
        """
        # I don't think user's should need to access prop
        prop = 0.999
        assert isinstance(prop, float), "prop must be a float"
        assert prop < 1, "prop must be a proportion >0 and < 1."
        random.seed(seed)

        ctree = self._ttree.copy()
        for node in ctree.treenode.traverse():

            ## slide internal nodes
            if node.up and node.children:

                ## get min and max slides
                minjit = max([i.dist for i in node.children]) * prop
                maxjit = (node.up.height * prop) - node.height
                newheight = random.uniform(-minjit, maxjit)

                ## slide children
                for child in node.children:
                    child.dist += newheight

                ## slide self to match
                node.dist -= newheight
        ctree._coords.update()
        return ctree


Instruction:
Here you have a function in Python 3, explain what it does
def node_multiplier(self, multiplier=0.5, seed=None):
        random.seed(seed)
        ctree = self._ttree.copy()
        low, high = sorted([multiplier, 1. / multiplier])
        mult = random.uniform(low, high)
        for node in ctree.treenode.traverse():
            node.dist = node.dist * mult
        ctree._coords.update()
        return ctree

Response: Returns a toytree with all nodes multiplied by a constant


Instruction:
Write a Python 3 script for
returning a tree with branch lengths transformed so that the tree is ultrametric.

Response:
def make_ultrametric(self, strategy=1):
        """
        Returns a tree with branch lengths transformed so that the tree is
        ultrametric. Strategies include (1) tip-align: extend tips to the length
        of the fartest tip from the root; (2) non-parametric rate-smoothing:
        minimize ancestor-descendant local rates on branches to align tips (
        not yet supported); and (3) penalized-likelihood: not yet supported.
        """
        ctree = self._ttree.copy()

        if strategy == 1:
            for node in ctree.treenode.traverse():
                if node.is_leaf():
                    node.dist = node.height + 1

        else:
            raise NotImplementedError(
                "Strategy {} not yet implemented. Seeking developers."
                .format(strategy))

        return ctree


Instruction:
How would you explain what the following Python 3 function does
def coaltree(ntips, ne=None, seed=None):

        # seed generator
        random.seed(seed)

        # convert units
        coalunits = False
        if not ne:
            coalunits = True
            ne = 10000

        # build tree: generate N tips as separate Nodes then attach together
        # at internal nodes drawn randomly from coalescent waiting times.
        tips = [
            toytree.tree().treenode.add_child(name=str(i))
            for i in range(ntips)
        ]
        while len(tips) > 1:
            rtree = toytree.tree()
            tip1 = tips.pop(random.choice(range(len(tips))))
            tip2 = tips.pop(random.choice(range(len(tips))))
            kingman = (4. * ne) / float(ntips * (ntips - 1))
            dist = random.expovariate(1. / kingman)
            rtree.treenode.add_child(tip1, dist=tip2.height + dist)
            rtree.treenode.add_child(tip2, dist=tip1.height + dist)
            tips.append(rtree.treenode)

        # build new tree from the newick string
        self = toytree.tree(tips[0].write())
        self.treenode.ladderize()

        # make tree edges in units of 2N (then N doesn't matter!)
        if coalunits:
            for node in self.treenode.traverse():
                node.dist /= (2. * ne)

        # ensure tips are at zero (they sometime vary just slightly)
        for node in self.treenode.traverse():
            if node.is_leaf():
                node.dist += node.height

        # set tipnames
        for tip in self.get_tip_labels():
            node = self.treenode.search_nodes(name=tip)[0]
            node.name = "r{}".format(node.name)

        # decompose fills in internal node names and idx
        self._coords.update()
        return self

Response: Returns a coalescent tree with ntips samples and waiting times drawn from the kingman coalescent.


Instruction:
How would you code a function in Python 3 to
return a random tree with N tips and a root height set to 1 or a user - entered treeheight value.

Response:
def unittree(ntips, treeheight=1.0, seed=None):
        """
        Returns a random tree topology w/ N tips and a root height set to
        1 or a user-entered treeheight value. Descendant nodes are evenly
        spaced between the root and time 0.

        Parameters
        -----------
        ntips (int):
            The number of tips in the randomly generated tree

        treeheight(float):
            Scale tree height (all edges) so that root is at this height.

        seed (int):
            Random number generator seed.
        """
        # seed generator
        random.seed(seed)

        # generate tree with N tips.
        tmptree = TreeNode()
        tmptree.populate(ntips)
        self = toytree.tree(newick=tmptree.write())

        # set tip names by labeling sequentially from 0
        self = (
            self
            .ladderize()
            .mod.make_ultrametric()
            .mod.node_scale_root_height(treeheight)
        )

        # set tipnames randomly (doesn't have to match idx)
        nidx = list(range(self.ntips))
        random.shuffle(nidx)
        for tidx, node in enumerate(self.treenode.get_leaves()):
            node.name = "r{}".format(nidx[tidx])

        # fill internal node names and idx
        self._coords.update()
        return self


Instruction:
Can you create a Python 3 function that
returns an imbalanced ( comb - like ) tree topology.

Response:
def imbtree(ntips, treeheight=1.0):
        """
        Return an imbalanced (comb-like) tree topology.
        """
        rtree = toytree.tree()
        rtree.treenode.add_child(name="0")
        rtree.treenode.add_child(name="1")

        for i in range(2, ntips):
            # empty node
            cherry = toytree.tree()
            # add new child
            cherry.treenode.add_child(name=str(i))
            # add old tree
            cherry.treenode.add_child(rtree.treenode)
            # update rtree
            rtree = cherry

        # get toytree from newick
        tre = toytree.tree(rtree.write(tree_format=9))
        tre = tre.mod.make_ultrametric()
        self = tre.mod.node_scale_root_height(treeheight)
        self._coords.update()
        return self


Instruction:
Can you create a Python 3 function that
returns a balanced tree topology.

Response:
def baltree(ntips, treeheight=1.0):
        """
        Returns a balanced tree topology.
        """
        # require even number of tips
        if ntips % 2:
            raise ToytreeError("balanced trees must have even number of tips.")

        # make first cherry
        rtree = toytree.tree()
        rtree.treenode.add_child(name="0")
        rtree.treenode.add_child(name="1")

        # add tips in a balanced way
        for i in range(2, ntips):

            # get node to split
            node = return_small_clade(rtree.treenode)

            # add two children
            node.add_child(name=node.name)
            node.add_child(name=str(i))

            # rename ancestral node
            node.name = None

        # rename tips so names are in order
        idx = 0
        for node in rtree.treenode.traverse("postorder"):
            if node.is_leaf():
                node.name = str(idx)
                idx += 1

        # get toytree from newick
        tre = toytree.tree(rtree.write(tree_format=9))
        tre = tre.mod.make_ultrametric()
        self = tre.mod.node_scale_root_height(treeheight)
        self._coords.update()
        return self