Instruction:
Given the following Python 3 function, write the documentation
def separation(self, r=10):

        """ Boids keep a small distance from other boids.

        Ensures that boids don't collide into each other,
        in a smoothly accelerated motion.

        """

        vx = vy = vz = 0
        for b in self.boids:
            if b != self:
                if abs(self.x-b.x) < r: vx += (self.x-b.x)
                if abs(self.y-b.y) < r: vy += (self.y-b.y)
                if abs(self.z-b.z) < r: vz += (self.z-b.z)

        return vx, vy, vz

Response: Calculates the separation of the two sets of components.


Instruction:
Can you tell what is the following Python 3 function doing
def alignment(self, d=5):

        """ Boids match velocity with other boids.
        """

        vx = vy = vz = 0
        for b in self.boids:
           if b != self:
               vx, vy, vz = vx+b.vx, vy+b.vy, vz+b.vz

        n = len(self.boids)-1
        vx, vy, vz = vx/n, vy/n, vz/n

        return (vx-self.vx)/d, (vy-self.vy)/d, (vz-self.vz)/d

Response: Calculates the alignment of the current object s components based on the velocity of the other boids.


Instruction:
Given the following Python 3 function, write the documentation
def limit(self, max=30):

        """ The speed limit for a boid.

        Boids can momentarily go very fast,
        something that is impossible for real animals.

        """

        if abs(self.vx) > max:
            self.vx = self.vx/abs(self.vx)*max
        if abs(self.vy) > max:
            self.vy = self.vy/abs(self.vy)*max
        if abs(self.vz) > max:
            self.vz = self.vz/abs(self.vz)*max

Response: Limit the number of antenna in the sequence to a certain amount.


Instruction:
Can you tell what is the following Python 3 function doing
def _angle(self):

        """ Returns the angle towards which the boid is steering.
        """

        from math import atan, pi, degrees
        a = degrees(atan(self.vy/self.vx)) + 360
        if self.vx < 0: a += 180

        return a

Response: Returns the angle in degrees of the boid is steering.


Instruction:
Explain what the following Python 3 code does
def goal(self, x, y, z, d=50.0):

        """ Tendency towards a particular place.
        """

        return (x-self.x)/d, (y-self.y)/d, (z-self.z)/d

Response: The goal of the current location.


Instruction:
Here you have a function in Python 3, explain what it does
def constrain(self):

        """ Cages the flock inside the x, y, w, h area.

        The actual cage is a bit larger,
        so boids don't seem to bounce of invisible walls
        (they are rather "encouraged" to stay in the area).

        If a boid touches the ground level,
        it may decide to perch there for a while.

        """

        dx = self.w * 0.1
        dy = self.h * 0.1

        for b in self:

            if b.x < self.x-dx: b.vx += _ctx.random(dx)
            if b.y < self.y-dy: b.vy += _ctx.random(dy)
            if b.x > self.x+self.w+dx: b.vx -= _ctx.random(dx)
            if b.y > self.y+self.h+dy: b.vy -= _ctx.random(dy)
            if b.z < 0: b.vz += 10
            if b.z > 100: b.vz -= 10

            if b.y > self._perch_y and _ctx.random() < self._perch:
                b.y = self._perch_y
                b.vy = -abs(b.vy) * 0.2
                b.is_perching = True
                try:
                    b._perch_t = self._perch_t()
                except:
                    b._perch_t = self._perch_t

Response: Constrain the area of the cages.


Instruction:
How would you implement a function in Python 3 that
updates the list of boids with the next motion frame.

Response:
def update(self,
               shuffled=True,
               cohesion=100,
               separation=10,
               alignment=5,
               goal=20,
               limit=30):

        """ Calculates the next motion frame for the flock.
        """

        # Shuffling the list of boids ensures fluid movement.
        # If you need the boids to retain their position in the list
        # each update, set the shuffled parameter to False.
        from random import shuffle
        if shuffled: shuffle(self)

        m1 = 1.0 # cohesion
        m2 = 1.0 # separation
        m3 = 1.0 # alignment
        m4 = 1.0 # goal

        # The flock scatters randomly with a Boids.scatter chance.
        # This means their cohesion (m1) is reversed,
        # and their joint alignment (m3) is dimished,
        # causing boids to oscillate in confusion.
        # Setting Boids.scatter(chance=0) ensures they never scatter.
        if not self.scattered and _ctx.random() < self._scatter:
            self.scattered = True
        if self.scattered:
            m1 = -m1
            m3 *= 0.25
            self._scatter_i += 1
        if self._scatter_i >= self._scatter_t:
            self.scattered = False
            self._scatter_i = 0

        # A flock can have a goal defined with Boids.goal(x,y,z),
        # a place of interest to flock around.
        if not self.has_goal:
            m4 = 0
        if self.flee:
            m4 = -m4

        for b in self:

            # A boid that is perching will continue to do so
            # until Boid._perch_t reaches zero.
            if b.is_perching:
                if b._perch_t > 0:
                    b._perch_t -= 1
                    continue
                else:
                    b.is_perching = False

            vx1, vy1, vz1 = b.cohesion(cohesion)
            vx2, vy2, vz2 = b.separation(separation)
            vx3, vy3, vz3 = b.alignment(alignment)
            vx4, vy4, vz4 = b.goal(self._gx, self._gy, self._gz, goal)

            b.vx += m1*vx1 + m2*vx2 + m3*vx3 + m4*vx4
            b.vy += m1*vy1 + m2*vy2 + m3*vy3 + m4*vy4
            b.vz += m1*vz1 + m2*vz2 + m3*vz3 + m4*vz4

            b.limit(limit)

            b.x += b.vx
            b.y += b.vy
            b.z += b.vz

        self.constrain()


Instruction:
Implement a Python 3 function for
yielding the match and end_idx for each match

Response:
def iterscan(self, string, idx=0, context=None):
        """
        Yield match, end_idx for each match
        """
        match = self.scanner.scanner(string, idx).match
        actions = self.actions
        lastend = idx
        end = len(string)
        while True:
            m = match()
            if m is None:
                break
            matchbegin, matchend = m.span()
            if lastend == matchend:
                break
            action = actions[m.lastindex]
            if action is not None:
                rval, next_pos = action(m, context)
                if next_pos is not None and next_pos != matchend:
                    # "fast forward" the scanner
                    matchend = next_pos
                    match = self.scanner.scanner(string, matchend).match
                yield rval, matchend
            lastend = matchend


Instruction:
Write a Python 3 function that can
return a copy of the layout for the given graph.

Response:
def copy(self, graph):

        """ Returns a copy of the layout for the given graph.
        """

        l = self.__class__(graph, self.n)
        l.i = 0
        return l


Instruction:
Explain what the following Python 3 code does
def create(iterations=1000, distance=1.0, layout=LAYOUT_SPRING, depth=True):

    """ Returns a new graph with predefined styling.
    """

    #global _ctx

    _ctx.colormode(_ctx.RGB)
    g = graph(iterations, distance, layout)

    # Styles for different types of nodes.
    s = style.style
    g.styles.append(s(style.LIGHT    , _ctx, fill   = _ctx.color(0.0, 0.0, 0.0, 0.20)))
    g.styles.append(s(style.DARK     , _ctx, fill   = _ctx.color(0.3, 0.5, 0.7, 0.75)))
    g.styles.append(s(style.BACK     , _ctx, fill   = _ctx.color(0.5, 0.8, 0.0, 0.50)))
    g.styles.append(s(style.IMPORTANT, _ctx, fill   = _ctx.color(0.3, 0.6, 0.8, 0.75)))
    g.styles.append(s(style.HIGHLIGHT, _ctx, stroke = _ctx.color(1.0, 0.0, 0.5), strokewidth=1.5))
    g.styles.append(s(style.MARKED   , _ctx))
    g.styles.append(s(style.ROOT     , _ctx, text   = _ctx.color(1.0, 0.0, 0.4, 1.00),
                                             stroke = _ctx.color(0.8, 0.8, 0.8, 0.60),
                                             strokewidth = 1.5,
                                             fontsize    = 16,
                                             textwidth   = 150))

    # Important nodes get a double stroke.
    def important_node(s, node, alpha=1.0):
        style.style(None, _ctx).node(s, node, alpha)
        r = node.r * 1.4
        _ctx.nofill()
        _ctx.oval(node.x-r, node.y-r, r*2, r*2)

    # Marked nodes have an inner dot.
    def marked_node(s, node, alpha=1.0):
        style.style(None, _ctx).node(s, node, alpha)
        r = node.r * 0.3
        _ctx.fill(s.stroke)
        _ctx.oval(node.x-r, node.y-r, r*2, r*2)

    g.styles.important.node = important_node
    g.styles.marked.node = marked_node

    g.styles.depth = depth

    # Styling guidelines. All nodes have the default style, except:
    # 1) a node directly connected to the root gets the LIGHT style.
    # 2) a node with more than 4 edges gets the DARK style.
    # 3) a node with a weight of 0.75-1.0 gets the IMPORTANT style.
    # 4) the graph.root node gets the ROOT style.
    # 5) the node last clicked gets the BACK style.
    g.styles.guide.append(style.LIGHT     , lambda graph, node: graph.root in node.links)
    g.styles.guide.append(style.DARK      , lambda graph, node: len(node.links) > 4)
    g.styles.guide.append(style.IMPORTANT , lambda graph, node: node.weight > 0.75)
    g.styles.guide.append(style.ROOT      , lambda graph, node: node == graph.root)
    g.styles.guide.append(style.BACK      , lambda graph, node: node == graph.events.clicked)

    # An additional rule applies every node's weight to its radius.
    def balance(graph, node):
        node.r = node.r*0.75 + node.r*node.weight*0.75
    g.styles.guide.append("balance", balance)

    # An additional rule that keeps leaf nodes closely clustered.
    def cluster(graph, node):
        if len(node.links) == 1:
            node.links.edge(node.links[0]).length *= 0.5
    g.styles.guide.append("cluster", cluster)

    g.styles.guide.order = [
        style.LIGHT, style.DARK, style.IMPORTANT, style.ROOT, style.BACK, "balance", "nurse"
    ]

    return g

Response: Creates a new graph with the given number of iterations and distance.


Instruction:
Can you implement a function in Python 3 that
returns True if given node can be reached over traversable edges.

Response:
def can_reach(self, node, traversable=lambda node, edge: True):

        """ Returns True if given node can be reached over traversable edges.
        To enforce edge direction, use a node==edge.node1 traversable.
        """

        if isinstance(node, str):
            node = self.graph[node]
        for n in self.graph.nodes:
            n._visited = False
        return proximity.depth_first_search(self,
            visit=lambda n: node == n,
            traversable=traversable
            )


Instruction:
Can you create a Python 3 function that
creates a copy of the graph.

Response:
def copy(self, empty=False):

        """ Create a copy of the graph (by default with nodes and edges).
        """

        g = graph(self.layout.n, self.distance, self.layout.type)
        g.layout = self.layout.copy(g)
        g.styles = self.styles.copy(g)
        g.events = self.events.copy(g)

        if not empty:
            for n in self.nodes:
                g.add_node(n.id, n.r, n.style, n.category, n.label, (n == self.root), n.__dict__)
            for e in self.edges:
                g.add_edge(e.node1.id, e.node2.id, e.weight, e.length, e.label, e.__dict__)

        return g


