def node(s, node, alpha=1.0):

    """ Visualization of a default node.
    """

    if s.depth:
        try: colors.shadow(dx=5, dy=5, blur=10, alpha=0.5*alpha)
        except: pass

    s._ctx.nofill()
    s._ctx.nostroke()
    if s.fill:
        s._ctx.fill(
            s.fill.r,
            s.fill.g,
            s.fill.b,
            s.fill.a * alpha
        )
    if s.stroke:
        s._ctx.strokewidth(s.strokewidth)
        s._ctx.stroke(
            s.stroke.r,
            s.stroke.g,
            s.stroke.b,
            s.stroke.a * alpha * 3
        )
    r = node.r
    s._ctx.oval(node.x-r, node.y-r, r*2, r*2)

def node ( s , node , alpha = 1.0 ) : if s . depth : try : colors . shadow ( dx = 5 , dy = 5 , blur = 10 , alpha = 0.5 * alpha ) except : pass s . _ctx . nofill ( ) s . _ctx . nostroke ( ) if s . fill : s . _ctx . fill ( s . fill . r , s . fill . g , s . fill . b , s . fill . a * alpha ) if s . stroke : s . _ctx . strokewidth ( s . strokewidth ) s . _ctx . stroke ( s . stroke . r , s . stroke . g , s . stroke . b , s . stroke . a * alpha * 3 ) r = node . r s . _ctx . oval ( node . x - r , node . y - r , r * 2 , r * 2 )


def node_label(s, node, alpha=1.0):

    """ Visualization of a node's id.
    """

    if s.text:
        #s._ctx.lineheight(1)
        s._ctx.font(s.font)
        s._ctx.fontsize(s.fontsize)
        s._ctx.nostroke()
        s._ctx.fill(
            s.text.r,
            s.text.g,
            s.text.b,
            s.text.a * alpha
        )

        # Cache an outlined label text and translate it.
        # This enhances the speed and avoids wiggling text.
        try: p = node._textpath
        except:
            txt = node.label
            try: txt = unicode(txt)
            except:
                try: txt = txt.decode("utf-8")
                except:
                    pass
            # Abbreviation.
            #root = node.graph.root
            #if txt != root and txt[-len(root):] == root:
            #    txt = txt[:len(txt)-len(root)]+root[0]+"."
            dx, dy = 0, 0
            if s.align == 2: #CENTER
                dx = -s._ctx.textwidth(txt, s.textwidth) / 2
                dy =  s._ctx.textheight(txt) / 2
            node._textpath = s._ctx.textpath(txt, dx, dy, width=s.textwidth)
            p = node._textpath

        if s.depth:
            try: __colors.shadow(dx=2, dy=4, blur=5, alpha=0.3*alpha)
            except: pass

        s._ctx.push()
        s._ctx.translate(node.x, node.y)
        s._ctx.scale(alpha)
        s._ctx.drawpath(p.copy())
        s._ctx.pop()

def node_label ( s , node , alpha = 1.0 ) : if s . text : s . _ctx . font ( s . font ) s . _ctx . fontsize ( s . fontsize ) s . _ctx . nostroke ( ) s . _ctx . fill ( s . text . r , s . text . g , s . text . b , s . text . a * alpha ) try : p = node . _textpath except : txt = node . label try : txt = unicode ( txt ) except : try : txt = txt . decode ( "utf-8" ) except : pass dx , dy = 0 , 0 if s . align == 2 : dx = - s . _ctx . textwidth ( txt , s . textwidth ) / 2 dy = s . _ctx . textheight ( txt ) / 2 node . _textpath = s . _ctx . textpath ( txt , dx , dy , width = s . textwidth ) p = node . _textpath if s . depth : try : __colors . shadow ( dx = 2 , dy = 4 , blur = 5 , alpha = 0.3 * alpha ) except : pass s . _ctx . push ( ) s . _ctx . translate ( node . x , node . y ) s . _ctx . scale ( alpha ) s . _ctx . drawpath ( p . copy ( ) ) s . _ctx . pop ( )


def edges(s, edges, alpha=1.0, weighted=False, directed=False):

    """ Visualization of the edges in a network.
    """

    p = s._ctx.BezierPath()

    if directed and s.stroke:
        pd = s._ctx.BezierPath()
    if weighted and s.fill:
        pw = [s._ctx.BezierPath() for i in range(11)]

    # Draw the edges in a single BezierPath for speed.
    # Weighted edges are divided into ten BezierPaths,
    # depending on their weight rounded between 0 and 10.
    if len(edges) == 0: return
    for e in edges:
        try:  s2 = e.node1.graph.styles[e.node1.style]
        except: s2 = s
        if s2.edge:
            s2.edge(s2, p, e, alpha)
            if directed and s.stroke:
                s2.edge_arrow(s2, pd, e, radius=10)
            if weighted and s.fill:
                s2.edge(s2, pw[int(e.weight*10)], e, alpha)

    s._ctx.autoclosepath(False)
    s._ctx.nofill()
    s._ctx.nostroke()

    # All weighted edges use the default fill.
    if weighted and s.fill:
        r = e.node1.__class__(None).r
        s._ctx.stroke(
            s.fill.r,
            s.fill.g,
            s.fill.b,
            s.fill.a * 0.65 * alpha
        )
        for w in range(1, len(pw)):
            s._ctx.strokewidth(r*w*0.1)
            s._ctx.drawpath(pw[w].copy())

    # All edges use the default stroke.
    if s.stroke:
        s._ctx.strokewidth(s.strokewidth)

        s._ctx.stroke(
            s.stroke.r,
            s.stroke.g,
            s.stroke.b,
            s.stroke.a * 0.65 * alpha
        )

    s._ctx.drawpath(p.copy())

    if directed and s.stroke:
        #clr = s._ctx.stroke().copy()
	clr=s._ctx.color(
            s.stroke.r,
            s.stroke.g,
            s.stroke.b,
            s.stroke.a * 0.65 * alpha
        )

        clr.a *= 1.3

	s._ctx.stroke(clr)

    	s._ctx.drawpath(pd.copy())

    for e in edges:
        try:  s2 = self.styles[e.node1.style]
        except: s2 = s
        if s2.edge_label:
            s2.edge_label(s2, e, alpha)

def edges ( s , edges , alpha = 1.0 , weighted = False , directed = False ) : p = s . _ctx . BezierPath ( ) if directed and s . stroke : pd = s . _ctx . BezierPath ( ) if weighted and s . fill : pw = [ s . _ctx . BezierPath ( ) for i in range ( 11 ) ] if len ( edges ) == 0 : return for e in edges : try : s2 = e . node1 . graph . styles [ e . node1 . style ] except : s2 = s if s2 . edge : s2 . edge ( s2 , p , e , alpha ) if directed and s . stroke : s2 . edge_arrow ( s2 , pd , e , radius = 10 ) if weighted and s . fill : s2 . edge ( s2 , pw [ int ( e . weight * 10 ) ] , e , alpha ) s . _ctx . autoclosepath ( False ) s . _ctx . nofill ( ) s . _ctx . nostroke ( ) if weighted and s . fill : r = e . node1 . __class__ ( None ) . r s . _ctx . stroke ( s . fill . r , s . fill . g , s . fill . b , s . fill . a * 0.65 * alpha ) for w in range ( 1 , len ( pw ) ) : s . _ctx . strokewidth ( r * w * 0.1 ) s . _ctx . drawpath ( pw [ w ] . copy ( ) ) if s . stroke : s . _ctx . strokewidth ( s . strokewidth ) s . _ctx . stroke ( s . stroke . r , s . stroke . g , s . stroke . b , s . stroke . a * 0.65 * alpha ) s . _ctx . drawpath ( p . copy ( ) ) if directed and s . stroke : clr = s . _ctx . color ( s . stroke . r , s . stroke . g , s . stroke . b , s . stroke . a * 0.65 * alpha ) clr . a *= 1.3 s . _ctx . stroke ( clr ) s . _ctx . drawpath ( pd . copy ( ) ) for e in edges : try : s2 = self . styles [ e . node1 . style ] except : s2 = s if s2 . edge_label : s2 . edge_label ( s2 , e , alpha )

Visualization of the edges in a network .


def edge(s, path, edge, alpha=1.0):

    """ Visualization of a single edge between two nodes.
    """

    path.moveto(edge.node1.x, edge.node1.y)
    if edge.node2.style == BACK:
        path.curveto(
            edge.node1.x,
            edge.node2.y,
            edge.node2.x,
            edge.node2.y,
            edge.node2.x,
            edge.node2.y,
        )
    else:
        path.lineto(
            edge.node2.x,
            edge.node2.y
        )

def edge ( s , path , edge , alpha = 1.0 ) : path . moveto ( edge . node1 . x , edge . node1 . y ) if edge . node2 . style == BACK : path . curveto ( edge . node1 . x , edge . node2 . y , edge . node2 . x , edge . node2 . y , edge . node2 . x , edge . node2 . y , ) else : path . lineto ( edge . node2 . x , edge . node2 . y )

Visualization of a single edge between two nodes .


def edge_label(s, edge, alpha=1.0):

    """ Visualization of the label accompanying an edge.
    """

    if s.text and edge.label != "":
        s._ctx.nostroke()
        s._ctx.fill(
            s.text.r,
            s.text.g,
            s.text.b,
            s.text.a * alpha*0.75
        )
        s._ctx.lineheight(1)
        s._ctx.font(s.font)
        s._ctx.fontsize(s.fontsize*0.75)

        # Cache an outlined label text and translate it.
        # This enhances the speed and avoids wiggling text.
        try: p = edge._textpath
        except:
            try: txt = unicode(edge.label)
            except:
                try: txt = edge.label.decode("utf-8")
                except:
                    pass
            edge._textpath = s._ctx.textpath(txt, s._ctx.textwidth(" "), 0, width=s.textwidth)
            p = edge._textpath

        # Position the label centrally along the edge line.
        a  = degrees( atan2(edge.node2.y-edge.node1.y, edge.node2.x-edge.node1.x) )
        d  = sqrt((edge.node2.x-edge.node1.x)**2 +(edge.node2.y-edge.node1.y)**2)
        d  = abs(d-s._ctx.textwidth(edge.label)) * 0.5

        s._ctx.push()
        s._ctx.transform(CORNER)
        s._ctx.translate(edge.node1.x, edge.node1.y)
        s._ctx.rotate(-a)
        s._ctx.translate(d, s.fontsize*1.0)
        s._ctx.scale(alpha)

        # Flip labels on the left hand side so they are legible.
        if 90 < a%360 < 270:
            s._ctx.translate(s._ctx.textwidth(edge.label), -s.fontsize*2.0)
            s._ctx.transform(CENTER)
            s._ctx.rotate(180)
            s._ctx.transform(CORNER)

        s._ctx.drawpath(p.copy())
        s._ctx.pop()