Instruction:
How would you code a function in Python 3 to
remove nodes and edges and reset the layout.

Response:
def clear(self):

        """ Remove nodes and edges and reset the layout.
        """

        dict.clear(self)
        self.nodes = []
        self.edges = []
        self.root  = None

        self.layout.i = 0
        self.alpha = 0


Instruction:
Write a Python 3 function that can
add a node from id and return the node object.

Response:
def add_node(self, id, radius=8, style=style.DEFAULT, category="", label=None, root=False,
                 properties={}):

        """ Add node from id and return the node object.
        """

        if self.has_key(id):
            return self[id]

        if not isinstance(style, str) and style.__dict__.has_key["name"]:
            style = style.name

        n = node(self, id, radius, style, category, label, properties)
        self[n.id] = n
        self.nodes.append(n)
        if root: self.root = n

        return n


Instruction:
Here you have a function in Python 3, explain what it does
def add_edge(self, id1, id2, weight=0.0, length=1.0, label="", properties={}):

        """ Add weighted (0.0-1.0) edge between nodes, creating them if necessary.
        The weight represents the importance of the connection (not the cost).
        """

        if id1 == id2: return None

        if not self.has_key(id1): self.add_node(id1)
        if not self.has_key(id2): self.add_node(id2)
        n1 = self[id1]
        n2 = self[id2]

        # If a->b already exists, don't re-create it.
        # However, b->a may still pass.
        if n1 in n2.links:
            if n2.links.edge(n1).node1 == n1:
                return self.edge(id1, id2)

        weight = max(0.0, min(weight, 1.0))

        e = edge(n1, n2, weight, length, label, properties)
        self.edges.append(e)
        n1.links.append(n2, e)
        n2.links.append(n1, e)

        return e

Response: Add an edge between two nodes.


Instruction:
Explain what the following Python 3 code does
def remove_node(self, id):

        """ Remove node with given id.
        """

        if self.has_key(id):
            n = self[id]
            self.nodes.remove(n)
            del self[id]

            # Remove all edges involving id and all links to it.
            for e in list(self.edges):
                if n in (e.node1, e.node2):
                    if n in e.node1.links:
                        e.node1.links.remove(n)
                    if n in e.node2.links:
                        e.node2.links.remove(n)
                    self.edges.remove(e)

Response: Removes a node from the list of nodes and edges.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def remove_edge(self, id1, id2):

        """ Remove edges between nodes with given id's.
        """

        for e in list(self.edges):
            if id1 in (e.node1.id, e.node2.id) and \
               id2 in (e.node1.id, e.node2.id):
                e.node1.links.remove(e.node2)
                e.node2.links.remove(e.node1)
                self.edges.remove(e)

Response: Removes edges between nodes with given id s.


Instruction:
Implement a function in Python 3 to
return the edge between the nodes with given id1 and id2.

Response:
def edge(self, id1, id2):
        """ Returns the edge between the nodes with given id1 and id2.
        """
        if id1 in self and \
           id2 in self and \
           self[id2] in self[id1].links:
            return self[id1].links.edge(id2)
        return None


Instruction:
Explain what the following Python 3 code does
def update(self, iterations=10):

        """ Iterates the graph layout and updates node positions.
        """

        # The graph fades in when initially constructed.
        self.alpha += 0.05
        self.alpha = min(self.alpha, 1.0)

        # Iterates over the graph's layout.
        # Each step the graph's bounds are recalculated
        # and a number of iterations are processed,
        # more and more as the layout progresses.
        if self.layout.i == 0:
            self.layout.prepare()
            self.layout.i += 1
        elif self.layout.i == 1:
            self.layout.iterate()
        elif self.layout.i < self.layout.n:
            n = min(iterations, self.layout.i / 10 + 1)
            for i in range(n):
                self.layout.iterate()

        # Calculate the absolute center of the graph.
        min_, max = self.layout.bounds
        self.x = _ctx.WIDTH - max.x*self.d - min_.x*self.d
        self.y = _ctx.HEIGHT - max.y*self.d - min_.y*self.d
        self.x /= 2
        self.y /= 2

        return not self.layout.done

Response: Updates the node positions and positions of the node in the current layout.


Instruction:
Can you tell what is the following Python 3 function doing
def offset(self, node):
        x = self.x + node.x - _ctx.WIDTH/2
        y = self.y + node.y - _ctx.HEIGHT/2
        return x, y

Response: Returns the distance from the center to the given node.


Instruction:
Can you tell what is the following Python 3 function doing
def draw(self, dx=0, dy=0, weighted=False, directed=False, highlight=[], traffic=None):

        """ Layout the graph incrementally.

        The graph is drawn at the center of the canvas.
        The weighted and directed parameters visualize edge weight and direction.
        The highlight specifies list of connected nodes.
        The path will be colored according to the "highlight" style.
        Clicking and dragging events are monitored.

        """

        self.update()

        # Draw the graph background.
        s = self.styles.default
        s.graph_background(s)

        # Center the graph on the canvas.
        _ctx.push()
        _ctx.translate(self.x+dx, self.y+dy)

        # Indicate betweenness centrality.
        if traffic:
            if isinstance(traffic, bool):
                traffic = 5
            for n in self.nodes_by_betweenness()[:traffic]:
                try: s = self.styles[n.style]
                except: s = self.styles.default
                if s.graph_traffic:
                    s.graph_traffic(s, n, self.alpha)

        # Draw the edges and their labels.
        s = self.styles.default
        if s.edges:
            s.edges(s, self.edges, self.alpha, weighted, directed)

        # Draw each node in the graph.
        # Apply individual style to each node (or default).
        for n in self.nodes:
            try:  s = self.styles[n.style]
            except: s = self.styles.default
            if s.node:
                s.node(s, n, self.alpha)

        # Highlight the given shortest path.
        try: s = self.styles.highlight
        except: s = self.styles.default
        if s.path:
            s.path(s, self, highlight)

        # Draw node id's as labels on each node.
        for n in self.nodes:
            try:  s = self.styles[n.style]
            except: s = self.styles.default
            if s.node_label:
                s.node_label(s, n, self.alpha)

        # Events for clicked and dragged nodes.
        # Nodes will resist being dragged by attraction and repulsion,
        # put the event listener on top to get more direct feedback.
        #self.events.update()

        _ctx.pop()

Response:
Layout the graph incrementally.

        The graph is drawn at the center of the canvas.
        The weighted and directed parameters visualize edge weight and direction.
        The highlight specifies list of connected nodes.
        The path will be colored according to the "highlight" style.
        Clicking and dragging events are monitored.


Instruction:
Write a Python 3 script to
remove all nodes with less or equal links than depth.

Response:
def prune(self, depth=0):
        """ Removes all nodes with less or equal links than depth.
        """
        for n in list(self.nodes):
            if len(n.links) <= depth:
                self.remove_node(n.id)


Instruction:
Make a summary of the following Python 3 code
def betweenness_centrality(self, normalized=True):
        bc = proximity.brandes_betweenness_centrality(self, normalized)
        for id, w in bc.iteritems(): self[id]._betweenness = w
        return bc

Response: Calculates the betweenness centrality and returns an object id - > weight dictionary.


Instruction:
Can you tell what is the following Python 3 function doing
def eigenvector_centrality(self, normalized=True, reversed=True, rating={},
                               start=None, iterations=100, tolerance=0.0001):
        """ Calculates eigenvector centrality and returns an node id -> weight dictionary.
        Node eigenvalue weights are updated in the process.
        """
        ec = proximity.eigenvector_centrality(
            self, normalized, reversed, rating, start, iterations, tolerance
        )
        for id, w in ec.iteritems(): self[id]._eigenvalue = w
        return ec

Response: Calculates the eigenvector centrality and returns an object with the node id - > weight dictionary.


Instruction:
Create a Python 3 function to
return a list of nodes sorted by betweenness centrality.

Response:
def nodes_by_betweenness(self, treshold=0.0):
        """ Returns nodes sorted by betweenness centrality.
        Nodes with a lot of passing traffic will be at the front of the list.
        """
        nodes = [(n.betweenness, n) for n in self.nodes if n.betweenness > treshold]
        nodes.sort(); nodes.reverse()
        return [n for w, n in nodes]


Instruction:
How would you explain what the following Python 3 function does
def nodes_by_eigenvalue(self, treshold=0.0):
        nodes = [(n.eigenvalue, n) for n in self.nodes if n.eigenvalue > treshold]
        nodes.sort(); nodes.reverse()
        return [n for w, n in nodes]

Response: Returns a list of nodes sorted by eigenvector centrality.


Instruction:
Here you have a function in Python 3, explain what it does
def nodes_by_category(self, category):
        return [n for n in self.nodes if n.category == category]

Response: Returns a list of nodes with the given category attribute.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def crown(self, depth=2):
        nodes = []
        for node in self.leaves: nodes += node.flatten(depth-1)
        return cluster.unique(nodes)

Response: Returns a list of nodes connected to leaves and etc.


Instruction:
Given the following Python 3 function, write the documentation
def _density(self):
        return 2.0*len(self.edges) / (len(self.nodes) * (len(self.nodes)-1))

Response: The density of the nodes and edges.


Instruction:
Make a summary of the following Python 3 code
def load(self, id):

        """ Rebuilds the graph around the given node id.
        """

        self.clear()

        # Root node.
        self.add_node(id, root=True)

        # Directly connected nodes have priority.
        for w, id2 in self.get_links(id):
            self.add_edge(id, id2, weight=w)
            if len(self) > self.max:
                break

        # Now get all the other nodes in the cluster.
        for w, id2, links in self.get_cluster(id):
            for id3 in links:
                self.add_edge(id3, id2, weight=w)
                self.add_edge(id, id3, weight=w)
            #if len(links) == 0:
            #    self.add_edge(id, id2)
            if len(self) > self.max:
                break

        # Provide a backlink to the previous root.
        if self.event.clicked:
            g.add_node(self.event.clicked)

Response: Loads the node with the given id.


Instruction:
Create a Python 3 function for
computing a cubic Bezier approximation of an elliptical arc.