def
edge_label
(
s
,
edge
,
alpha
=
1.0
)
:
if
s
.
text
and
edge
.
label
!=
""
:
s
.
_ctx
.
nostroke
(
)
s
.
_ctx
.
fill
(
s
.
text
.
r
,
s
.
text
.
g
,
s
.
text
.
b
,
s
.
text
.
a
*
alpha
*
0.75
)
s
.
_ctx
.
lineheight
(
1
)
s
.
_ctx
.
font
(
s
.
font
)
s
.
_ctx
.
fontsize
(
s
.
fontsize
*
0.75
)
try
:
p
=
edge
.
_textpath
except
:
try
:
txt
=
unicode
(
edge
.
label
)
except
:
try
:
txt
=
edge
.
label
.
decode
(
"utf-8"
)
except
:
pass
edge
.
_textpath
=
s
.
_ctx
.
textpath
(
txt
,
s
.
_ctx
.
textwidth
(
" "
)
,
0
,
width
=
s
.
textwidth
)
p
=
edge
.
_textpath
a
=
degrees
(
atan2
(
edge
.
node2
.
y
edge
.
node1
.
y
,
edge
.
node2
.
x
edge
.
node1
.
x
)
)
d
=
sqrt
(
(
edge
.
node2
.
x
edge
.
node1
.
x
)
**
2
+
(
edge
.
node2
.
y
edge
.
node1
.
y
)
**
2
)
d
=
abs
(
d
s
.
_ctx
.
textwidth
(
edge
.
label
)
)
*
0.5
s
.
_ctx
.
push
(
)
s
.
_ctx
.
transform
(
CORNER
)
s
.
_ctx
.
translate
(
edge
.
node1
.
x
,
edge
.
node1
.
y
)
s
.
_ctx
.
rotate
(
a
)
s
.
_ctx
.
translate
(
d
,
s
.
fontsize
*
1.0
)
s
.
_ctx
.
scale
(
alpha
)
if
90
<
a
%
360
<
270
:
s
.
_ctx
.
translate
(
s
.
_ctx
.
textwidth
(
edge
.
label
)
,
s
.
fontsize
*
2.0
)
s
.
_ctx
.
transform
(
CENTER
)
s
.
_ctx
.
rotate
(
180
)
s
.
_ctx
.
transform
(
CORNER
)
s
.
_ctx
.
drawpath
(
p
.
copy
(
)
)
s
.
_ctx
.
pop
(
)

Visualization of the label accompanying an edge .


def path(s, graph, path):

    """ Visualization of a shortest path between two nodes.
    """

    def end(n):
        r = n.r * 0.35
        s._ctx.oval(n.x-r, n.y-r, r*2, r*2)

    if path and len(path) > 1 and s.stroke:

        s._ctx.nofill()
        s._ctx.stroke(
            s.stroke.r,
            s.stroke.g,
            s.stroke.b,
            s.stroke.a
        )
        if s.name != DEFAULT:
            s._ctx.strokewidth(s.strokewidth)
        else:
            s._ctx.strokewidth(s.strokewidth*2)

        first = True
        for id in path:
            n = graph[id]
            if first:
                first = False
                s._ctx.beginpath(n.x, n.y)
                end(n)
            else:
                s._ctx.lineto(n.x, n.y)
        s._ctx.endpath()
        end(n)

def path ( s , graph , path ) : def end ( n ) : r = n . r * 0.35 s . _ctx . oval ( n . x - r , n . y - r , r * 2 , r * 2 ) if path and len ( path ) > 1 and s . stroke : s . _ctx . nofill ( ) s . _ctx . stroke ( s . stroke . r , s . stroke . g , s . stroke . b , s . stroke . a ) if s . name != DEFAULT : s . _ctx . strokewidth ( s . strokewidth ) else : s . _ctx . strokewidth ( s . strokewidth * 2 ) first = True for id in path : n = graph [ id ] if first : first = False s . _ctx . beginpath ( n . x , n . y ) end ( n ) else : s . _ctx . lineto ( n . x , n . y ) s . _ctx . endpath ( ) end ( n )

Visualization of a shortest path between two nodes .


def create(self, stylename, **kwargs):
        """ Creates a new style which inherits from the default style,
        or any other style which name is supplied to the optional template parameter.
        """
        if stylename == "default":
            self[stylename] = style(stylename, self._ctx, **kwargs)
            return self[stylename]
        k = kwargs.get("template", "default")
        s = self[stylename] = self[k].copy(stylename)
        for attr in kwargs:
            if s.__dict__.has_key(attr):
                s.__dict__[attr] = kwargs[attr]
        return s

def create ( self , stylename , ** kwargs ) : if stylename == "default" : self [ stylename ] = style ( stylename , self . _ctx , ** kwargs ) return self [ stylename ] k = kwargs . get ( "template" , "default" ) s = self [ stylename ] = self [ k ] . copy ( stylename ) for attr in kwargs : if s . __dict__ . has_key ( attr ) : s . __dict__ [ attr ] = kwargs [ attr ] return s

Creates a new style which inherits from the default style or any other style which name is supplied to the optional template parameter .


def copy(self, graph):
        """ Returns a copy of all styles and a copy of the styleguide.
        """
        s = styles(graph)
        s.guide = self.guide.copy(graph)
        dict.__init__(s, [(v.name, v.copy()) for v in self.values()])
        return s

def copy ( self , graph ) : s = styles ( graph ) s . guide = self . guide . copy ( graph ) dict . __init__ ( s , [ ( v . name , v . copy ( ) ) for v in self . values ( ) ] ) return s

Returns a copy of all styles and a copy of the styleguide .


def apply(self):
        """ Check the rules for each node in the graph and apply the style.
        """
        sorted = self.order + self.keys()
        unique = []; [unique.append(x) for x in sorted if x not in unique]
        for node in self.graph.nodes:
            for s in unique:
                if self.has_key(s) and self[s](self.graph, node):
                    node.style = s

def apply ( self ) : sorted = self . order + self . keys ( ) unique = [ ] [ unique . append ( x ) for x in sorted if x not in unique ] for node in self . graph . nodes : for s in unique : if self . has_key ( s ) and self [ s ] ( self . graph , node ) : node . style = s

Check the rules for each node in the graph and apply the style .


def copy(self, graph):
        """ Returns a copy of the styleguide for the given graph.
        """
        g = styleguide(graph)
        g.order = self.order
        dict.__init__(g, [(k, v) for k, v in self.iteritems()])
        return g

def copy ( self , graph ) : g = styleguide ( graph ) g . order = self . order dict . __init__ ( g , [ ( k , v ) for k , v in self . iteritems ( ) ] ) return g

Returns a copy of the styleguide for the given graph .


def open_socket(self):
        """
        Opens the socket and binds to the given host and port. Uses
        SO_REUSEADDR to be as robust as possible.
        """
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.setblocking(0)
        self.socket.bind((self.host, self.port))

def open_socket ( self ) : self . socket = socket . socket ( socket . AF_INET , socket . SOCK_DGRAM ) self . socket . setsockopt ( socket . SOL_SOCKET , socket . SO_REUSEADDR , 1 ) self . socket . setblocking ( 0 ) self . socket . bind ( ( self . host , self . port ) )

Opens the socket and binds to the given host and port . Uses SO_REUSEADDR to be as robust as possible .


def load_profiles(self):
        """
        Loads all possible TUIO profiles and returns a dictionary with the
        profile addresses as keys and an instance of a profile as the value
        """
        _profiles = {}
        for name, klass in inspect.getmembers(profiles):
            if inspect.isclass(klass) and name.endswith('Profile') and name != 'TuioProfile':
                # Adding profile to the self.profiles dictionary
                profile = klass()
                _profiles[profile.address] = profile
                # setting convenient variable to access objects of profile
                try:
                    setattr(self, profile.list_label, profile.objs)
                except AttributeError:
                    continue
                # Mapping callback method to every profile
                self.manager.add(self.callback, profile.address)
        return _profiles

def load_profiles ( self ) : _profiles = { } for name , klass in inspect . getmembers ( profiles ) : if inspect . isclass ( klass ) and name . endswith ( 'Profile' ) and name != 'TuioProfile' : profile = klass ( ) _profiles [ profile . address ] = profile try : setattr ( self , profile . list_label , profile . objs ) except AttributeError : continue self . manager . add ( self . callback , profile . address ) return _profiles


def update(self):
        """
        Tells the connection manager to receive the next 1024 byte of messages
        to analyze.
        """
        try:
            self.manager.handle(self.socket.recv(1024))
        except socket.error:
            pass

def update ( self ) : try : self . manager . handle ( self . socket . recv ( 1024 ) ) except socket . error : pass

Tells the connection manager to receive the next 1024 byte of messages to analyze .


def callback(self, *incoming):
        """
        Gets called by the CallbackManager if a new message was received
        """
        message = incoming[0]
        if message:
            address, command = message[0], message[2]
            profile = self.get_profile(address)
            if profile is not None:
                try:
                    getattr(profile, command)(self, message)
                except AttributeError:
                    pass

def callback ( self , * incoming ) : message = incoming [ 0 ] if message : address , command = message [ 0 ] , message [ 2 ] profile = self . get_profile ( address ) if profile is not None : try : getattr ( profile , command ) ( self , message ) except AttributeError : pass


def copytree(src, dst, symlinks=False, ignore=None):
    """
    copytree that works even if folder already exists
    """
    # http://stackoverflow.com/questions/1868714/how-do-i-copy-an-entire-directory-of-files-into-an-existing-directory-using-pyth
    if not os.path.exists(dst):
        os.makedirs(dst)
        shutil.copystat(src, dst)
    lst = os.listdir(src)
    if ignore:
        excl = ignore(src, lst)
        lst = [x for x in lst if x not in excl]
    for item in lst:
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if symlinks and os.path.islink(s):
            if os.path.lexists(d):
                os.remove(d)
            os.symlink(os.readlink(s), d)
            try:
                st = os.lstat(s)
                mode = stat.S_IMODE(st.st_mode)
                os.lchmod(d, mode)
            except:
                pass  # lchmod not available
        elif os.path.isdir(s):
            copytree(s, d, symlinks, ignore)
        else:
            shutil.copy2(s, d)

def copytree ( src , dst , symlinks = False , ignore = None ) : if not os . path . exists ( dst ) : os . makedirs ( dst ) shutil . copystat ( src , dst ) lst = os . listdir ( src ) if ignore : excl = ignore ( src , lst ) lst = [ x for x in lst if x not in excl ] for item in lst : s = os . path . join ( src , item ) d = os . path . join ( dst , item ) if symlinks and os . path . islink ( s ) : if os . path . lexists ( d ) : os . remove ( d ) os . symlink ( os . readlink ( s ) , d ) try : st = os . lstat ( s ) mode = stat . S_IMODE ( st . st_mode ) os . lchmod ( d , mode ) except : pass elif os . path . isdir ( s ) : copytree ( s , d , symlinks , ignore ) else : shutil . copy2 ( s , d )


def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
        allow_nan=True, cls=None, indent=None, separators=None,
        encoding='utf-8', default=None, **kw):
    """
    Serialize ``obj`` to a JSON formatted ``str``.

    If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
    (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
    will be skipped instead of raising a ``TypeError``.

    If ``ensure_ascii`` is ``False``, then the return value will be a
    ``unicode`` instance subject to normal Python ``str`` to ``unicode``
    coercion rules instead of being escaped to an ASCII ``str``.

    If ``check_circular`` is ``False``, then the circular reference check
    for container types will be skipped and a circular reference will
    result in an ``OverflowError`` (or worse).

    If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
    strict compliance of the JSON specification, instead of using the
    JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).

    If ``indent`` is a non-negative integer, then JSON array elements and
    object members will be pretty-printed with that indent level. An indent
    level of 0 will only insert newlines. ``None`` is the most compact
    representation.

    If ``separators`` is an ``(item_separator, dict_separator)`` tuple
    then it will be used instead of the default ``(', ', ': ')`` separators.
    ``(',', ':')`` is the most compact JSON representation.

    ``encoding`` is the character encoding for str instances, default is UTF-8.

    ``default(obj)`` is a function that should return a serializable version
    of obj or raise TypeError. The default simply raises TypeError.

    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
    ``.default()`` method to serialize additional types), specify it with
    the ``cls`` kwarg.
    """
    # cached encoder
    if (skipkeys is False and ensure_ascii is True and
        check_circular is True and allow_nan is True and
        cls is None and indent is None and separators is None and
        encoding == 'utf-8' and default is None and not kw):
        return _default_encoder.encode(obj)
    if cls is None:
        cls = JSONEncoder
    return cls(
        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
        separators=separators, encoding=encoding, default=default,
        **kw).encode(obj)

def dumps ( obj , skipkeys = False , ensure_ascii = True , check_circular = True , allow_nan = True , cls = None , indent = None , separators = None , encoding = 'utf-8' , default = None , ** kw ) : if ( skipkeys is False and ensure_ascii is True and check_circular is True and allow_nan is True and cls is None and indent is None and separators is None and encoding == 'utf-8' and default is None and not kw ) : return _default_encoder . encode ( obj ) if cls is None : cls = JSONEncoder return cls ( skipkeys = skipkeys , ensure_ascii = ensure_ascii , check_circular = check_circular , allow_nan = allow_nan , indent = indent , separators = separators , encoding = encoding , default = default , ** kw ) . encode ( obj )


def search(q, start=0, wait=10, asynchronous=False, cached=False):

    """ Returns a Google web query formatted as a GoogleSearch list object.
    """

    service = GOOGLE_SEARCH
    return GoogleSearch(q, start, service, "", wait, asynchronous, cached)

def search ( q , start = 0 , wait = 10 , asynchronous = False , cached = False ) : service = GOOGLE_SEARCH return GoogleSearch ( q , start , service , "" , wait , asynchronous , cached )

Returns a Google web query formatted as a GoogleSearch list object .


def search_images(q, start=0, size="", wait=10, asynchronous=False, cached=False):

    """ Returns a Google images query formatted as a GoogleSearch list object.
    """

    service = GOOGLE_IMAGES
    return GoogleSearch(q, start, service, size, wait, asynchronous, cached)

def search_images ( q , start = 0 , size = "" , wait = 10 , asynchronous = False , cached = False ) : service = GOOGLE_IMAGES return GoogleSearch ( q , start , service , size , wait , asynchronous , cached )

Returns a Google images query formatted as a GoogleSearch list object .


def search_news(q, start=0, wait=10, asynchronous=False, cached=False):

    """ Returns a Google news query formatted as a GoogleSearch list object.
    """

    service = GOOGLE_NEWS
    return GoogleSearch(q, start, service, "", wait, asynchronous, cached)

def search_news ( q , start = 0 , wait = 10 , asynchronous = False , cached = False ) : service = GOOGLE_NEWS return GoogleSearch ( q , start , service , "" , wait , asynchronous , cached )

Returns a Google news query formatted as a GoogleSearch list object .


def search_blogs(q, start=0, wait=10, asynchronous=False, cached=False):

    """ Returns a Google blogs query formatted as a GoogleSearch list object.
    """

    service = GOOGLE_BLOGS
    return GoogleSearch(q, start, service, "", wait, asynchronous, cached)

def search_blogs ( q , start = 0 , wait = 10 , asynchronous = False , cached = False ) : service = GOOGLE_BLOGS return GoogleSearch ( q , start , service , "" , wait , asynchronous , cached )

Returns a Google blogs query formatted as a GoogleSearch list object .


def hash(self, id):

        """ Creates a unique filename in the cache for the id.
        """

        h = md5(id).hexdigest()
        return os.path.join(self.path, h+self.type)

def hash ( self , id ) : h = md5 ( id ) . hexdigest ( ) return os . path . join ( self . path , h + self . type )

Creates a unique filename in the cache for the id .


def age(self, id):

        """ Returns the age of the cache entry, in days.
        """

        path = self.hash(id)
        if os.path.exists(path):
            modified = datetime.datetime.fromtimestamp(os.stat(path)[8])
            age = datetime.datetime.today() - modified
            return age.days
        else:
            return 0

def age ( self , id ) : path = self . hash ( id ) if os . path . exists ( path ) : modified = datetime . datetime . fromtimestamp ( os . stat ( path ) [ 8 ] ) age = datetime . datetime . today ( ) - modified return age . days else : return 0

Returns the age of the cache entry in days .


def angle(x0, y0, x1, y1):
    """ Returns the angle between two points.
    """
    return degrees(atan2(y1-y0, x1-x0))


def distance(x0, y0, x1, y1):
    """ Returns the distance between two points.
    """
    return sqrt(pow(x1-x0, 2) + pow(y1-y0, 2))

def distance ( x0 , y0 , x1 , y1 ) : return sqrt ( pow ( x1 - x0 , 2 ) + pow ( y1 - y0 , 2 ) )

Returns the distance between two points .


def line_line_intersection(x1, y1, x2, y2, x3, y3, x4, y4, infinite=False):
    """ Determines the intersection point of two lines, or two finite line segments if infinite=False.
        When the lines do not intersect, returns an empty list.
    """
    # Based on: P. Bourke, http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
    ua = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
    ub = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
    d = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
    if d == 0:
        if ua == ub == 0:
            # The lines are coincident
            return []
        else:
            # The lines are parallel.
            return []
    ua /= float(d)
    ub /= float(d)
    if not infinite and not (0 <= ua <= 1 and 0 <= ub <= 1):
        # Intersection point is not within both line segments.
        return None, None
    return [(x1 + ua * (x2 - x1),
             y1 + ua * (y2 - y1))]

def line_line_intersection ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , infinite = False ) : ua = ( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 ) ub = ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 ) d = ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 ) if d == 0 : if ua == ub == 0 : return [ ] else : return [ ] ua /= float ( d ) ub /= float ( d ) if not infinite and not ( 0 <= ua <= 1 and 0 <= ub <= 1 ) : return None , None return [ ( x1 + ua * ( x2 - x1 ) , y1 + ua * ( y2 - y1 ) ) ]

Determines the intersection point of two lines or two finite line segments if infinite = False . When the lines do not intersect returns an empty list .


def circle_line_intersection(cx, cy, radius, x1, y1, x2, y2, infinite=False):
    """ Returns a list of points where the circle and the line intersect.
            Returns an empty list when the circle and the line do not intersect.
    """
    # Based on: http://www.vb-helper.com/howto_net_line_circle_intersections.html
    dx = x2 - x1
    dy = y2 - y1
    A = dx * dx + dy * dy
    B = 2 * (dx * (x1 - cx) + dy * (y1 - cy))
    C = pow(x1 - cx, 2) + pow(y1 - cy, 2) - radius * radius
    det = B * B - 4 * A * C
    if A <= 0.0000001 or det < 0:
        return []
    elif det == 0:
        # One point of intersection.
        t = -B / (2 * A)
        return [(x1 + t * dx, y1 + t * dy)]
    else:
        # Two points of intersection.
        # A point of intersection lies on the line segment if 0 <= t <= 1,
        # and on an extension of the segment otherwise.
        points = []
        det2 = sqrt(det)
        t1 = (-B + det2) / (2 * A)
        t2 = (-B - det2) / (2 * A)
        if infinite or 0 <= t1 <= 1:
            points.append((x1 + t1 * dx, y1 + t1 * dy))
        if infinite or 0 <= t2 <= 1:
            points.append((x1 + t2 * dx, y1 + t2 * dy))
        return points

def circle_line_intersection ( cx , cy , radius , x1 , y1 , x2 , y2 , infinite = False ) : dx = x2 - x1 dy = y2 - y1 A = dx * dx + dy * dy B = 2 * ( dx * ( x1 - cx ) + dy * ( y1 - cy ) ) C = pow ( x1 - cx , 2 ) + pow ( y1 - cy , 2 ) - radius * radius det = B * B - 4 * A * C if A <= 0.0000001 or det < 0 : return [ ] elif det == 0 : t = - B / ( 2 * A ) return [ ( x1 + t * dx , y1 + t * dy ) ] else : points = [ ] det2 = sqrt ( det ) t1 = ( - B + det2 ) / ( 2 * A ) t2 = ( - B - det2 ) / ( 2 * A ) if infinite or 0 <= t1 <= 1 : points . append ( ( x1 + t1 * dx , y1 + t1 * dy ) ) if infinite or 0 <= t2 <= 1 : points . append ( ( x1 + t2 * dx , y1 + t2 * dy ) ) return points

Returns a list of points where the circle and the line intersect . Returns an empty list when the circle and the line do not intersect .


def invert(self):
        """ Multiplying a matrix by its inverse produces the identity matrix.
        """
        m = self.matrix
        d = m[0] * m[4] - m[1] * m[3]
        self.matrix = [
             m[4] / d, -m[1] / d, 0,
             -m[3] / d,  m[0] / d, 0,
             (m[3] * m[7] - m[4] * m[6]) / d,
             -(m[0] * m[7] - m[1] * m[6]) / d,
             1
        ]