Response:
def bezier_arc(x1, y1, x2, y2, start_angle=0, extent=90):

    """ Compute a cubic Bezier approximation of an elliptical arc.

    (x1, y1) and (x2, y2) are the corners of the enclosing rectangle.
    The coordinate system has coordinates that increase to the right and down.
    Angles, measured in degress, start with 0 to the right (the positive X axis)
    and increase counter-clockwise.
    The arc extends from start_angle to start_angle+extent.
    I.e. start_angle=0 and extent=180 yields an openside-down semi-circle.

    The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4)
    such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and
    (x3, y3) as their respective Bezier control points.
    """

    x1,y1, x2,y2 = min(x1,x2), max(y1,y2), max(x1,x2), min(y1,y2)

    if abs(extent) <= 90:
        frag_angle = float(extent)
        nfrag = 1
    else:
        nfrag = int(ceil(abs(extent)/90.))
        if nfrag == 0:
            warnings.warn('Invalid value for extent: %r' % extent)
            return []
        frag_angle = float(extent) / nfrag

    x_cen = (x1+x2)/2.
    y_cen = (y1+y2)/2.
    rx = (x2-x1)/2.
    ry = (y2-y1)/2.
    half_angle = radians(frag_angle) / 2
    kappa = abs(4. / 3. * (1. - cos(half_angle)) / sin(half_angle))

    if frag_angle < 0:
        sign = -1
    else:
        sign = 1

    point_list = []

    for i in range(nfrag):
        theta0 = radians(start_angle + i*frag_angle)
        theta1 = radians(start_angle + (i+1)*frag_angle)
        c0 = cos(theta0)
        c1 = cos(theta1)
        s0 = sin(theta0)
        s1 = sin(theta1)
        if frag_angle > 0:
            signed_kappa = -kappa
        else:
            signed_kappa = kappa
        point_list.append((x_cen + rx * c0,
                          y_cen - ry * s0,
                          x_cen + rx * (c0 + signed_kappa * s0),
                          y_cen - ry * (s0 - signed_kappa * c0),
                          x_cen + rx * (c1 - signed_kappa * s1),
                          y_cen - ry * (s1 + signed_kappa * c1),
                          x_cen + rx * c1,
                          y_cen - ry * s1))

    return point_list


Instruction:
Write a Python 3 script to
return the angle in degrees between two vectors.

Response:
def angle(x1, y1, x2, y2):
    """ The angle in degrees between two vectors.
    """
    sign = 1.0
    usign = (x1*y2 - y1*x2)
    if usign < 0:
        sign = -1.0
    num = x1*x2 + y1*y2
    den = hypot(x1,y1) * hypot(x2,y2)
    ratio = min(max(num/den, -1.0), 1.0)
    return sign * degrees(acos(ratio))


Instruction:
Make a summary of the following Python 3 code
def transform_from_local(xp, yp, cphi, sphi, mx, my):
    x = xp * cphi - yp * sphi + mx
    y = xp * sphi + yp * cphi + my
    return (x,y)

Response: Transform from the local frame to absolute space.


Instruction:
Make a summary of the following Python 3 code
def _create_view(self, name="shoebot-output"):
        view = Gtk.TextView()
        view.set_editable(False)

        fontdesc = Pango.FontDescription("Monospace")
        view.modify_font(fontdesc)
        view.set_name(name)

        buff = view.get_buffer()
        buff.create_tag('error', foreground='red')
        return view

Response: Create the gtk. TextView used for shell output


Instruction:
Implement a Python 3 function for
setting the bot for this topic.

Response:
def set_bot(self, bot):
        ''' Bot must be set before running '''
        self.bot = bot
        self.sink.set_bot(bot)


Instruction:
Explain what the following Python 3 code does
def settings(self, **kwargs):
        '''
        Pass a load of settings into the canvas
        '''
        for k, v in kwargs.items():
            setattr(self, k, v)

Response: Pass a load of settings into the canvas


Instruction:
Explain what the following Python 3 code does
def size_or_default(self):
        '''
        If size is not set, otherwise set size to DEFAULT_SIZE
        and return it.

        This means, only the first call to size() is valid.
        '''
        if not self.size:
            self.size = self.DEFAULT_SIZE
        return self.size

Response: Return the size of the current object.


Instruction:
Write a Python 3 script to
set the size of the object.

Response:
def set_size(self, size):
        '''
        Size is only set the first time it is called

        Size that is set is returned
        '''
        if self.size is None:
            self.size = size
            return size
        else:
            return self.size


Instruction:
Make a summary of the following Python 3 code
def snapshot(self, target, defer=True, file_number=None):
        '''
        Ask the drawqueue to output to target.

        target can be anything supported by the combination
        of canvas implementation and drawqueue implmentation.

        If target is not supported then an exception is thrown.
        '''
        output_func = self.output_closure(target, file_number)
        if defer:
            self._drawqueue.append(output_func)
        else:
            self._drawqueue.append_immediate(output_func)

Response: Ask the drawqueue to output to target.


Instruction:
Can you create a Python 3 function that
flushes the drawqueue to the sink.

Response:
def flush(self, frame):
        '''
        Passes the drawqueue to the sink for rendering
        '''
        self.sink.render(self.size_or_default(), frame, self._drawqueue)
        self.reset_drawqueue()


Instruction:
Can you generate the documentation for the following Python 3 function
def overlap(self, x1, y1, x2, y2, r=5):

        """ Returns True when point 1 and point 2 overlap.

        There is an r treshold in which point 1 and point 2
        are considered to overlap.

        """

        if abs(x2-x1) < r and abs(y2-y1) < r:
            return True
        else:
            return False

Response: Returns True when point 1 and point 2 overlap.


Instruction:
How would you implement a function in Python 3 that
reflects the point x y through origin x0 y0.

Response:
def reflect(self, x0, y0, x, y):

        """ Reflects the point x, y through origin x0, y0.
        """

        rx = x0 - (x-x0)
        ry = y0 - (y-y0)
        return rx, ry


Instruction:
How would you code a function in Python 3 to
calculate the angle between two points.

Response:
def angle(self, x0, y0, x1, y1):

        """ Calculates the angle between two points.
        """

        a = degrees( atan((y1-y0) / (x1-x0+0.00001)) ) + 360
        if x1-x0 < 0: a += 180
        return a


Instruction:
Can you implement a function in Python 3 that
calculates the coordinates of a point from the origin.

Response:
def coordinates(self, x0, y0, distance, angle):

        """ Calculates the coordinates of a point from the origin.
        """

        x = x0 + cos(radians(angle)) * distance
        y = y0 + sin(radians(angle)) * distance
        return Point(x, y)


Instruction:
Can you generate the documentation for the following Python 3 function
def contains_point(self, x, y, d=2):

        """ Returns true when x, y is on the path stroke outline.
        """

        if self.path != None and len(self.path) > 1 \
        and self.path.contains(x, y):
            # If all points around the mouse are also part of the path,
            # this means we are somewhere INSIDE the path.
            # Only points near the edge (i.e. on the outline stroke)
            # should propagate.
            if not self.path.contains(x+d, y) \
            or not self.path.contains(x, y+d) \
            or not self.path.contains(x-d, y) \
            or not self.path.contains(x, y-d) \
            or not self.path.contains(x+d, y+d) \
            or not self.path.contains(x-d, y-d) \
            or not self.path.contains(x+d, y-d) \
            or not self.path.contains(x-d, y+d):
                return True

        return False

Response: Returns True when x y is on the path stroke outline.


Instruction:
Can you create a Python 3 function that
inserts a point on the path at the mouse location.

Response:
def insert_point(self, x, y):

        """ Inserts a point on the path at the mouse location.

        We first need to check if the mouse location is on the path.
        Inserting point is time intensive and experimental.

        """

        try:
            bezier = _ctx.ximport("bezier")
        except:
            from nodebox.graphics import bezier

        # Do a number of checks distributed along the path.
        # Keep the one closest to the actual mouse location.
        # Ten checks works fast but leads to imprecision in sharp corners
        # and curves closely located next to each other.
        # I prefer the slower but more stable approach.
        n = 100
        closest = None
        dx0 = float("inf")
        dy0 = float("inf")
        for i in range(n):
            t = float(i)/n
            pt = self.path.point(t)
            dx = abs(pt.x-x)
            dy = abs(pt.y-y)
            if dx+dy <= dx0+dy0:
                dx0 = dx
                dy0 = dy
                closest = t

        # Next, scan the area around the approximation.
        # If the closest point is located at 0.2 on the path,
        # we need to scan between 0.1 and 0.3 for a better
        # approximation. If 1.5 was the best guess, scan
        # 1.40, 1.41 ... 1.59 and so on.
        # Each decimal precision takes 20 iterations.
        decimals = [3,4]
        for d in decimals:
            d = 1.0/pow(10,d)

            for i in range(20):
                t = closest-d + float(i)*d*0.1
                if t < 0.0: t = 1.0+t
                if t > 1.0: t = t-1.0
                pt = self.path.point(t)
                dx = abs(pt.x-x)
                dy = abs(pt.y-y)
                if dx <= dx0 and dy <= dy0:
                    dx0 = dx
                    dy0 = dy
                    closest_precise = t

            closest = closest_precise

        # Update the points list with the inserted point.
        p = bezier.insert_point(self.path, closest_precise)
        i, t, pt = bezier._locate(self.path, closest_precise)
        i += 1
        pt = PathElement()
        pt.cmd = p[i].cmd
        pt.x = p[i].x
        pt.y = p[i].y
        pt.ctrl1 = Point(p[i].ctrl1.x, p[i].ctrl1.y)
        pt.ctrl2 = Point(p[i].ctrl2.x, p[i].ctrl2.y)
        pt.freehand = False
        self._points.insert(i, pt)
        self._points[i-1].ctrl1 = Point(p[i-1].ctrl1.x, p[i-1].ctrl1.y)
        self._points[i+1].ctrl1 = Point(p[i+1].ctrl1.x, p[i+1].ctrl1.y)
        self._points[i+1].ctrl2 = Point(p[i+1].ctrl2.x, p[i+1].ctrl2.y)