Multiplying a matrix by its inverse produces the identity matrix .


def transform_path(self, path):
        """ Returns a BezierPath object with the transformation applied.
        """
        p = path.__class__() # Create a new BezierPath.
        for pt in path:
            if pt.cmd == "close":
                p.closepath()
            elif pt.cmd == "moveto":
                p.moveto(*self.apply(pt.x, pt.y))
            elif pt.cmd == "lineto":
                p.lineto(*self.apply(pt.x, pt.y))
            elif pt.cmd == "curveto":
                vx1, vy1 = self.apply(pt.ctrl1.x, pt.ctrl1.y)
                vx2, vy2 = self.apply(pt.ctrl2.x, pt.ctrl2.y)
                x, y = self.apply(pt.x, pt.y)
                p.curveto(vx1, vy1, vx2, vy2, x, y)
        return p

def transform_path ( self , path ) : p = path . __class__ ( ) for pt in path : if pt . cmd == "close" : p . closepath ( ) elif pt . cmd == "moveto" : p . moveto ( * self . apply ( pt . x , pt . y ) ) elif pt . cmd == "lineto" : p . lineto ( * self . apply ( pt . x , pt . y ) ) elif pt . cmd == "curveto" : vx1 , vy1 = self . apply ( pt . ctrl1 . x , pt . ctrl1 . y ) vx2 , vy2 = self . apply ( pt . ctrl2 . x , pt . ctrl2 . y ) x , y = self . apply ( pt . x , pt . y ) p . curveto ( vx1 , vy1 , vx2 , vy2 , x , y ) return p

Returns a BezierPath object with the transformation applied .


def intersection(self, b):
        """ Returns bounds that encompass the intersection of the two.
            If there is no overlap between the two, None is returned.
        """
        if not self.intersects(b):
            return None
        mx, my = max(self.x, b.x), max(self.y, b.y)
        return Bounds(mx, my,
            min(self.x+self.width, b.x+b.width) - mx,
            min(self.y+self.height, b.y+b.height) - my)

def intersection ( self , b ) : if not self . intersects ( b ) : return None mx , my = max ( self . x , b . x ) , max ( self . y , b . y ) return Bounds ( mx , my , min ( self . x + self . width , b . x + b . width ) - mx , min ( self . y + self . height , b . y + b . height ) - my )

Returns bounds that encompass the intersection of the two . If there is no overlap between the two None is returned .


def union(self, b):
        """ Returns bounds that encompass the union of the two.
        """
        mx, my = min(self.x, b.x), min(self.y, b.y)
        return Bounds(mx, my,
            max(self.x+self.width, b.x+b.width) - mx,
            max(self.y+self.height, b.y+b.height) - my)

def union ( self , b ) : mx , my = min ( self . x , b . x ) , min ( self . y , b . y ) return Bounds ( mx , my , max ( self . x + self . width , b . x + b . width ) - mx , max ( self . y + self . height , b . y + b . height ) - my )

Returns bounds that encompass the union of the two .


def error(message):
    '''Prints an error message, the help message and quits'''
    global parser
    print (_("Error: ") + message)
    print ()
    parser.print_help()
    sys.exit()

def
error
(
message
)
:
global
parser
print
(
_
(
"Error: "
)
+
message
)
print
(
)
parser
.
print_help
(
)
sys
.
exit
(
)

Prints an error message the help message and quits


def textpath(self, txt, x, y, width=None, height=1000000, enableRendering=False, **kwargs):
        '''
        Draws an outlined path of the input text
        '''
        txt = self.Text(txt, x, y, width, height, **kwargs)
        path = txt.path
        if draw:
            path.draw()
        return path

def textpath ( self , txt , x , y , width = None , height = 1000000 , enableRendering = False , ** kwargs ) : txt = self . Text ( txt , x , y , width , height , ** kwargs ) path = txt . path if draw : path . draw ( ) return path


def draw_cornu_flat(x0, y0, t0, t1, s0, c0, flip, cs, ss, cmd):

    """ Raph Levien's code draws fast LINETO segments.
    """

    for j in range(0, 100):
        t = j * .01
        s, c = eval_cornu(t0 + t * (t1 - t0))
        s *= flip
        s -= s0
        c -= c0
        #print '%', c, s
        x = c * cs - s * ss
        y = s * cs + c * ss
        print_pt(x0 + x, y0 + y, cmd)
        cmd = 'lineto'
    return cmd

def draw_cornu_flat ( x0 , y0 , t0 , t1 , s0 , c0 , flip , cs , ss , cmd ) : for j in range ( 0 , 100 ) : t = j * .01 s , c = eval_cornu ( t0 + t * ( t1 - t0 ) ) s *= flip s -= s0 c -= c0 x = c * cs - s * ss y = s * cs + c * ss print_pt ( x0 + x , y0 + y , cmd ) cmd = 'lineto' return cmd

Raph Levien s code draws fast LINETO segments .


def draw_cornu_bezier(x0, y0, t0, t1, s0, c0, flip, cs, ss, cmd, scale, rot):

    """ Mark Meyer's code draws elegant CURVETO segments.
    """

    s = None
    for j in range(0, 5):
        # travel along the function two points at a time (at time t and t2)
        # the first time through we'll need to get both points
        # after that we only need the second point because the old second point
        # becomes the new first point
        t = j * .2
        t2 = t+ .2

        curvetime = t0 + t * (t1 - t0)
        curvetime2 = t0 + t2 * (t1 - t0)
        Dt = (curvetime2 - curvetime) * scale

        if not s:
            # get first point
            # avoid calling this again: the next time though x,y will equal x3, y3
            s, c = eval_cornu(curvetime)
            s *= flip
            s -= s0
            c -= c0
            # calculate derivative of fresnel function at point to get tangent slope
            # just take the integrand of the fresnel function
            dx1 =  cos(pow(curvetime, 2) + (flip * rot))
            dy1 =  flip * sin(pow(curvetime, 2) + (flip *rot))
            # x,y = first point on function
            x = ((c * cs - s * ss) +x0)
            y = ((s * cs + c * ss) + y0)

        #evaluate the fresnel further along the function to look ahead to the next point
        s2,c2 = eval_cornu(curvetime2)
        s2 *= flip
        s2 -= s0
        c2 -= c0

        dx2 = cos(pow(curvetime2, 2) + (flip * rot))
        dy2 = flip * sin(pow(curvetime2, 2) + (flip * rot))
        # x3, y3 = second point on function
        x3 = ((c2 * cs - s2 * ss)+x0)
        y3 = ((s2 * cs + c2 * ss)+y0)

        # calculate control points
        x1 = (x + ((Dt/3.0) * dx1))
        y1 = (y + ((Dt/3.0) * dy1))
        x2 = (x3 - ((Dt/3.0) * dx2))
        y2 = (y3 - ((Dt/3.0) * dy2))

        if cmd == 'moveto':
            print_pt(x, y, cmd)
            cmd = 'curveto'
        print_crv(x1, y1, x2, y2, x3, y3)

        dx1, dy1 = dx2, dy2
        x,y = x3, y3

    return cmd

def draw_cornu_bezier ( x0 , y0 , t0 , t1 , s0 , c0 , flip , cs , ss , cmd , scale , rot ) : s = None for j in range ( 0 , 5 ) : t = j * .2 t2 = t + .2 curvetime = t0 + t * ( t1 - t0 ) curvetime2 = t0 + t2 * ( t1 - t0 ) Dt = ( curvetime2 - curvetime ) * scale if not s : s , c = eval_cornu ( curvetime ) s *= flip s -= s0 c -= c0 dx1 = cos ( pow ( curvetime , 2 ) + ( flip * rot ) ) dy1 = flip * sin ( pow ( curvetime , 2 ) + ( flip * rot ) ) x = ( ( c * cs - s * ss ) + x0 ) y = ( ( s * cs + c * ss ) + y0 ) s2 , c2 = eval_cornu ( curvetime2 ) s2 *= flip s2 -= s0 c2 -= c0 dx2 = cos ( pow ( curvetime2 , 2 ) + ( flip * rot ) ) dy2 = flip * sin ( pow ( curvetime2 , 2 ) + ( flip * rot ) ) x3 = ( ( c2 * cs - s2 * ss ) + x0 ) y3 = ( ( s2 * cs + c2 * ss ) + y0 ) x1 = ( x + ( ( Dt / 3.0 ) * dx1 ) ) y1 = ( y + ( ( Dt / 3.0 ) * dy1 ) ) x2 = ( x3 - ( ( Dt / 3.0 ) * dx2 ) ) y2 = ( y3 - ( ( Dt / 3.0 ) * dy2 ) ) if cmd == 'moveto' : print_pt ( x , y , cmd ) cmd = 'curveto' print_crv ( x1 , y1 , x2 , y2 , x3 , y3 ) dx1 , dy1 = dx2 , dy2 x , y = x3 , y3 return cmd

Mark Meyer s code draws elegant CURVETO segments .


def search(q, start=1, count=10, context=None, wait=10, asynchronous=False, cached=False):

    """ Returns a Yahoo web query formatted as a YahooSearch list object.
    """

    service = YAHOO_SEARCH
    return YahooSearch(q, start, count, service, context, wait, asynchronous, cached)

def search ( q , start = 1 , count = 10 , context = None , wait = 10 , asynchronous = False , cached = False ) : service = YAHOO_SEARCH return YahooSearch ( q , start , count , service , context , wait , asynchronous , cached )

Returns a Yahoo web query formatted as a YahooSearch list object .


def search_images(q, start=1, count=10, wait=10, asynchronous=False, cached=False):

    """ Returns a Yahoo images query formatted as a YahooSearch list object.
    """

    service = YAHOO_IMAGES
    return YahooSearch(q, start, count, service, None, wait, asynchronous, cached)

def search_images ( q , start = 1 , count = 10 , wait = 10 , asynchronous = False , cached = False ) : service = YAHOO_IMAGES return YahooSearch ( q , start , count , service , None , wait , asynchronous , cached )

Returns a Yahoo images query formatted as a YahooSearch list object .


def search_news(q, start=1, count=10, wait=10, asynchronous=False, cached=False):

    """ Returns a Yahoo news query formatted as a YahooSearch list object.
    """

    service = YAHOO_NEWS
    return YahooSearch(q, start, count, service, None, wait, asynchronous, cached)

def search_news ( q , start = 1 , count = 10 , wait = 10 , asynchronous = False , cached = False ) : service = YAHOO_NEWS return YahooSearch ( q , start , count , service , None , wait , asynchronous , cached )

Returns a Yahoo news query formatted as a YahooSearch list object .


def suggest_spelling(q, wait=10, asynchronous=False, cached=False):

    """ Returns list of suggested spelling corrections for the given query.
    """

    return YahooSpelling(q, wait, asynchronous, cached)

def suggest_spelling ( q , wait = 10 , asynchronous = False , cached = False ) : return YahooSpelling ( q , wait , asynchronous , cached )

Returns list of suggested spelling corrections for the given query .


def layer(self, img, x=0, y=0, name=""):

        """Creates a new layer from file, Layer, PIL Image.

        If img is an image file or PIL Image object,
        Creates a new layer with the given image file.
        The image is positioned on the canvas at x, y.

        If img is a Layer,
        uses that layer's x and y position and name.

        """

        from types import StringType
        if isinstance(img, Image.Image):
            img = img.convert("RGBA")
            self.layers.append(Layer(self, img, x, y, name))
            return len(self.layers)-1
        if isinstance(img, Layer):
            img.canvas = self
            self.layers.append(img)
            return len(self.layers)-1
        if type(img) == StringType:
            img = Image.open(img)
            img = img.convert("RGBA")
            self.layers.append(Layer(self, img, x, y, name))
            return len(self.layers)-1

def layer ( self , img , x = 0 , y = 0 , name = "" ) : from types import StringType if isinstance ( img , Image . Image ) : img = img . convert ( "RGBA" ) self . layers . append ( Layer ( self , img , x , y , name ) ) return len ( self . layers ) - 1 if isinstance ( img , Layer ) : img . canvas = self self . layers . append ( img ) return len ( self . layers ) - 1 if type ( img ) == StringType : img = Image . open ( img ) img = img . convert ( "RGBA" ) self . layers . append ( Layer ( self , img , x , y , name ) ) return len ( self . layers ) - 1

Creates a new layer from file Layer PIL Image . If img is an image file or PIL Image object Creates a new layer with the given image file . The image is positioned on the canvas at x y . If img is a Layer uses that layer s x and y position and name .


def merge(self, layers):

        """Flattens the given layers on the canvas.

        Merges the given layers with the indices in the list
        on the bottom layer in the list.
        The other layers are discarded.

        """

        layers.sort()
        if layers[0] == 0: del layers[0]
        self.flatten(layers)

def merge ( self , layers ) : layers . sort ( ) if layers [ 0 ] == 0 : del layers [ 0 ] self . flatten ( layers )

Flattens the given layers on the canvas . Merges the given layers with the indices in the list on the bottom layer in the list . The other layers are discarded .


def export(self, filename):

        """Exports the flattened canvas.

        Flattens the canvas.
        PNG retains the alpha channel information.
        Other possibilities are JPEG and GIF.

        """

        self.flatten()
        self.layers[1].img.save(filename)
        return filename

def export ( self , filename ) : self . flatten ( ) self . layers [ 1 ] . img . save ( filename ) return filename

Exports the flattened canvas . Flattens the canvas . PNG retains the alpha channel information . Other possibilities are JPEG and GIF .


def delete(self):

        """Removes this layer from the canvas.

        """

        i = self.index()
        if i != None: del self.canvas.layers[i]

def delete ( self ) : i = self . index ( ) if i != None : del self . canvas . layers [ i ]


def up(self):

        """Moves the layer up in the stacking order.

        """

        i = self.index()
        if i != None:
            del self.canvas.layers[i]
            i = min(len(self.canvas.layers), i+1)
            self.canvas.layers.insert(i, self)

def up ( self ) : i = self . index ( ) if i != None : del self . canvas . layers [ i ] i = min ( len ( self . canvas . layers ) , i + 1 ) self . canvas . layers . insert ( i , self )

Moves the layer up in the stacking order .


def down(self):

        """Moves the layer down in the stacking order.

        """

        i = self.index()
        if i != None:
            del self.canvas.layers[i]
            i = max(0, i-1)
            self.canvas.layers.insert(i, self)

def down ( self ) : i = self . index ( ) if i != None : del self . canvas . layers [ i ] i = max ( 0 , i - 1 ) self . canvas . layers . insert ( i , self )

Moves the layer down in the stacking order .


def duplicate(self):

        """Creates a copy of the current layer.

        This copy becomes the top layer on the canvas.

        """

        i = self.canvas.layer(self.img.copy(), self.x, self.y, self.name)
        clone = self.canvas.layers[i]
        clone.alpha = self.alpha
        clone.blend = self.blend

def duplicate ( self ) : i = self . canvas . layer ( self . img . copy ( ) , self . x , self . y , self . name ) clone = self . canvas . layers [ i ] clone . alpha = self . alpha clone . blend = self . blend

Creates a copy of the current layer . This copy becomes the top layer on the canvas .


def brightness(self, value=1.0):

        """Increases or decreases the brightness in the layer.

        The given value is a percentage to increase
        or decrease the image brightness,
        for example 0.8 means brightness at 80%.

        """

        b = ImageEnhance.Brightness(self.img)
        self.img = b.enhance(value)

def brightness ( self , value = 1.0 ) : b = ImageEnhance . Brightness ( self . img ) self . img = b . enhance ( value )

Increases or decreases the brightness in the layer . The given value is a percentage to increase or decrease the image brightness for example 0 . 8 means brightness at 80% .


def contrast(self, value=1.0):

        """Increases or decreases the contrast in the layer.

        The given value is a percentage to increase
        or decrease the image contrast,
        for example 1.2 means contrast at 120%.

        """

        c = ImageEnhance.Contrast(self.img)
        self.img = c.enhance(value)

def contrast ( self , value = 1.0 ) : c = ImageEnhance . Contrast ( self . img ) self . img = c . enhance ( value )

Increases or decreases the contrast in the layer . The given value is a percentage to increase or decrease the image contrast for example 1 . 2 means contrast at 120% .


def desaturate(self):

        """Desaturates the layer, making it grayscale.

        Instantly removes all color information from the layer,
        while maintaing its alpha channel.

        """

        alpha = self.img.split()[3]
        self.img = self.img.convert("L")
        self.img = self.img.convert("RGBA")
        self.img.putalpha(alpha)

def desaturate ( self ) : alpha = self . img . split ( ) [ 3 ] self . img = self . img . convert ( "L" ) self . img = self . img . convert ( "RGBA" ) self . img . putalpha ( alpha )

Desaturates the layer making it grayscale . Instantly removes all color information from the layer while maintaing its alpha channel .


def invert(self):

        """Inverts the layer.

        """

        alpha = self.img.split()[3]
        self.img = self.img.convert("RGB")
        self.img = ImageOps.invert(self.img)
        self.img = self.img.convert("RGBA")
        self.img.putalpha(alpha)

def invert ( self ) : alpha = self . img . split ( ) [ 3 ] self . img = self . img . convert ( "RGB" ) self . img = ImageOps . invert ( self . img ) self . img = self . img . convert ( "RGBA" ) self . img . putalpha ( alpha )


def translate(self, x, y):

        """Positions the layer at the given coordinates.

        The x and y parameters define where to position
        the top left corner of the layer,
        measured from the top left of the canvas.

        """

        self.x = x
        self.y = y

def translate ( self , x , y ) : self . x = x self . y = y

Positions the layer at the given coordinates . The x and y parameters define where to position the top left corner of the layer measured from the top left of the canvas .


def scale(self, w=1.0, h=1.0):

        """Resizes the layer to the given width and height.

        When width w or height h is a floating-point number,
        scales percentual,
        otherwise scales to the given size in pixels.

        """

        from types import FloatType
        w0, h0 = self.img.size
        if type(w) == FloatType: w = int(w*w0)
        if type(h) == FloatType: h = int(h*h0)

        self.img = self.img.resize((w,h), INTERPOLATION)
        self.w = w
        self.h = h

def scale ( self , w = 1.0 , h = 1.0 ) : from types import FloatType w0 , h0 = self . img . size if type ( w ) == FloatType : w = int ( w * w0 ) if type ( h ) == FloatType : h = int ( h * h0 ) self . img = self . img . resize ( ( w , h ) , INTERPOLATION ) self . w = w self . h = h

Resizes the layer to the given width and height . When width w or height h is a floating - point number scales percentual otherwise scales to the given size in pixels .


def rotate(self, angle):

        """Rotates the layer.

        Rotates the layer by given angle.
        Positive numbers rotate counter-clockwise,
        negative numbers rotate clockwise.

        Rotate commands are executed instantly,
        so many subsequent rotates will distort the image.

        """

        #When a layer rotates, its corners will fall outside
        #of its defined width and height.
        #Thus, its bounding box needs to be expanded.

        #Calculate the diagonal width, and angle from the layer center.
        #This way we can use the layers's corners
        #to calculate the bounding box.

        from math import sqrt, pow, sin, cos, degrees, radians, asin
        w0, h0 = self.img.size
        d = sqrt(pow(w0,2) + pow(h0,2))
        d_angle = degrees(asin((w0*0.5) / (d*0.5)))

        angle = angle % 360
        if angle > 90 and angle <= 270: d_angle += 180

        w = sin(radians(d_angle + angle)) * d
        w = max(w, sin(radians(d_angle - angle)) * d)
        w = int(abs(w))

        h = cos(radians(d_angle + angle)) * d
        h = max(h, cos(radians(d_angle - angle)) * d)
        h = int(abs(h))

        dx = int((w-w0) / 2)
        dy = int((h-h0) / 2)
        d = int(d)

        #The rotation box's background color
        #is the mean pixel value of the rotating image.
        #This is the best option to avoid borders around
        #the rotated image.

        bg = ImageStat.Stat(self.img).mean
        bg = (int(bg[0]), int(bg[1]), int(bg[2]), 0)

        box = Image.new("RGBA", (d,d), bg)
        box.paste(self.img, ((d-w0)/2, (d-h0)/2))
        box = box.rotate(angle, INTERPOLATION)
        box = box.crop(((d-w)/2+2, (d-h)/2, d-(d-w)/2, d-(d-h)/2))
        self.img = box

        #Since rotate changes the bounding box size,
        #update the layers' width, height, and position,
        #so it rotates from the center.

        self.x += (self.w-w)/2
        self.y += (self.h-h)/2
        self.w = w
        self.h = h