Instruction:
How would you explain what the following Python 3 function does
def update(self):

        """ Update runs each frame to check for mouse interaction.

        Alters the path by allowing the user to add new points,
        drag point handles and move their location.
        Updates are automatically stored as SVG
        in the given filename.

        """

        x, y = mouse()
        if self.show_grid:
            x, y = self.grid.snap(x, y)

        if _ctx._ns["mousedown"] \
        and not self.freehand:

            self._dirty = True

            # Handle buttons first.
            # When pressing down on a button, all other action halts.
            # Buttons appear near a point being edited.
            # Once clicked, actions are resolved.
            if self.edit != None \
            and not self.drag_point \
            and not self.drag_handle1 \
            and not self.drag_handle2:
                pt = self._points[self.edit]
                dx = pt.x+self.btn_x
                dy = pt.y+self.btn_y
                # The delete button
                if self.overlap(dx, dy, x, y, r=self.btn_r):
                    self.delete = self.edit
                    return
                # The moveto button,
                # active on the last point in the path.
                dx += self.btn_r*2 + 2
                if self.edit == len(self._points) -1 and \
                   self.overlap(dx, dy, x, y, r=self.btn_r):
                    self.moveto = self.edit
                    return

            if self.insert:
                self.inserting = True
                return

            # When not dragging a point or the handle of a point,
            # i.e. the mousebutton was released and then pressed again,
            # check to see if a point on the path is pressed.
            # When this point is not the last new point,
            # enter edit mode.
            if not self.drag_point and \
               not self.drag_handle1 and \
               not self.drag_handle2:
                self.editing = False
                indices = range(len(self._points))
                indices.reverse()
                for i in indices:
                    pt = self._points[i]
                    if pt != self.new \
                    and self.overlap(x, y, pt.x, pt.y) \
                    and self.new == None:
                        # Don't select a point if in fact
                        # it is at the same location of the first handle
                        # of the point we are currently editing.
                        if self.edit == i+1 \
                        and self.overlap(self._points[i+1].ctrl1.x,
                                         self._points[i+1].ctrl1.y, x, y):
                            continue
                        else:
                            self.edit = i
                            self.editing = True
                            break

            # When the mouse button is down,
            # edit mode continues as long as
            # a point or handle is dragged.
            # Else, stop editing and switch to add-mode
            # (the user is clicking somewhere on the canvas).
            if not self.editing:
                if self.edit != None:
                    pt = self._points[self.edit]
                    if self.overlap(pt.ctrl1.x, pt.ctrl1.y, x, y) or \
                       self.overlap(pt.ctrl2.x, pt.ctrl2.y, x, y):
                        self.editing = True
                    else:
                        self.edit = None

            # When not in edit mode, there are two options.
            # Either no new point is defined and the user is
            # clicking somewhere on the canvas (add a new point)
            # or the user is dragging the handle of the new point.
            # Adding a new point is a fluid click-to-locate and
            # drag-to-curve action.
            if self.edit == None:
                if self.new == None:
                    # A special case is when the used clicked
                    # the moveto button on the last point in the path.
                    # This indicates a gap (i.e. MOVETO) in the path.
                    self.new = PathElement()
                    if self.moveto == True \
                    or len(self._points) == 0:
                        cmd = MOVETO
                        self.moveto = None
                        self.last_moveto = self.new
                    else:
                        cmd = CURVETO
                    self.new.cmd = cmd
                    self.new.x = x
                    self.new.y = y
                    self.new.ctrl1 = Point(x, y)
                    self.new.ctrl2 = Point(x, y)
                    self.new.freehand = False
                    # Don't forget to map the point's ctrl1 handle
                    # to the ctrl2 handle of the previous point.
                    # This makes for smooth, continuous paths.
                    if len(self._points) > 0:
                        prev = self._points[-1]
                        rx, ry = self.reflect(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)
                        self.new.ctrl1 = Point(rx, ry)
                    self._points.append(self.new)
                else:
                    # Illustrator-like behavior:
                    # when the handle is dragged downwards,
                    # the path bulges upwards.
                    rx, ry = self.reflect(self.new.x, self.new.y, x, y)
                    self.new.ctrl2 = Point(rx, ry)

            # Edit mode
            elif self.new == None:

                pt = self._points[self.edit]

                # The user is pressing the mouse on a point,
                # enter drag-point mode.
                if self.overlap(pt.x, pt.y, x, y) \
                and not self.drag_handle1 \
                and not self.drag_handle2 \
                and not self.new != None:
                    self.drag_point = True
                    self.drag_handle1 = False
                    self.drag_handle2 = False

                # The user is pressing the mouse on a point's handle,
                # enter drag-handle mode.
                if self.overlap(pt.ctrl1.x, pt.ctrl1.y, x, y) \
                and pt.cmd == CURVETO \
                and not self.drag_point \
                and not self.drag_handle2:
                    self.drag_point = False
                    self.drag_handle1 = True
                    self.drag_handle2 = False
                if self.overlap(pt.ctrl2.x, pt.ctrl2.y, x, y) \
                and pt.cmd == CURVETO \
                and not self.drag_point \
                and not self.drag_handle1:
                    self.drag_point = False
                    self.drag_handle1 = False
                    self.drag_handle2 = True

                # In drag-point mode,
                # the point is located at the mouse coordinates.
                # The handles move relatively to the new location
                # (e.g. they are retained, the path does not distort).
                # Modify the ctrl1 handle of the next point as well.
                if self.drag_point == True:
                    dx = x - pt.x
                    dy = y - pt.y
                    pt.x = x
                    pt.y = y
                    pt.ctrl2.x += dx
                    pt.ctrl2.y += dy
                    if self.edit < len(self._points)-1:
                        rx, ry = self.reflect(pt.x, pt.y, x, y)
                        next = self._points[self.edit+1]
                        next.ctrl1.x += dx
                        next.ctrl1.y += dy

                # In drag-handle mode,
                # set the path's handle to the mouse location.
                # Rotate the handle of the next or previous point
                # to keep paths smooth - unless the user is pressing "x".
                if self.drag_handle1 == True:
                    pt.ctrl1 = Point(x, y)
                    if self.edit > 0 \
                    and self.last_key != "x":
                        prev = self._points[self.edit-1]
                        d = self.distance(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)
                        a = self.angle(prev.x, prev.y, pt.ctrl1.x, pt.ctrl1.y)
                        prev.ctrl2 = self.coordinates(prev.x, prev.y, d, a+180)
                if self.drag_handle2 == True:
                    pt.ctrl2 = Point(x, y)
                    if self.edit < len(self._points)-1 \
                    and self.last_key != "x":
                        next = self._points[self.edit+1]
                        d = self.distance(pt.x, pt.y, next.ctrl1.x, next.ctrl1.y)
                        a = self.angle(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)
                        next.ctrl1 = self.coordinates(pt.x, pt.y, d, a+180)

        elif not self.freehand:

            # The mouse button is released
            # so we are not dragging anything around.
            self.new = None
            self.drag_point = False
            self.drag_handle1 = False
            self.drag_handle2 = False

            # The delete button for a point was clicked.
            if self.delete != None and len(self._points) > 0:
                i = self.delete
                cmd = self._points[i].cmd
                del self._points[i]
                if 0 < i < len(self._points):
                    prev = self._points[i-1]
                    rx, ry = self.reflect(prev.x, prev.y, prev.ctrl2.x, prev.ctrl2.y)
                    self._points[i].ctrl1 = Point(rx, ry)
                # Also delete all the freehand points
                # prior to this point.
                start_i = i
                while i > 1:
                    i -= 1
                    pt = self._points[i]
                    if pt.freehand:
                        del self._points[i]
                    elif i < start_i-1 and pt.freehand == False:
                        if pt.cmd == MOVETO:
                            del self._points[i]
                        break
                # When you delete a MOVETO point,
                # the last moveto (the one where the dashed line points to)
                # needs to be updated.
                if len(self._points) > 0 \
                and (cmd == MOVETO or i == 0):
                    self.last_moveto = self._points[0]
                    for pt in self._points:
                        if pt.cmd == MOVETO:
                            self.last_moveto = pt
                self.delete = None
                self.edit = None

            # The moveto button for the last point
            # in the path was clicked.
            elif isinstance(self.moveto, int):
                self.moveto = True
                self.edit = None

            # We are not editing a node and
            # the mouse is hovering over the path outline stroke:
            # it is possible to insert a point here.
            elif self.edit == None \
            and self.contains_point(x, y, d=2):
                self.insert = True
            else:
                self.insert = False

            # Commit insert of new point.
            if self.inserting \
            and self.contains_point(x, y, d=2):
                self.insert_point(x, y)
                self.insert = False
            self.inserting = False

            # No modifications are being made right now
            # and the SVG file needs to be updated.
            if self._dirty == True:
                self.export_svg()
                self._dirty = False

        # Keyboard interaction.
        if _ctx._ns["keydown"]:
            self.last_key = _ctx._ns["key"]
            self.last_keycode = _ctx._ns["keycode"]
        if not _ctx._ns["keydown"] and self.last_key != None:
            # If the TAB-key is pressed,
            # switch the magnetic grid either on or off.
            if self.last_keycode == KEY_TAB:
                self.show_grid = not self.show_grid
            # When "f" is pressed, switch freehand mode.
            if self.last_key == "f":
                self.edit = None
                self.freehand = not self.freehand
                if self.freehand:
                    self.msg = "freehand"
                else:
                    self.msg = "curves"
            # When ESC is pressed exit edit mode.
            if self.last_keycode == KEY_ESC:
                self.edit = None
            # When BACKSPACE is pressed, delete current point.
            if self.last_keycode == _ctx.KEY_BACKSPACE \
            and self.edit != None:
                self.delete = self.edit
            self.last_key = None
            self.last_code = None

        # Using the keypad you can scroll the screen.
        if _ctx._ns["keydown"]:
            dx = 0
            dy = 0
            keycode = _ctx._ns["keycode"]
            if keycode == _ctx.KEY_LEFT:
                dx = -10
            elif keycode == _ctx.KEY_RIGHT:
                dx = 10
            if keycode == _ctx.KEY_UP:
                dy = -10
            elif keycode == _ctx.KEY_DOWN:
                dy = 10
            if dx != 0 or dy != 0:
                for pt in self._points:
                    pt.x += dx
                    pt.y += dy
                    pt.ctrl1.x += dx
                    pt.ctrl1.y += dy
                    pt.ctrl2.x += dx
                    pt.ctrl2.y += dy

Response: Updates the path based on the mouse interaction.