def rotate ( self , angle ) : from math import sqrt , pow , sin , cos , degrees , radians , asin w0 , h0 = self . img . size d = sqrt ( pow ( w0 , 2 ) + pow ( h0 , 2 ) ) d_angle = degrees ( asin ( ( w0 * 0.5 ) / ( d * 0.5 ) ) ) angle = angle % 360 if angle > 90 and angle <= 270 : d_angle += 180 w = sin ( radians ( d_angle + angle ) ) * d w = max ( w , sin ( radians ( d_angle - angle ) ) * d ) w = int ( abs ( w ) ) h = cos ( radians ( d_angle + angle ) ) * d h = max ( h , cos ( radians ( d_angle - angle ) ) * d ) h = int ( abs ( h ) ) dx = int ( ( w - w0 ) / 2 ) dy = int ( ( h - h0 ) / 2 ) d = int ( d ) bg = ImageStat . Stat ( self . img ) . mean bg = ( int ( bg [ 0 ] ) , int ( bg [ 1 ] ) , int ( bg [ 2 ] ) , 0 ) box = Image . new ( "RGBA" , ( d , d ) , bg ) box . paste ( self . img , ( ( d - w0 ) / 2 , ( d - h0 ) / 2 ) ) box = box . rotate ( angle , INTERPOLATION ) box = box . crop ( ( ( d - w ) / 2 + 2 , ( d - h ) / 2 , d - ( d - w ) / 2 , d - ( d - h ) / 2 ) ) self . img = box self . x += ( self . w - w ) / 2 self . y += ( self . h - h ) / 2 self . w = w self . h = h

Rotates the layer . Rotates the layer by given angle . Positive numbers rotate counter - clockwise negative numbers rotate clockwise . Rotate commands are executed instantly so many subsequent rotates will distort the image .


def flip(self, axis=HORIZONTAL):

        """Flips the layer, either HORIZONTAL or VERTICAL.

        """

        if axis == HORIZONTAL:
            self.img = self.img.transpose(Image.FLIP_LEFT_RIGHT)
        if axis == VERTICAL:
            self.img = self.img.transpose(Image.FLIP_TOP_BOTTOM)

def flip ( self , axis = HORIZONTAL ) : if axis == HORIZONTAL : self . img = self . img . transpose ( Image . FLIP_LEFT_RIGHT ) if axis == VERTICAL : self . img = self . img . transpose ( Image . FLIP_TOP_BOTTOM )

Flips the layer either HORIZONTAL or VERTICAL .


def sharpen(self, value=1.0):

        """Increases or decreases the sharpness in the layer.

        The given value is a percentage to increase
        or decrease the image sharpness,
        for example 0.8 means sharpness at 80%.

        """

        s = ImageEnhance.Sharpness(self.img)
        self.img = s.enhance(value)

def sharpen ( self , value = 1.0 ) : s = ImageEnhance . Sharpness ( self . img ) self . img = s . enhance ( value )

Increases or decreases the sharpness in the layer . The given value is a percentage to increase or decrease the image sharpness for example 0 . 8 means sharpness at 80% .


def levels(self):

        """Returns a histogram for each RGBA channel.

        Returns a 4-tuple of lists, r, g, b, and a.
        Each list has 255 items, a count for each pixel value.

        """

        h = self.img.histogram()
        r = h[0:255]
        g = h[256:511]
        b = h[512:767]
        a = h[768:1024]

        return r, g, b, a

Returns a histogram for each RGBA channel . Returns a 4 - tuple of lists r g b and a . Each list has 255 items a count for each pixel value .


def hue(self, img1, img2):

        """Applies the hue blend mode.

        Hues image img1 with image img2.
        The hue filter replaces the hues of pixels in img1
        with the hues of pixels in img2.
        Returns a composite image with the alpha channel retained.

        """

        import colorsys

        p1 = list(img1.getdata())
        p2 = list(img2.getdata())
        for i in range(len(p1)):

            r1, g1, b1, a1 = p1[i]
            r1 = r1 / 255.0
            g1 = g1 / 255.0
            b1 = b1 / 255.0

            h1, s1, v1 = colorsys.rgb_to_hsv(r1, g1, b1)

            r2, g2, b2, a2 = p2[i]
            r2 = r2 / 255.0
            g2 = g2 / 255.0
            b2 = b2 / 255.0
            h2, s2, v2 = colorsys.rgb_to_hsv(r2, g2, b2)

            r3, g3, b3 = colorsys.hsv_to_rgb(h2, s1, v1)

            r3 = int(r3*255)
            g3 = int(g3*255)
            b3 = int(b3*255)
            p1[i] = (r3, g3, b3, a1)

        img = Image.new("RGBA", img1.size, 255)
        img.putdata(p1)
        return img

Applies the hue blend mode . Hues image img1 with image img2 . The hue filter replaces the hues of pixels in img1 with the hues of pixels in img2 . Returns a composite image with the alpha channel retained .


def _load_namespace(self, namespace, filename=None):
        """
        Initialise bot namespace with info in shoebot.data

        :param filename: Will be set to __file__ in the namespace
        """
        from shoebot import data
        for name in dir(data):
            namespace[name] = getattr(data, name)

        for name in dir(self):
            if name[0] != '_':
                namespace[name] = getattr(self, name)

        namespace['_ctx'] = self  # Used in older nodebox scripts.
        namespace['__file__'] = filename

def _load_namespace ( self , namespace , filename = None ) : from shoebot import data for name in dir ( data ) : namespace [ name ] = getattr ( data , name ) for name in dir ( self ) : if name [ 0 ] != '_' : namespace [ name ] = getattr ( self , name ) namespace [ '_ctx' ] = self namespace [ '__file__' ] = filename

Initialise bot namespace with info in shoebot . data


def _should_run(self, iteration, max_iterations):
        ''' Return False if bot should quit '''
        if iteration == 0:
            # First frame always runs
            return True
        if max_iterations:
            if iteration < max_iterations:
                return True
        elif max_iterations is None:
            if self._dynamic:
                return True
            else:
                return False
            return True
        if not self._dynamic:
            return False

        return False

def _should_run ( self , iteration , max_iterations ) : if iteration == 0 : return True if max_iterations : if iteration < max_iterations : return True elif max_iterations is None : if self . _dynamic : return True else : return False return True if not self . _dynamic : return False return False


def _frame_limit(self, start_time):
        """
        Limit to framerate, should be called after
        rendering has completed

        :param start_time: When execution started
        """
        if self._speed:
            completion_time = time()
            exc_time = completion_time - start_time
            sleep_for = (1.0 / abs(self._speed)) - exc_time
            if sleep_for > 0:
                sleep(sleep_for)

def _frame_limit ( self , start_time ) : if self . _speed : completion_time = time ( ) exc_time = completion_time - start_time sleep_for = ( 1.0 / abs ( self . _speed ) ) - exc_time if sleep_for > 0 : sleep ( sleep_for )

Limit to framerate should be called after rendering has completed


def _addvar(self, v):
        ''' Sets a new accessible variable.

        :param v: Variable.
        '''
        oldvar = self._oldvars.get(v.name)
        if oldvar is not None:
            if isinstance(oldvar, Variable):
                if oldvar.compliesTo(v):
                    v.value = oldvar.value
            else:
                # Set from commandline
                v.value = v.sanitize(oldvar)
        else:
            for listener in VarListener.listeners:
                listener.var_added(v)
        self._vars[v.name] = v
        self._namespace[v.name] = v.value
        self._oldvars[v.name] = v
        return v

def _addvar ( self , v ) : oldvar = self . _oldvars . get ( v . name ) if oldvar is not None : if isinstance ( oldvar , Variable ) : if oldvar . compliesTo ( v ) : v . value = oldvar . value else : v . value = v . sanitize ( oldvar ) else : for listener in VarListener . listeners : listener . var_added ( v ) self . _vars [ v . name ] = v self . _namespace [ v . name ] = v . value self . _oldvars [ v . name ] = v return v


def hex_to_rgb(hex):
    """ Returns RGB values for a hex color string.
    """
    hex = hex.lstrip("#")
    if len(hex) < 6:
        hex += hex[-1] * (6 - len(hex))
    if len(hex) == 6:
        r, g, b = hex[0:2], hex[2:4], hex[4:]
        r, g, b = [int(n, 16) / 255.0 for n in (r, g, b)]
        a = 1.0
    elif len(hex) == 8:
        r, g, b, a = hex[0:2], hex[2:4], hex[4:6], hex[6:]
        r, g, b, a = [int(n, 16) / 255.0 for n in (r, g, b, a)]
    return r, g, b, a

def hex_to_rgb ( hex ) : hex = hex . lstrip ( "#" ) if len ( hex ) < 6 : hex += hex [ - 1 ] * ( 6 - len ( hex ) ) if len ( hex ) == 6 : r , g , b = hex [ 0 : 2 ] , hex [ 2 : 4 ] , hex [ 4 : ] r , g , b = [ int ( n , 16 ) / 255.0 for n in ( r , g , b ) ] a = 1.0 elif len ( hex ) == 8 : r , g , b , a = hex [ 0 : 2 ] , hex [ 2 : 4 ] , hex [ 4 : 6 ] , hex [ 6 : ] r , g , b , a = [ int ( n , 16 ) / 255.0 for n in ( r , g , b , a ) ] return r , g , b , a

Returns RGB values for a hex color string .


def simple_traceback(ex, source):
    """
    Format traceback, showing line number and surrounding source.
    """
    exc_type, exc_value, exc_tb = sys.exc_info()
    exc = traceback.format_exception(exc_type, exc_value, exc_tb)

    source_arr = source.splitlines()

    # Defaults...
    exc_location = exc[-2]
    for i, err in enumerate(exc):
        if 'exec source in ns' in err:
            exc_location = exc[i + 1]
            break

    # extract line number from traceback
    fn = exc_location.split(',')[0][8:-1]
    line_number = int(exc_location.split(',')[1].replace('line', '').strip())

    # Build error messages

    err_msgs = []

    # code around the error
    err_where = ' '.join(exc[i - 1].split(',')[1:]).strip()  # 'line 37 in blah"
    err_msgs.append('Error in the Shoebot script at %s:' % err_where)
    for i in xrange(max(0, line_number - 5), line_number):
        if fn == "<string>":
            line = source_arr[i]
        else:
            line = linecache.getline(fn, i + 1)
        err_msgs.append('%s: %s' % (i + 1, line.rstrip()))
    err_msgs.append('  %s^ %s' % (len(str(i)) * ' ', exc[-1].rstrip()))

    err_msgs.append('')
    # traceback
    err_msgs.append(exc[0].rstrip())
    for err in exc[3:]:
        err_msgs.append(err.rstrip())

    return '\n'.join(err_msgs)