Instruction:
Explain what the following Python 3 code does
def draw(self):

        """ Draws the editable path and interface elements.
        """

        # Enable interaction.
        self.update()
        x, y = mouse()

        # Snap to grid when enabled.
        # The grid is enabled with the TAB key.
        if self.show_grid:
            self.grid.draw()
            x, y = self.grid.snap(x, y)

        _ctx.strokewidth(self.strokewidth)
        if self.freehand:
            self.draw_freehand()

        r = 4
        _ctx.nofill()
        if len(self._points) > 0:

            first = True
            for i in range(len(self._points)):

                # Construct the path.
                pt = self._points[i]
                if first:
                    _ctx.beginpath(pt.x, pt.y)
                    first = False
                else:
                    if pt.cmd == CLOSE:
                        _ctx.closepath()
                    elif pt.cmd == MOVETO:
                        _ctx.moveto(pt.x, pt.y)
                    elif pt.cmd == LINETO:
                        _ctx.lineto(pt.x, pt.y)
                    elif pt.cmd == CURVETO:
                        _ctx.curveto(pt.ctrl1.x, pt.ctrl1.y,
                                     pt.ctrl2.x, pt.ctrl2.y,
                                     pt.x, pt.y)
                # In add- or edit-mode,
                # display the current point's handles.
                if ((i == self.edit and self.new == None) \
                or pt == self.new) \
                and pt.cmd == CURVETO \
                and not pt.freehand:
                    _ctx.stroke(self.handle_color)
                    _ctx.nofill()
                    _ctx.oval(pt.x-r, pt.y-r, r*2, r*2)
                    _ctx.stroke(self.handle_color)
                    _ctx.line(pt.ctrl2.x, pt.ctrl2.y, pt.x, pt.y)
                    _ctx.fill(self.handle_color)
                # Display the new point's handle being dragged.
                if pt == self.new \
                and not pt.freehand:
                    rx, ry = self.reflect(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)
                    _ctx.stroke(self.handle_color)
                    _ctx.line(rx, ry, pt.x, pt.y)
                    _ctx.nostroke()
                    _ctx.fill(self.handle_color)
                    _ctx.oval(rx-r/2, ry-r/2, r, r)
                # Display handles for point being edited.
                if i == self.edit \
                and self.new == None \
                and pt.cmd == CURVETO \
                and not pt.freehand:
                    _ctx.oval(pt.ctrl2.x-r/2, pt.ctrl2.y-r/2, r, r)
                    if i > 0:
                        prev = self._points[i-1]
                        _ctx.line(pt.ctrl1.x, pt.ctrl1.y, prev.x, prev.y)
                        _ctx.oval(pt.ctrl1.x-r/2, pt.ctrl1.y-r/2, r, r)
                    if i > 0 and self._points[i-1].cmd != MOVETO:
                        _ctx.line(prev.ctrl2.x, prev.ctrl2.y, prev.x, prev.y)
                    if i < len(self._points)-1:
                        next = self._points[i+1]
                        if next.cmd == CURVETO:
                            _ctx.line(next.ctrl1.x, next.ctrl1.y, pt.x, pt.y)

                # When hovering over a point,
                # highlight it.
                elif self.overlap(x, y, pt.x, pt.y) \
                and not pt.freehand:
                    self.insert = False # quit insert mode
                    _ctx.nofill()
                    _ctx.stroke(self.handle_color)
                    _ctx.oval(pt.x-r, pt.y-r, r*2, r*2)

                # Provide visual coordinates
                # for points being dragged, moved or hovered.
                _ctx.fontsize(9)
                _ctx.fill(self.handle_color)
                txt = " ("+str(int(pt.x))+", "+str(int(pt.y))+")"
                if (i == self.edit and self.new == None) \
                or pt == self.new \
                and not pt.freehand:
                    _ctx.text(txt, pt.x+r, pt.y+2)
                elif self.overlap(x, y, pt.x, pt.y) \
                and not pt.freehand:
                    _ctx.text(txt, pt.x+r, pt.y+2)

                # Draw a circle for each point
                # in the path.
                if not pt.freehand:
                    if pt.cmd != MOVETO:
                        _ctx.fill(self.path_color)
                        _ctx.nostroke()
                    else:
                        _ctx.stroke(self.path_color)
                        _ctx.nofill()
                    _ctx.oval(pt.x-r/2, pt.y-r/2, r, r)

            # Draw the current path,
            # update the path property.
            _ctx.stroke(self.path_color)
            _ctx.fill(self.path_fill)
            _ctx.autoclosepath(False)
            p = _ctx.endpath()
            self.path = p

            # Possible to insert a point here.
            if self.insert:
                _ctx.stroke(self.handle_color)
                _ctx.nofill()
                _ctx.oval(x-r*0.8, y-r*0.8, r*1.6, r*1.6)

            # When not editing a node,
            # prospect how the curve will continue
            # when adding a new point.
            if self.edit == None \
            and self.new == None \
            and self.moveto != True \
            and not self.freehand:
                _ctx.nofill()
                _ctx.stroke(self.new_color)
                rx, ry = self.reflect(pt.x, pt.y, pt.ctrl2.x, pt.ctrl2.y)
                _ctx.beginpath(pt.x, pt.y)
                _ctx.curveto(rx, ry, x, y, x, y)
                _ctx.endpath()

                # A dashed line indicates what
                # a CLOSETO would look like.
                if self.last_moveto != None:
                    start = self.last_moveto
                else:
                    start = self._points[0]
                p = _ctx.line(x, y, start.x, start.y, draw=False)
                try: p._nsBezierPath.setLineDash_count_phase_([2,4], 2, 50)
                except:
                    pass
                _ctx.drawpath(p)

            # When doing a MOVETO,
            # show the new point hovering at the mouse location.
            elif self.edit == None \
            and self.new == None \
            and self.moveto != None:
                _ctx.stroke(self.new_color)
                _ctx.nofill()
                _ctx.oval(x-r*0.8, y-r*0.8, r*1.6, r*1.6)

            # Draws button for a point being edited.
            # The first button deletes the point.
            # The second button, which appears only on the last point
            # in the path, tells the editor to perform a MOVETO
            # before adding a new point.
            if self.edit != None:
                pt = self._points[self.edit]
                x = pt.x + self.btn_x
                y = pt.y + self.btn_y
                r = self.btn_r
                _ctx.nostroke()
                _ctx.fill(0,0,0,0.2)
                _ctx.fill(self.handle_color)
                _ctx.oval(x-r, y-r, r*2, r*2)
                _ctx.fill(1)
                _ctx.rotate(45)
                _ctx.rect(x-r+2, y-0.625, r+1, 1.25)
                _ctx.rotate(-90)
                _ctx.rect(x-r+2, y-0.625, r+1, 1.25)
                _ctx.reset()
                if self.edit == len(self._points)-1:
                    _ctx.fill(self.handle_color)
                    _ctx.oval(x+r*2+2-r, y-r, r*2, r*2)
                    _ctx.fill(1)
                    _ctx.rect(x+r*2+2-2.25, y-r+3, 1.5, r-1)
                    _ctx.rect(x+r*2+2+0.75, y-r+3, 1.5, r-1)

        # Handle onscreen notifications.
        # Any text in msg is displayed in a box in the center
        # and slowly fades away, after which msg is cleared.
        if self.msg != "":
            self.msg_alpha -= 0.1
            _ctx.nostroke()
            _ctx.fill(0,0,0, self.msg_alpha)
            _ctx.fontsize(18)
            _ctx.lineheight(1)
            w = _ctx.textwidth(self.msg)
            _ctx.rect(_ctx.WIDTH/2-w/2-9, _ctx.HEIGHT/2-27, w+18, 36, roundness=0.4)
            _ctx.fill(1,1,1, 0.8)
            _ctx.align(CENTER)
            _ctx.text(self.msg, 0, _ctx.HEIGHT/2, width=_ctx.WIDTH)
        if self.msg_alpha <= 0.0:
            self.msg = ""
            self.msg_alpha = 1.0

Response: Draw the editable path and interface elements.


Instruction:
Given the following Python 3 function, write the documentation
def draw_freehand(self):

        """ Freehand sketching.
        """

        if _ctx._ns["mousedown"]:

            x, y = mouse()
            if self.show_grid:
                x, y = self.grid.snap(x, y)

            if self.freehand_move == True:
                cmd = MOVETO
                self.freehand_move = False
            else:
                cmd = LINETO

            # Add a new LINETO to the path,
            # except when starting to draw,
            # then a MOVETO is added to the path.
            pt = PathElement()
            if cmd != MOVETO:
                pt.freehand = True # Used when mixed with curve drawing.
            else:
                pt.freehand = False
            pt.cmd = cmd
            pt.x = x
            pt.y = y
            pt.ctrl1 = Point(x,y)
            pt.ctrl2 = Point(x,y)
            self._points.append(pt)

            # Draw the current location of the cursor.
            r = 4
            _ctx.nofill()
            _ctx.stroke(self.handle_color)
            _ctx.oval(pt.x-r, pt.y-r, r*2, r*2)
            _ctx.fontsize(9)
            _ctx.fill(self.handle_color)
            _ctx.text(" ("+str(int(pt.x))+", "+str(int(pt.y))+")", pt.x+r, pt.y)

            self._dirty = True

        else:

            # Export the updated drawing,
            # remember to do a MOVETO on the next interaction.
            self.freehand_move = True
            if self._dirty:
                self._points[-1].freehand = False
                self.export_svg()
                self._dirty = False

Response: Draw the freehand sketching.


Instruction:
Create a Python 3 function to
export the path as SVG.

Response:
def export_svg(self):

        """ Exports the path as SVG.

        Uses the filename given when creating this object.
        The file is automatically updated to reflect
        changes to the path.

        """

        d = ""
        if len(self._points) > 0:
            d += "M "+str(self._points[0].x)+" "+str(self._points[0].y)+" "
            for pt in self._points:
                if pt.cmd == MOVETO:
                    d += "M "+str(pt.x)+" "+str(pt.y)+" "
                elif pt.cmd == LINETO:
                    d += "L "+str(pt.x)+" "+str(pt.y)+" "
                elif pt.cmd == CURVETO:
                    d += "C "
                    d += str(pt.ctrl1.x)+" "+str(pt.ctrl1.y)+" "
                    d += str(pt.ctrl2.x)+" "+str(pt.ctrl2.y)+" "
                    d += str(pt.x)+" "+str(pt.y)+" "

        c = "rgb("
        c += str(int(self.path_color.r*255)) + ","
        c += str(int(self.path_color.g*255)) + ","
        c += str(int(self.path_color.b*255)) + ")"

        s  = '<?xml version="1.0"?>\n'
        s += '<svg width="'+str(_ctx.WIDTH)+'pt" height="'+str(_ctx.HEIGHT)+'pt">\n'
        s += '<g>\n'
        s += '<path d="'+d+'" fill="none" stroke="'+c+'" stroke-width="'+str(self.strokewidth)+'" />\n'
        s += '</g>\n'
        s += '</svg>\n'

        f = open(self.file+".svg", "w")
        f.write(s)
        f.close()


Instruction:
Implement a function in Python 3 to
download the image from Flickr and returns the path property.

Response:
def download(self, size=SIZE_XLARGE, thumbnail=False, wait=60, asynchronous=False):

        """ Downloads this image to cache.

        Calling the download() method instantiates an asynchronous URLAccumulator
        that will fetch the image's URL from Flickr.
        A second process then downloads the file at the retrieved URL.

        Once it is done downloading, this image will have its path property
        set to an image file in the cache.

        """

        if thumbnail == True: size = SIZE_THUMBNAIL # backwards compatibility
        self._size = disambiguate_size(size)
        self._wait = wait
        self._asynchronous = asynchronous

        url  = "http://api.flickr.com/services/rest/?method=flickr.photos.getSizes"
        url += "&photo_id=" + self.id
        url += "&api_key=" + API_KEY
        URLAccumulator.__init__(self, url, wait, asynchronous, "flickr", ".xml", 2)

        if not asynchronous:
            return self.path


Instruction:
Write a Python 3 function for
handling right mouse button clicks

Response:
def gtk_mouse_button_down(self, widget, event):
        ''' Handle right mouse button clicks '''
        if self.menu_enabled and event.button == 3:
            menu = self.uimanager.get_widget('/Save as')
            menu.popup(None, None, None, None, event.button, event.time)
        else:
            super(ShoebotWindow, self).gtk_mouse_button_down(widget, event)


Instruction:
How would you code a function in Python 3 to
show the variables window.

Response:
def show_variables_window(self):
        """
        Show the variables window.
        """
        if self.var_window is None and self.bot._vars:
            self.var_window = VarWindow(self, self.bot, '%s variables' % (self.title or 'Shoebot'))
            self.var_window.window.connect("destroy", self.var_window_closed)


Instruction:
Write a Python 3 function that can
hide the variables window

Response:
def hide_variables_window(self):
        """
        Hide the variables window
        """
        if self.var_window is not None:
            self.var_window.window.destroy()
            self.var_window = None


Instruction:
How would you explain what the following Python 3 function does
def var_window_closed(self, widget):
        # TODO - Clean up the menu handling stuff its a bit spagetti right now
        self.action_group.get_action('vars').set_active(False)
        self.show_vars = False
        self.var_window = None

Response: Called if user clicked close button on var window


Instruction:
Can you implement a function in Python 3 that
tells the canvas to perform a snapshot when it s finished rendering

Response:
def schedule_snapshot(self, format):
        """
        Tell the canvas to perform a snapshot when it's finished rendering
        :param format:
        :return:
        """
        bot = self.bot
        canvas = self.bot.canvas
        script = bot._namespace['__file__']
        if script:
            filename = os.path.splitext(script)[0] + '.' + format
        else:
            filename = 'output.' + format

        f = canvas.output_closure(filename, self.bot._frame)
        self.scheduled_snapshots.append(f)


Instruction:
Here you have a function in Python 3, explain what it does
def trigger_fullscreen_action(self, fullscreen):
        action = self.action_group.get_action('fullscreen')
        action.set_active(fullscreen)

Response:
Toggle fullscreen from outside the GUI,
        causes the GUI to updated and run all its actions.


Instruction:
Can you tell what is the following Python 3 function doing
def do_window_close(self, widget, data=None):
        publish_event(QUIT_EVENT)

        if self.has_server:
            self.sock.close()

        self.hide_variables_window()

        self.destroy()
        self.window_open = False

Response: This function is called when the user closes the window.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def do_toggle_fullscreen(self, action):
        is_fullscreen = action.get_active()
        if is_fullscreen:
            self.fullscreen()
        else:
            self.unfullscreen()

Response: This function is called when the user clicks on the fullscreen of the user.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def do_toggle_play(self, action):
        # TODO - move this into bot controller
        # along with stuff in socketserver and shell
        if self.pause_speed is None and not action.get_active():
            self.pause_speed = self.bot._speed
            self.bot._speed = 0
        else:
            self.bot._speed = self.pause_speed
            self.pause_speed = None

Response: Widget Action to toggle play / pause.


Instruction:
Given the following Python 3 function, write the documentation
def do_toggle_variables(self, action):
        self.show_vars = action.get_active()
        if self.show_vars:
            self.show_variables_window()
        else:
            self.hide_variables_window()

Response: This method is called when the user clicks on the variables window.


Instruction:
How would you implement a function in Python 3 that
sets the default values. Called at __init__ and at the end of run.

Response:
def _set_initial_defaults(self):
        '''Set the default values. Called at __init__ and at the end of run(),
        do that new draw loop iterations don't take up values left over by the
        previous one.'''
        DEFAULT_WIDTH, DEFAULT_HEIGHT = self._canvas.DEFAULT_SIZE
        self.WIDTH = self._namespace.get('WIDTH', DEFAULT_WIDTH)
        self.HEIGHT = self._namespace.get('HEIGHT', DEFAULT_WIDTH)
        if 'WIDTH' in self._namespace or 'HEIGHT' in self._namespace:
            self.size(w=self._namespace.get('WIDTH'), h=self._namespace.get('HEIGHT'))

        self._transformmode = Bot.CENTER

        self._canvas.settings(
            fontfile="assets/notcouriersans.ttf",
            fontsize=16,
            align=Bot.LEFT,
            lineheight=1,
            fillcolor=self.color(.2),
            strokecolor=None,
            strokewidth=1.0,
            background=self.color(1, 1, 1))


Instruction:
Explain what the following Python 3 code does
def _key_pressed(self, key, keycode):
        '''GUI callback for key pressed'''
        self._namespace['key'] = key
        self._namespace['keycode'] = keycode
        self._namespace['keydown'] = True

Response: GUI callback for key pressed


Instruction:
Can you tell what is the following Python 3 function doing
def _makeInstance(self, clazz, args, kwargs):
        '''Creates an instance of a class defined in this document.
           This method sets the context of the object to the current context.'''
        inst = clazz(self, *args, **kwargs)
        return inst

Response: Creates an instance of a class defined in this document.


Instruction:
How would you explain what the following Python 3 function does
def _makeColorableInstance(self, clazz, args, kwargs):
        kwargs = dict(kwargs)

        fill = kwargs.get('fill', self._canvas.fillcolor)
        if not isinstance(fill, Color):
            fill = Color(fill, mode='rgb', color_range=1)
        kwargs['fill'] = fill

        stroke = kwargs.get('stroke', self._canvas.strokecolor)
        if not isinstance(stroke, Color):
            stroke = Color(stroke, mode='rgb', color_range=1)
        kwargs['stroke'] = stroke

        kwargs['strokewidth'] = kwargs.get('strokewidth', self._canvas.strokewidth)
        inst = clazz(self, *args, **kwargs)
        return inst

Response: Create an object of the specified class with the specified arguments and kwargs.


Instruction:
Here you have a function in Python 3, explain what it does
def color(self, *args):
        '''
        :param args: color in a supported format.

        :return: Color object containing the color.
        '''
        return self.Color(mode=self.color_mode, color_range=self.color_range, *args)

Response: Color method that returns a Color object containing the color.


Instruction:
Create a Python 3 function to
return an iterator that contains coordinate tuples.

Response:
def grid(self, cols, rows, colSize=1, rowSize=1, shuffled=False):
        """Returns an iterator that contains coordinate tuples.
        The grid can be used to quickly create grid-like structures.
        A common way to use them is:
            for x, y in grid(10,10,12,12):
                rect(x,y, 10,10)
        """
        # Taken ipsis verbis from Nodebox
        from random import shuffle
        rowRange = range(int(rows))
        colRange = range(int(cols))
        if (shuffled):
            shuffle(rowRange)
            shuffle(colRange)
        for y in rowRange:
            for x in colRange:
                yield (x * colSize, y * rowSize)


Instruction:
How would you code a function in Python 3 to
save the contents of current surface into a file or a Cairo surface or context.

Response:
def snapshot(self, target=None, defer=None, autonumber=False):
        '''Save the contents of current surface into a file or cairo surface/context

        :param filename: Can be a filename or a Cairo surface.
        :param defer: If true, buffering/threading may be employed however output will not be immediate.
        :param autonumber: If true then a number will be appended to the filename.
        '''
        if autonumber:
            file_number = self._frame
        else:
            file_number = None

        if isinstance(target, cairo.Surface):
            # snapshot to Cairo surface
            if defer is None:
                self._canvas.snapshot(surface, defer)
                defer = False
            ctx = cairo.Context(target)
            # this used to be self._canvas.snapshot, but I couldn't make it work.
            # self._canvas.snapshot(target, defer)
            # TODO: check if this breaks when taking more than 1 snapshot
            self._canvas._drawqueue.render(ctx)
            return
        elif target is None:
            # If nothing specified, use a default filename from the script name
            script_file = self._namespace.get('__file__')
            if script_file:
                target = os.path.splitext(script_file)[0] + '.svg'
                file_number = True

        if target:
            # snapshot to file, target is a filename
            if defer is None:
                defer = True
            self._canvas.snapshot(target, defer=defer, file_number=file_number)
        else:
            raise ShoebotError('No image saved')


Instruction:
Explain what the following Python 3 code does
def show(self, format='png', as_data=False):
        '''Returns an Image object of the current surface. Used for displaying
        output in Jupyter notebooks. Adapted from the cairo-jupyter project.'''

        from io import BytesIO

        b = BytesIO()

        if format == 'png':
            from IPython.display import Image
            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.WIDTH, self.HEIGHT)
            self.snapshot(surface)
            surface.write_to_png(b)
            b.seek(0)
            data = b.read()
            if as_data:
                return data
            else:
                return Image(data)
        elif format == 'svg':
            from IPython.display import SVG
            surface = cairo.SVGSurface(b, self.WIDTH, self.HEIGHT)
            surface.finish()
            b.seek(0)
            data = b.read()
            if as_data:
                return data
            else:
                return SVG(data)

Response:
Returns an Image object of the current surface. Used for displaying
            output in Jupyter notebooks.


Instruction:
Create a Python 3 function for
importing Nodebox libraries. Import Nodebox libraries. The libraries get _ctx which provides them with the nodebox API.

Response:
def ximport(self, libName):
        '''
        Import Nodebox libraries.

        The libraries get _ctx, which provides
        them with the nodebox API.

        :param libName: Library name to import
        '''
        # from Nodebox
        lib = __import__(libName)
        self._namespace[libName] = lib
        lib._ctx = self
        return lib


Instruction:
Write a Python 3 script for
setting the canvas size w h

Response:
def size(self, w=None, h=None):
        '''Set the canvas size

        Only the first call will actually be effective.

        :param w: Width
        :param h: height
        '''

        if not w:
            w = self._canvas.width
        if not h:
            h = self._canvas.height
        if not w and not h:
            return (self._canvas.width, self._canvas.height)

        # FIXME: Updating in all these places seems a bit hacky
        w, h = self._canvas.set_size((w, h))
        self._namespace['WIDTH'] = w
        self._namespace['HEIGHT'] = h
        self.WIDTH = w  # Added to make evolution example work
        self.HEIGHT = h


Instruction:
Write a Python 3 function for
setting animation framerate. :param framerate: Frames per second to run bot. :return: Current framerate of animation.

Response:
def speed(self, framerate=None):
        '''Set animation framerate.

        :param framerate: Frames per second to run bot.
        :return: Current framerate of animation.
        '''
        if framerate is not None:
            self._speed = framerate
            self._dynamic = True
        else:
            return self._speed


Instruction:
Make a summary of the following Python 3 code
def set_callbacks(self, **kwargs):
        ''' Set callbacks for input events '''
        for name in self.SUPPORTED_CALLBACKS:
            func = kwargs.get(name, getattr(self, name))
            setattr(self, name, func)

Response: Set callbacks for input events


Instruction:
Can you generate the documentation for the following Python 3 function
def complement(clr):
    clr = color(clr)
    colors = colorlist(clr)
    colors.append(clr.complement)

    return colors

Response: Returns the color and its complement in a list.


Instruction:
How would you code a function in Python 3 to
return a list of complementary colors.

Response:
def complementary(clr):
    """
    Returns a list of complementary colors.

    The complement is the color 180 degrees across
    the artistic RYB color wheel.
    The list contains darker and softer contrasting
    and complementing colors.
    """
    clr = color(clr)
    colors = colorlist(clr)

    # A contrasting color: much darker or lighter than the original.
    c = clr.copy()
    if clr.brightness > 0.4:
        c.brightness = 0.1 + c.brightness * 0.25
    else:
        c.brightness = 1.0 - c.brightness * 0.25
    colors.append(c)

    # A soft supporting color: lighter and less saturated.
    c = clr.copy()
    c.brightness = 0.3 + c.brightness
    c.saturation = 0.1 + c.saturation * 0.3
    colors.append(c)

    # A contrasting complement: very dark or very light.
    clr = clr.complement
    c = clr.copy()
    if clr.brightness > 0.3:
        c.brightness = 0.1 + clr.brightness * 0.25
    else:
        c.brightness = 1.0 - c.brightness * 0.25
    colors.append(c)

    # The complement and a light supporting variant.
    colors.append(clr)

    c = clr.copy()
    c.brightness = 0.3 + c.brightness
    c.saturation = 0.1 + c.saturation * 0.25
    colors.append(c)

    return colors


Instruction:
Make a summary of the following Python 3 code
def split_complementary(clr):
    clr = color(clr)
    colors = colorlist(clr)
    clr = clr.complement
    colors.append(clr.rotate_ryb(-30).lighten(0.1))
    colors.append(clr.rotate_ryb(30).lighten(0.1))

    return colors

Response: Returns a list with the split complement of the color.


Instruction:
Create a Python 3 function to
return the left half of the split complement.