def
simple_traceback
(
ex
,
source
)
:
exc_type
,
exc_value
,
exc_tb
=
sys
.
exc_info
(
)
exc
=
traceback
.
format_exception
(
exc_type
,
exc_value
,
exc_tb
)
source_arr
=
source
.
splitlines
(
)
exc_location
=
exc
[
2
]
for
i
,
err
in
enumerate
(
exc
)
:
if
'exec source in ns'
in
err
:
exc_location
=
exc
[
i
+
1
]
break
fn
=
exc_location
.
split
(
','
)
[
0
]
[
8
:
1
]
line_number
=
int
(
exc_location
.
split
(
','
)
[
1
]
.
replace
(
'line'
,
''
)
.
strip
(
)
)
err_msgs
=
[
]
err_where
=
' '
.
join
(
exc
[
i
1
]
.
split
(
','
)
[
1
:
]
)
.
strip
(
)
err_msgs
.
append
(
'Error in the Shoebot script at %s:'
%
err_where
)
for
i
in
xrange
(
max
(
0
,
line_number
5
)
,
line_number
)
:
if
fn
==
"<string>"
:
line
=
source_arr
[
i
]
else
:
line
=
linecache
.
getline
(
fn
,
i
+
1
)
err_msgs
.
append
(
'%s: %s'
%
(
i
+
1
,
line
.
rstrip
(
)
)
)
err_msgs
.
append
(
'  %s^ %s'
%
(
len
(
str
(
i
)
)
*
' '
,
exc
[
1
]
.
rstrip
(
)
)
)
err_msgs
.
append
(
''
)
err_msgs
.
append
(
exc
[
0
]
.
rstrip
(
)
)
for
err
in
exc
[
3
:
]
:
err_msgs
.
append
(
err
.
rstrip
(
)
)
return
'\n'
.
join
(
err_msgs
)

Format traceback showing line number and surrounding source .


def create(self, name, overwrite=True):

        """Creates an SQLite database file.

        Creates an SQLite database with the given name.
        The .box file extension is added automatically.
        Overwrites any existing database by default.

        """

        self._name = name.rstrip(".db")
        from os import unlink
        if overwrite:
            try: unlink(self._name + ".db")
            except: pass
        self._con = sqlite.connect(self._name + ".db")
        self._cur = self._con.cursor()

def create ( self , name , overwrite = True ) : self . _name = name . rstrip ( ".db" ) from os import unlink if overwrite : try : unlink ( self . _name + ".db" ) except : pass self . _con = sqlite . connect ( self . _name + ".db" ) self . _cur = self . _con . cursor ( )

Creates an SQLite database file . Creates an SQLite database with the given name . The . box file extension is added automatically . Overwrites any existing database by default .


def create_table(self, name, fields=[], key="id"):

        """Creates a new table.

        Creates a table with the given name,
        containing the list of given fields.
        Since SQLite uses manifest typing, no data type need be supplied.
        The primary key is "id" by default,
        an integer that can be set or otherwise autoincrements.

        """

        for f in fields:
            if f == key: fields.remove(key)
        sql  = "create table "+name+" "
        sql += "("+key+" integer primary key"
        for f in fields: sql += ", "+f+" varchar(255)"
        sql += ")"
        self._cur.execute(sql)
        self._con.commit()
        self.index(name, key, unique=True)
        self.connect(self._name)

def
create_table
(
self
,
name
,
fields
=
[
]
,
key
=
"id"
)
:
for
f
in
fields
:
if
f
==
key
:
fields
.
remove
(
key
)
sql
=
"create table "
+
name
+
" "
sql
+=
"("
+
key
+
" integer primary key"
for
f
in
fields
:
sql
+=
", "
+
f
+
" varchar(255)"
sql
+=
")"
self
.
_cur
.
execute
(
sql
)
self
.
_con
.
commit
(
)
self
.
index
(
name
,
key
,
unique
=
True
)
self
.
connect
(
self
.
_name
)

Creates a new table . Creates a table with the given name containing the list of given fields . Since SQLite uses manifest typing no data type need be supplied . The primary key is id by default an integer that can be set or otherwise autoincrements .


def create_index(self, table, field, unique=False, ascending=True):

        """Creates a table index.

        Creates an index on the given table,
        on the given field with unique values enforced or not,
        in ascending or descending order.

        """

        if unique: u = "unique "
        else: u = ""
        if ascending: a = "asc"
        else: a = "desc"
        sql  = "create "+u+"index index_"+table+"_"+field+" "
        sql += "on "+table+"("+field+" "+a+")"
        self._cur.execute(sql)
        self._con.commit()

def
create_index
(
self
,
table
,
field
,
unique
=
False
,
ascending
=
True
)
:
if
unique
:
u
=
"unique "
else
:
u
=
""
if
ascending
:
a
=
"asc"
else
:
a
=
"desc"
sql
=
"create "
+
u
+
"index index_"
+
table
+
"_"
+
field
+
" "
sql
+=
"on "
+
table
+
"("
+
field
+
" "
+
a
+
")"
self
.
_cur
.
execute
(
sql
)
self
.
_con
.
commit
(
)

Creates a table index . Creates an index on the given table on the given field with unique values enforced or not in ascending or descending order .


def close(self):

        """Commits any pending transactions and closes the database.
        """

        self._con.commit()
        self._cur.close()
        self._con.close()

def close ( self ) : self . _con . commit ( ) self . _cur . close ( ) self . _con . close ( )

Commits any pending transactions and closes the database .


def sql(self, sql):

        """ Executes a raw SQL statement on the database.
        """

        self._cur.execute(sql)
        if sql.lower().find("select") >= 0:
            matches = []
            for r in self._cur: matches.append(r)
            return matches

def sql ( self , sql ) : self . _cur . execute ( sql ) if sql . lower ( ) . find ( "select" ) >= 0 : matches = [ ] for r in self . _cur : matches . append ( r ) return matches

Executes a raw SQL statement on the database .


def edit(self, id, *args, **kw):

        """ Edits the row with given id.
        """

        if args and kw:
            return
        if args and type(args[0]) == dict:
            fields = [k for k in args[0]]
            v = [args[0][k] for k in args[0]]
        if kw:
            fields = [k for k in kw]
            v = [kw[k] for k in kw]

        sql  = "update "+self._name+" set "+"=?, ".join(fields)+"=? where "+self._key+"="+unicode(id)
        self._db._cur.execute(sql, v)
        self._db._i += 1
        if self._db._i >= self._db._commit:
            self._db._i = 0
            self._db._con.commit()

def
edit
(
self
,
id
,
*
args
,
**
kw
)
:
if
args
and
kw
:
return
if
args
and
type
(
args
[
0
]
)
==
dict
:
fields
=
[
k
for
k
in
args
[
0
]
]
v
=
[
args
[
0
]
[
k
]
for
k
in
args
[
0
]
]
if
kw
:
fields
=
[
k
for
k
in
kw
]
v
=
[
kw
[
k
]
for
k
in
kw
]
sql
=
"update "
+
self
.
_name
+
" set "
+
"=?, "
.
join
(
fields
)
+
"=? where "
+
self
.
_key
+
"="
+
unicode
(
id
)
self
.
_db
.
_cur
.
execute
(
sql
,
v
)
self
.
_db
.
_i
+=
1
if
self
.
_db
.
_i
>=
self
.
_db
.
_commit
:
self
.
_db
.
_i
=
0
self
.
_db
.
_con
.
commit
(
)


def remove(self, id, operator="=", key=None):

        """ Deletes the row with given id.
        """

        if key == None: key = self._key
        try: id = unicode(id)
        except: pass
        sql = "delete from "+self._name+" where "+key+" "+operator+" ?"
        self._db._cur.execute(sql, (id,))

def
remove
(
self
,
id
,
operator
=
"="
,
key
=
)
:
if
key
==
:
key
=
self
.
_key
try
:
id
=
unicode
(
id
)
except
:
pass
sql
=
"delete from "
+
self
.
_name
+
" where "
+
key
+
" "
+
operator
+
" ?"
self
.
_db
.
_cur
.
execute
(
sql
,
(
id
,
)
)


def next_event(block=False, timeout=None):
    """
    Get the next available event or None

    :param block:
    :param timeout:
    :return: None or (event, data)
    """
    try:
        return channel.listen(block=block, timeout=timeout).next()['data']
    except StopIteration:
        return None

def next_event ( block = False , timeout = None ) : try : return channel . listen ( block = block , timeout = timeout ) . next ( ) [ 'data' ] except StopIteration : return None


def publish_event(event_t, data=None, extra_channels=None, wait=None):
    """
    Publish an event ot any subscribers.

    :param event_t:  event type
    :param data:     event data
    :param extra_channels:
    :param wait:
    :return:
    """
    event = Event(event_t, data)
    pubsub.publish("shoebot", event)
    for channel_name in extra_channels or []:
        pubsub.publish(channel_name, event)
    if wait is not None:
        channel = pubsub.subscribe(wait)
        channel.listen(wait)

def publish_event ( event_t , data = None , extra_channels = None , wait = None ) : event = Event ( event_t , data ) pubsub . publish ( "shoebot" , event ) for channel_name in extra_channels or [ ] : pubsub . publish ( channel_name , event ) if wait is not None : channel = pubsub . subscribe ( wait ) channel . listen ( wait )


def _set_mode(self, mode):
        '''
        Sets call_transform_mode to point to the
        center_transform or corner_transform
        '''
        if mode == CENTER:
            self._call_transform_mode = self._center_transform
        elif mode == CORNER:
            self._call_transform_mode = self._corner_transform
        else:
            raise ValueError('mode must be CENTER or CORNER')

def
_set_mode
(
self
,
mode
)
:
if
mode
==
CENTER
:
self
.
_call_transform_mode
=
self
.
_center_transform
elif
mode
==
CORNER
:
self
.
_call_transform_mode
=
self
.
_corner_transform
else
:
raise
ValueError
(
'mode must be CENTER or CORNER'
)


def inheritFromContext(self, ignore=()):
        """
        Doesn't store exactly the same items as Nodebox for ease of implementation,
        it has enough to get the Nodebox Dentrite example working.
        """
        for canvas_attr, grob_attr in STATES.items():
            if canvas_attr in ignore:
                continue
            setattr(self, grob_attr, getattr(self._bot._canvas, canvas_attr))

def inheritFromContext ( self , ignore = ( ) ) : for canvas_attr , grob_attr in STATES . items ( ) : if canvas_attr in ignore : continue setattr ( self , grob_attr , getattr ( self . _bot . _canvas , canvas_attr ) )

Doesn t store exactly the same items as Nodebox for ease of implementation it has enough to get the Nodebox Dentrite example working .