Response:
def left_complement(clr):
    """
    Returns the left half of the split complement.

    A list is returned with the same darker and softer colors
    as in the complementary list, but using the hue of the
    left split complement instead of the complement itself.
    """
    left = split_complementary(clr)[1]
    colors = complementary(clr)
    colors[3].h = left.h
    colors[4].h = left.h
    colors[5].h = left.h

    colors = colorlist(
        colors[0], colors[2], colors[1], colors[3], colors[4], colors[5]
    )

    return colors


Instruction:
How would you explain what the following Python 3 function does
def right_complement(clr):
    right = split_complementary(clr)[2]
    colors = complementary(clr)
    colors[3].h = right.h
    colors[4].h = right.h
    colors[5].h = right.h

    colors = colorlist(
        colors[0], colors[2], colors[1], colors[5], colors[4], colors[3]
    )

    return colors

Response: Returns the right half of the split complement.


Instruction:
Write a Python 3 function for
returning an analogous color list for a given color.

Response:
def analogous(clr, angle=10, contrast=0.25):
    """
    Returns colors that are next to each other on the wheel.

    These yield natural color schemes (like shades of water or sky).
    The angle determines how far the colors are apart,
    making it bigger will introduce more variation.
    The contrast determines the darkness/lightness of
    the analogue colors in respect to the given colors.
    """
    contrast = max(0, min(contrast, 1.0))

    clr = color(clr)
    colors = colorlist(clr)

    for i, j in [(1, 2.2), (2, 1), (-1, -0.5), (-2, 1)]:
        c = clr.rotate_ryb(angle * i)
        t = 0.44 - j * 0.1
        if clr.brightness - contrast * j < t:
            c.brightness = t
        else:
            c.brightness = clr.brightness - contrast * j
        c.saturation -= 0.05
        colors.append(c)

    return colors


Instruction:
Here you have a function in Python 3, explain what it does
def monochrome(clr):
    def _wrap(x, min, threshold, plus):
        if x - min < threshold:
            return x + plus
        else:
            return x - min

    colors = colorlist(clr)

    c = clr.copy()
    c.brightness = _wrap(clr.brightness, 0.5, 0.2, 0.3)
    c.saturation = _wrap(clr.saturation, 0.3, 0.1, 0.3)
    colors.append(c)

    c = clr.copy()
    c.brightness = _wrap(clr.brightness, 0.2, 0.2, 0.6)
    colors.append(c)

    c = clr.copy()
    c.brightness = max(0.2, clr.brightness + (1 - clr.brightness) * 0.2)
    c.saturation = _wrap(clr.saturation, 0.3, 0.1, 0.3)
    colors.append(c)

    c = clr.copy()
    c.brightness = _wrap(clr.brightness, 0.5, 0.2, 0.3)
    colors.append(c)

    return colors

Response: Returns a list of colors in the same hue with varying brightness and saturation.


Instruction:
Write a Python 3 function for
returning a triad of colors.

Response:
def triad(clr, angle=120):
    """
    Returns a triad of colors.

    The triad is made up of this color and two other colors
    that together make up an equilateral triangle on
    the artistic color wheel.
    """
    clr = color(clr)
    colors = colorlist(clr)
    colors.append(clr.rotate_ryb(angle).lighten(0.1))
    colors.append(clr.rotate_ryb(-angle).lighten(0.1))

    return colors


Instruction:
Can you implement a function in Python 3 that
returns a tetrad of colors.

Response:
def tetrad(clr, angle=90):
    """
    Returns a tetrad of colors.

    The tetrad is made up of this color and three other colors
    that together make up a cross on the artistic color wheel.
    """
    clr = color(clr)
    colors = colorlist(clr)

    c = clr.rotate_ryb(angle)
    if clr.brightness < 0.5:
        c.brightness += 0.2
    else:
        c.brightness -= -0.2
    colors.append(c)

    c = clr.rotate_ryb(angle * 2)
    if clr.brightness < 0.5:
        c.brightness += 0.1
    else:
        c.brightness -= -0.1
    colors.append(c)

    colors.append(clr.rotate_ryb(angle * 3).lighten(0.1))

    return colors


Instruction:
Can you generate a brief explanation for the following Python 3 code
def compound(clr, flip=False):
    def _wrap(x, min, threshold, plus):
        if x - min < threshold:
            return x + plus
        else:
            return x - min

    d = 1
    if flip: d = -1

    clr = color(clr)
    colors = colorlist(clr)

    c = clr.rotate_ryb(30 * d)
    c.brightness = _wrap(clr.brightness, 0.25, 0.6, 0.25)
    colors.append(c)

    c = clr.rotate_ryb(30 * d)
    c.saturation = _wrap(clr.saturation, 0.4, 0.1, 0.4)
    c.brightness = _wrap(clr.brightness, 0.4, 0.2, 0.4)
    colors.append(c)

    c = clr.rotate_ryb(160 * d)
    c.saturation = _wrap(clr.saturation, 0.25, 0.1, 0.25)
    c.brightness = max(0.2, clr.brightness)
    colors.append(c)

    c = clr.rotate_ryb(150 * d)
    c.saturation = _wrap(clr.saturation, 0.1, 0.8, 0.1)
    c.brightness = _wrap(clr.brightness, 0.3, 0.6, 0.3)
    colors.append(c)

    c = clr.rotate_ryb(150 * d)
    c.saturation = _wrap(clr.saturation, 0.1, 0.8, 0.1)
    c.brightness = _wrap(clr.brightness, 0.4, 0.2, 0.4)
    # colors.append(c)

    return colors

Response: Returns a list of colors that are compound of the given colorlist.


Instruction:
Can you generate the documentation for the following Python 3 function
def outline(path, colors, precision=0.4, continuous=True):
    # The count of points in a given path/contour.
    def _point_count(path, precision):
        return max(int(path.length * precision * 0.5), 10)

    # The total count of points in the path.
    n = sum([_point_count(contour, precision) for contour in path.contours])

    # For a continuous gradient,
    # we need to calculate a subrange in the list of colors
    # for each contour to draw colors from.
    contour_i = 0
    contour_n = len(path.contours) - 1
    if contour_n == 0: continuous = False

    i = 0
    for contour in path.contours:

        if not continuous: i = 0

        # The number of points for each contour.
        j = _point_count(contour, precision)

        first = True
        for pt in contour.points(j):
            if first:
                first = False
            else:
                if not continuous:
                    # If we have a list of 100 colors and 50 points,
                    # point i maps to color i*2.
                    clr = float(i) / j * len(colors)
                else:
                    # In a continuous gradient of 100 colors,
                    # the 2nd contour in a path with 10 contours
                    # draws colors between 10-20
                    clr = float(i) / n * len(colors) - 1 * contour_i / contour_n
                _ctx.stroke(colors[int(clr)])
                _ctx.line(x0, y0, pt.x, pt.y)
            x0 = pt.x
            y0 = pt.y
            i += 1

        pt = contour.point(0.9999999)  # Fix in pathmatics!
        _ctx.line(x0, y0, pt.x, pt.y)
        contour_i += 1

Response: Outline a path with a list of colors.


Instruction:
Can you implement a function in Python 3 that
guesses the shade and hue name of a color.

Response:
def guess_name(clr):
    """
    Guesses the shade and hue name of a color.

    If the given color is named in the named_colors list, return that name.
    Otherwise guess its nearest hue and shade range.
    """
    clr = Color(clr)

    if clr.is_transparent: return "transparent"
    if clr.is_black: return "black"
    if clr.is_white: return "white"
    if clr.is_black: return "black"

    for name in named_colors:
        try:
            r, g, b = named_colors[name]
        except:
            continue
        if r == clr.r and g == clr.g and b == clr.b:
            return name

    for shade in shades:
        if clr in shade:
            return shade.name + " " + clr.nearest_hue()
            break

    return clr.nearest_hue()


Instruction:
Can you generate the documentation for the following Python 3 function
def shader(x, y, dx, dy, radius=300, angle=0, spread=90):
    if angle != None:
        radius *= 2

    # Get the distance and angle between point and light source.
    d = sqrt((dx - x) ** 2 + (dy - y) ** 2)
    a = degrees(atan2(dy - y, dx - x)) + 180

    # If no angle is defined,
    # light is emitted evenly in all directions
    # and carries as far as the defined radius
    # (e.g. like a radial gradient).
    if d <= radius:
        d1 = 1.0 * d / radius
    else:
        d1 = 1.0
    if angle is None:
        return 1 - d1

    # Normalize the light's direction and spread
    # between 0 and 360.
    angle = 360 - angle % 360
    spread = max(0, min(spread, 360))
    if spread == 0:
        return 0.0

    # Objects that fall within the spreaded direction
    # of the light are illuminated.
    d = abs(a - angle)
    if d <= spread / 2:
        d2 = d / spread + d1
    else:
        d2 = 1.0

    # Wrapping from 0 to 360:
    # a light source with a direction of 10 degrees
    # and a spread of 45 degrees illuminates
    # objects between 0 and 35 degrees and 350 and 360 degrees.
    if 360 - angle <= spread / 2:
        d = abs(360 - angle + a)
        if d <= spread / 2:
            d2 = d / spread + d1
    # Wrapping from 360 to 0.
    if angle < spread / 2:
        d = abs(360 + angle - a)
        if d <= spread / 2:
            d2 = d / spread + d1

    return 1 - max(0, min(d2, 1))

Response: Calculates the brightness of a light source at x y and dx dy and radius influences the strength of the light source at x y and dy.


Instruction:
Write a Python 3 function for
searching the theme cache for a specific color and range.

Response:
def search_engine(query, top=5, service="google", license=None,
                  cache=os.path.join(DEFAULT_CACHE, "google")):
    """
    Return a color aggregate from colors and ranges parsed from the web.
    T. De Smedt, http://nodebox.net/code/index.php/Prism
    """
    # Check if we have cached information first.
    try:
        a = theme(query, cache=cache)
        return a
    except:
        pass

    if service == "google":
        from web import google
        search_engine = google
    if service == "yahoo":
        from web import yahoo
        search_engine = yahoo
        if license:
            yahoo.license_key = license

    # Sort all the primary hues (plus black and white) for q.
    sorted_colors = search_engine.sort(
        [h for h in primary_hues] + ["black", "white"],
        context=query, strict=True, cached=True
    )

    # Sort all the shades (bright, hard, ...) for q.
    sorted_shades = search_engine.sort(
        [str(s) for s in shades],
        context=query, strict=True, cached=True
    )

    # Reforms '"black death"' to 'black'.
    f = lambda x: x.strip("\"").split()[0]

    # Take the top most relevant hues.
    n2 = sum([w for h, w in sorted_colors[:top]])
    sorted_colors = [(color(f(h)), w / n2) for h, w in sorted_colors[:top]]

    # Take the three most relevant shades.
    n2 = sum([w for s, w in sorted_shades[:3]])
    sorted_shades = [(shade(f(s)), w / n2) for s, w in sorted_shades[:3]]

    a = theme(cache=cache)
    a.name = query
    for clr, w1 in sorted_colors:
        for rng, w2 in sorted_shades:
            a.add_range(rng, clr, w1 * w2)

    a._save()
    return a


Instruction:
Given the following Python 3 function, write the documentation
def morguefile(query, n=10, top=10):

    from web import morguefile
    images = morguefile.search(query)[:top]
    path = choice(images).download(thumbnail=True, wait=10)

    return ColorList(path, n, name=query)

Response: Returns a list of colors drawn from a morgueFile image.


Instruction:
Here you have a function in Python 3, explain what it does
def str_to_rgb(self, str):

        """ Returns RGB values based on a descriptive string.

        If the given str is a named color, return its RGB values.
        Otherwise, return a random named color that has str
        in its name, or a random named color which name appears in str.

        Specific suffixes (-ish, -ed, -y and -like) are recognised
        as well, for example, if you need a random variation of "red"
        you can use reddish (or greenish, yellowy, etc.)

        """

        str = str.lower()
        for ch in "_- ":
            str = str.replace(ch, "")

        # if named_hues.has_key(str):
        #    clr = color(named_hues[str], 1, 1, mode="hsb")
        #    return clr.r, clr.g, clr.b

        if named_colors.has_key(str):
            return named_colors[str]

        for suffix in ["ish", "ed", "y", "like"]:
            str = re.sub("(.*?)" + suffix + "$", "\\1", str)
        str = re.sub("(.*?)dd$", "\\1d", str)

        matches = []
        for name in named_colors:
            if name in str or str in name:
                matches.append(named_colors[name])
        if len(matches) > 0:
            return choice(matches)

        return named_colors["transparent"]

Response: Converts a string to a named color or a random named color.


Instruction:
Implement a Python 3 function for
rotating the color wheel by the given angle.

Response:
def rotate_ryb(self, angle=180):

        """ Returns a color rotated on the artistic RYB color wheel.

        An artistic color wheel has slightly different opposites
        (e.g. purple-yellow instead of purple-lime).
        It is mathematically incorrect but generally assumed
        to provide better complementary colors.

        http://en.wikipedia.org/wiki/RYB_color_model

        """

        h = self.h * 360
        angle = angle % 360

        # Approximation of Itten's RYB color wheel.
        # In HSB, colors hues range from 0-360.
        # However, on the artistic color wheel these are not evenly distributed.
        # The second tuple value contains the actual distribution.
        wheel = [
            (0, 0), (15, 8),
            (30, 17), (45, 26),
            (60, 34), (75, 41),
            (90, 48), (105, 54),
            (120, 60), (135, 81),
            (150, 103), (165, 123),
            (180, 138), (195, 155),
            (210, 171), (225, 187),
            (240, 204), (255, 219),
            (270, 234), (285, 251),
            (300, 267), (315, 282),
            (330, 298), (345, 329),
            (360, 0)
        ]

        # Given a hue, find out under what angle it is
        # located on the artistic color wheel.
        for i in _range(len(wheel) - 1):
            x0, y0 = wheel[i]
            x1, y1 = wheel[i + 1]
            if y1 < y0:
                y1 += 360
            if y0 <= h <= y1:
                a = 1.0 * x0 + (x1 - x0) * (h - y0) / (y1 - y0)
                break

        # And the user-given angle (e.g. complement).
        a = (a + angle) % 360

        # For the given angle, find out what hue is
        # located there on the artistic color wheel.
        for i in _range(len(wheel) - 1):
            x0, y0 = wheel[i]
            x1, y1 = wheel[i + 1]
            if y1 < y0:
                y1 += 360
            if x0 <= a <= x1:
                h = 1.0 * y0 + (y1 - y0) * (a - x0) / (x1 - x0)
                break

        h = h % 360
        return Color(h / 360, self.s, self.brightness, self.a, mode="hsb", name="")


Instruction:
Can you write a function in Python 3 where it
returns the name of the nearest named hue.

Response:
def nearest_hue(self, primary=False):

        """ Returns the name of the nearest named hue.

        For example,
        if you supply an indigo color (a color between blue and violet),
        the return value is "violet". If primary is set  to True,
        the return value is "purple".

        Primary colors leave out the fuzzy lime, teal,
        cyan, azure and violet hues.

        """
        if self.is_black:
            return "black"
        elif self.is_white:
            return "white"
        elif self.is_grey:
            return "grey"

        if primary:
            hues = primary_hues
        else:
            hues = named_hues.keys()
        nearest, d = "", 1.0
        for hue in hues:
            if abs(self.hue - named_hues[hue]) % 1 < d:
                nearest, d = hue, abs(self.hue - named_hues[hue]) % 1

        return nearest


Instruction:
Can you generate a brief explanation for the following Python 3 code
def blend(self, clr, factor=0.5):
        r = self.r * (1 - factor) + clr.r * factor
        g = self.g * (1 - factor) + clr.g * factor
        b = self.b * (1 - factor) + clr.b * factor
        a = self.a * (1 - factor) + clr.a * factor
        return Color(r, g, b, a, mode="rgb")

Response: Blend this color with another color.


Instruction:
Given the following Python 3 function, write the documentation
def distance(self, clr):
        coord = lambda a, d: (cos(radians(a)) * d, sin(radians(a)) * d)
        x0, y0 = coord(self.h * 360, self.s)
        x1, y1 = coord(clr.h * 360, clr.s)
        z0 = self.brightness
        z1 = clr.brightness
        d = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2)
        return d

Response: Returns the Euclidean distance between two colors.


Instruction:
Can you generate the documentation for the following Python 3 function
def image_to_rgb(self, path, n=10):
        from PIL import Image
        img = Image.open(path)
        p = img.getdata()
        f = lambda p: choice(p)

        for i in _range(n):
            rgba = f(p)
            rgba = _list(rgba)
            if len(rgba) == 3:
                rgba.append(255)
            r, g, b, a = [v / 255.0 for v in rgba]
            clr = color(r, g, b, a, mode="rgb")
            self.append(clr)

Response: Convert an image to RGB colors.


Instruction:
Implement a Python 3 function for
returning the list of colors that have the given word in their context.

Response:
def context_to_rgb(self, str):
        """ Returns the colors that have the given word in their context.

        For example, the word "anger" appears
        in black, orange and red contexts,
        so the list will contain those three colors.

        """
        matches = []
        for clr in context:
            tags = context[clr]
            for tag in tags:
                if tag.startswith(str) \
                        or str.startswith(tag):
                    matches.append(clr)
                    break

        matches = [color(name) for name in matches]
        return matches


Instruction:
Write a Python 3 script for
returning the intersection of each color s context and each color s context.

Response:
def _context(self):
        """
        Returns the intersection of each color's context.

        Get the nearest named hue of each color,
        and finds overlapping tags in each hue's colors.
        For example, a list containing yellow, deeppink and olive
        yields: femininity, friendship, happiness, joy.

        """
        tags1 = None
        for clr in self:
            overlap = []
            if clr.is_black:
                name = "black"
            elif clr.is_white:
                name = "white"
            elif clr.is_grey:
                name = "grey"
            else:
                name = clr.nearest_hue(primary=True)
            if name == "orange" and clr.brightness < 0.6:
                name = "brown"
            tags2 = context[name]
            if tags1 is None:
                tags1 = tags2
            else:
                for tag in tags2:
                    if tag in tags1:
                        if tag not in overlap:
                            overlap.append(tag)
                tags1 = overlap

        overlap.sort()
        return overlap


Instruction:
Can you implement a function in Python 3 that
returns a deep copy of the list.

Response:
def copy(self):

        """ Returns a deep copy of the list.
        """

        return ColorList(
            [color(clr.r, clr.g, clr.b, clr.a, mode="rgb") for clr in self],
            name=self.name,
            tags=self.tags
        )


Instruction:
Write a Python 3 script for
returning the darkest color from the list.

Response:
def _darkest(self):
        """
        Returns the darkest color from the list.

        Knowing the contrast between a light and a dark swatch
        can help us decide how to display readable typography.

        """
        min, n = (1.0, 1.0, 1.0), 3.0
        for clr in self:
            if clr.r + clr.g + clr.b < n:
                min, n = clr, clr.r + clr.g + clr.b

        return min


Instruction:
How would you implement a function in Python 3 that
returns one average color for the colors in the list.

Response:
def _average(self):
        """
        Returns one average color for the colors in the list.
        """
        r, g, b, a = 0, 0, 0, 0
        for clr in self:
            r += clr.r
            g += clr.g
            b += clr.b
            a += clr.alpha

        r /= len(self)
        g /= len(self)
        b /= len(self)
        a /= len(self)

        return color(r, g, b, a, mode="rgb")


Instruction:
How would you explain what the following Python 3 function does
def sort_by_distance(self, reversed=False):
        if len(self) == 0: return ColorList()

        # Find the darkest color in the list.
        root = self[0]
        for clr in self[1:]:
            if clr.brightness < root.brightness:
                root = clr

        # Remove the darkest color from the stack,
        # put it in the sorted list as starting element.
        stack = [clr for clr in self]
        stack.remove(root)
        sorted = [root]

        # Now find the color in the stack closest to that color.
        # Take this color from the stack and add it to the sorted list.
        # Now find the color closest to that color, etc.
        while len(stack) > 1:
            closest, distance = stack[0], stack[0].distance(sorted[-1])
            for clr in stack[1:]:
                d = clr.distance(sorted[-1])
                if d < distance:
                    closest, distance = clr, d
            stack.remove(closest)
            sorted.append(closest)
        sorted.append(stack[0])

        if reversed: _list.reverse(sorted)
        return ColorList(sorted)

Response: Returns a list with the smallest distance between two neighboring colors.


Instruction:
Write a Python 3 function for
returning a sorted copy of the color list according to the given comparison.

Response:
def _sorted_copy(self, comparison, reversed=False):
        """
        Returns a sorted copy with the colors arranged according to the given comparison.
        """
        sorted = self.copy()
        _list.sort(sorted, comparison)
        if reversed:
            _list.reverse(sorted)
        return sorted


Instruction:
Given the following Python 3 function, write the documentation
def cluster_sort(self, cmp1="hue", cmp2="brightness", reversed=False, n=12):
        sorted = self.sort(cmp1)
        clusters = ColorList()

        d = 1.0
        i = 0
        for j in _range(len(sorted)):
            if getattr(sorted[j], cmp1) < d:
                clusters.extend(sorted[i:j].sort(cmp2))
                d -= 1.0 / n
                i = j
        clusters.extend(sorted[i:].sort(cmp2))
        if reversed: _list.reverse(clusters)
        return clusters

Response: Sorts the list by cmp1 then cuts it into n pieces which are sorted by cmp2.


Instruction:
Implement a Python 3 function for
returning a reversed copy of the list.

Response:
def reverse(self):
        """
        Returns a reversed copy of the list.
        """
        colors = ColorList.copy(self)
        _list.reverse(colors)
        return colors


Instruction:
Create a Python 3 function for
returning a list that is a repetition of the given list.

Response:
def repeat(self, n=2, oscillate=False, callback=None):
        """
        Returns a list that is a repetition of the given list.

        When oscillate is True,
        moves from the end back to the beginning,
        and then from the beginning to the end, and so on.
        """
        colorlist = ColorList()
        colors = ColorList.copy(self)
        for i in _range(n):
            colorlist.extend(colors)
            if oscillate: colors = colors.reverse()
            if callback: colors = callback(colors)

        return colorlist