def load_edited_source(self, source, good_cb=None, bad_cb=None, filename=None):
        """
        Load changed code into the execution environment.

        Until the code is executed correctly, it will be
        in the 'tenuous' state.
        """
        with LiveExecution.lock:
            self.good_cb = good_cb
            self.bad_cb = bad_cb
            try:
                # text compile
                compile(source + '\n\n', filename or self.filename, "exec")
                self.edited_source = source
            except Exception as e:
                if bad_cb:
                    self.edited_source = None
                    tb = traceback.format_exc()
                    self.call_bad_cb(tb)
                return
            if filename is not None:
                self.filename = filename

def load_edited_source ( self , source , good_cb = None , bad_cb = None , filename = None ) : with LiveExecution . lock : self . good_cb = good_cb self . bad_cb = bad_cb try : compile ( source + '\n\n' , filename or self . filename , "exec" ) self . edited_source = source except Exception as e : if bad_cb : self . edited_source = None tb = traceback . format_exc ( ) self . call_bad_cb ( tb ) return if filename is not None : self . filename = filename

Load changed code into the execution environment .


def reload_functions(self):
        """
        Replace functions in namespace with functions from edited_source.
        """
        with LiveExecution.lock:
            if self.edited_source:
                tree = ast.parse(self.edited_source)
                for f in [n for n in ast.walk(tree) if isinstance(n, ast.FunctionDef)]:
                    self.ns[f.name].__code__ = meta.decompiler.compile_func(f, self.filename, self.ns).__code__

def reload_functions ( self ) : with LiveExecution . lock : if self . edited_source : tree = ast . parse ( self . edited_source ) for f in [ n for n in ast . walk ( tree ) if isinstance ( n , ast . FunctionDef ) ] : self . ns [ f . name ] . __code__ = meta . decompiler . compile_func ( f , self . filename , self . ns ) . __code__

Replace functions in namespace with functions from edited_source .


def run_tenuous(self):
        """
        Run edited source, if no exceptions occur then it
        graduates to known good.
        """
        with LiveExecution.lock:
            ns_snapshot = copy.copy(self.ns)
            try:
                source = self.edited_source
                self.edited_source = None
                self.do_exec(source, ns_snapshot)
                self.known_good = source
                self.call_good_cb()
                return True, None
            except Exception as ex:
                tb = traceback.format_exc()
                self.call_bad_cb(tb)
                self.ns.clear()
                self.ns.update(ns_snapshot)
                return False, ex

def run_tenuous ( self ) : with LiveExecution . lock : ns_snapshot = copy . copy ( self . ns ) try : source = self . edited_source self . edited_source = None self . do_exec ( source , ns_snapshot ) self . known_good = source self . call_good_cb ( ) return True , None except Exception as ex : tb = traceback . format_exc ( ) self . call_bad_cb ( tb ) self . ns . clear ( ) self . ns . update ( ns_snapshot ) return False , ex

Run edited source if no exceptions occur then it graduates to known good .


def run(self):
        """
        Attempt to known good or tenuous source.
        """
        with LiveExecution.lock:
            if self.edited_source:
                success, ex = self.run_tenuous()
                if success:
                    return

            self.do_exec(self.known_good, self.ns)

def run ( self ) : with LiveExecution . lock : if self . edited_source : success , ex = self . run_tenuous ( ) if success : return self . do_exec ( self . known_good , self . ns )

Attempt to known good or tenuous source .


def run_context(self):
        """
        Context in which the user can run the source in a custom manner.

        If no exceptions occur then the source will move from 'tenuous'
        to 'known good'.

        >>> with run_context() as (known_good, source, ns):
        >>> ...  exec source in ns
        >>> ...  ns['draw']()

        """
        with LiveExecution.lock:
            if self.edited_source is None:
                yield True, self.known_good, self.ns
                return

            ns_snapshot = copy.copy(self.ns)
            try:
                yield False, self.edited_source, self.ns
                self.known_good = self.edited_source
                self.edited_source = None
                self.call_good_cb()
                return
            except Exception as ex:
                tb = traceback.format_exc()
                self.call_bad_cb(tb)
                self.edited_source = None
                self.ns.clear()
                self.ns.update(ns_snapshot)

def run_context ( self ) : with LiveExecution . lock : if self . edited_source is None : yield True , self . known_good , self . ns return ns_snapshot = copy . copy ( self . ns ) try : yield False , self . edited_source , self . ns self . known_good = self . edited_source self . edited_source = None self . call_good_cb ( ) return except Exception as ex : tb = traceback . format_exc ( ) self . call_bad_cb ( tb ) self . edited_source = None self . ns . clear ( ) self . ns . update ( ns_snapshot )

Context in which the user can run the source in a custom manner .


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

def separation ( self , r = 10 ) : 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

Boids keep a small distance from other boids . Ensures that boids don t collide into each other in a smoothly accelerated motion .


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

def alignment ( self , d = 5 ) : 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


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

def limit ( self , max = 30 ) : 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

The speed limit for a boid . Boids can momentarily go very fast something that is impossible for real animals .


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

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

Returns the angle towards which the boid is steering .


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

def goal ( self , x , y , z , d = 50.0 ) : return ( x - self . x ) / d , ( y - self . y ) / d , ( z - self . z ) / d


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()

def update ( self , shuffled = True , cohesion = 100 , separation = 10 , alignment = 5 , goal = 20 , limit = 30 ) : from random import shuffle if shuffled : shuffle ( self ) m1 = 1.0 m2 = 1.0 m3 = 1.0 m4 = 1.0 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 if not self . has_goal : m4 = 0 if self . flee : m4 = - m4 for b in self : 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 ( )

Calculates the next motion frame for the flock .


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

def iterscan ( self , string , idx = 0 , context = None ) : 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 : matchend = next_pos match = self . scanner . scanner ( string , matchend ) . match yield rval , matchend lastend = matchend


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

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

Returns a copy of the layout for the given graph .


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
            )

def can_reach ( self , node , traversable = lambda node , edge : True ) : 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 )

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


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

def clear ( self ) : dict . clear ( self ) self . nodes = [ ] self . edges = [ ] self . root = None self . layout . i = 0 self . alpha = 0

Remove nodes and edges and reset the layout .


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

def add_node ( self , id , radius = 8 , style = style . DEFAULT , category = "" , label = None , root = False , properties = { } ) : 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

Add node from id and return the node object .


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)

def remove_node ( self , id ) : if self . has_key ( id ) : n = self [ id ] self . nodes . remove ( n ) del self [ id ] 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 )


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)

def remove_edge ( self , id1 , id2 ) : 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 )

Remove edges between nodes with given id s .


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

def edge ( self , id1 , id2 ) : if id1 in self and id2 in self and self [ id2 ] in self [ id1 ] . links : return self [ id1 ] . links . edge ( id2 ) return None

Returns the edge between the nodes with given id1 and id2 .


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

def update ( self , iterations = 10 ) : self . alpha += 0.05 self . alpha = min ( self . alpha , 1.0 ) 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 ( ) 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

Iterates the graph layout and updates node positions .


def offset(self, node):
        """ Returns the distance from the center to the given node.
        """
        x = self.x + node.x - _ctx.WIDTH/2
        y = self.y + node.y - _ctx.HEIGHT/2
        return x, y

def offset ( self , node ) : x = self . x + node . x - _ctx . WIDTH / 2 y = self . y + node . y - _ctx . HEIGHT / 2 return x , y

Returns the distance from the center to the given node .


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()

def draw ( self , dx = 0 , dy = 0 , weighted = False , directed = False , highlight = [ ] , traffic = None ) : self . update ( ) s = self . styles . default s . graph_background ( s ) _ctx . push ( ) _ctx . translate ( self . x + dx , self . y + dy ) 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 ) s = self . styles . default if s . edges : s . edges ( s , self . edges , self . alpha , weighted , directed ) 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 ) try : s = self . styles . highlight except : s = self . styles . default if s . path : s . path ( s , self , highlight ) 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 ) _ctx . pop ( )

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 .


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)

def prune ( self , depth = 0 ) : for n in list ( self . nodes ) : if len ( n . links ) <= depth : self . remove_node ( n . id )

Removes all nodes with less or equal links than depth .


def betweenness_centrality(self, normalized=True):
        """ Calculates betweenness centrality and returns an node id -> weight dictionary.
        Node betweenness weights are updated in the process.
        """
        bc = proximity.brandes_betweenness_centrality(self, normalized)
        for id, w in bc.iteritems(): self[id]._betweenness = w
        return bc

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

Calculates betweenness centrality and returns an node id - > weight dictionary . Node betweenness weights are updated in the process .


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

def eigenvector_centrality ( self , normalized = True , reversed = True , rating = { } , start = None , iterations = 100 , tolerance = 0.0001 ) : ec = proximity . eigenvector_centrality ( self , normalized , reversed , rating , start , iterations , tolerance ) for id , w in ec . iteritems ( ) : self [ id ] . _eigenvalue = w return ec

Calculates eigenvector centrality and returns an node id - > weight dictionary . Node eigenvalue weights are updated in the process .


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]

def nodes_by_betweenness ( self , treshold = 0.0 ) : nodes = [ ( n . betweenness , n ) for n in self . nodes if n . betweenness > treshold ] nodes . sort ( ) nodes . reverse ( ) return [ n for w , n in nodes ]

Returns nodes sorted by betweenness centrality . Nodes with a lot of passing traffic will be at the front of the list .


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

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 ]

Returns nodes sorted by eigenvector centrality . Nodes with a lot of incoming traffic will be at the front of the list


def nodes_by_category(self, category):
        """ Returns nodes with the given category attribute.
        """
        return [n for n in self.nodes if n.category == category]

def nodes_by_category ( self , category ) : return [ n for n in self . nodes if n . category == category ]

Returns nodes with the given category attribute .


def crown(self, depth=2):
        """ Returns a list of leaves, nodes connected to leaves, etc.
        """
        nodes = []
        for node in self.leaves: nodes += node.flatten(depth-1)
        return cluster.unique(nodes)

def crown ( self , depth = 2 ) : nodes = [ ] for node in self . leaves : nodes += node . flatten ( depth - 1 ) return cluster . unique ( nodes )

Returns a list of leaves nodes connected to leaves etc .


def _density(self):
        """ The number of edges in relation to the total number of possible edges.
        """
        return 2.0*len(self.edges) / (len(self.nodes) * (len(self.nodes)-1))

def _density ( self ) : return 2.0 * len ( self . edges ) / ( len ( self . nodes ) * ( len ( self . nodes ) - 1 ) )

The number of edges in relation to the total number of possible edges .