Back to index

python-biopython  1.60
__init__.py
Go to the documentation of this file.
00001 # Copyright 2001 by Tarjei Mikkelsen.  All rights reserved.
00002 # This code is part of the Biopython distribution and governed by its
00003 # license.  Please see the LICENSE file that should have been included
00004 # as part of this package.
00005 
00006 """BioPython Pathway module.
00007 
00008 Bio.Pathway is a lightweight class library designed to support the following tasks:
00009 
00010  - Data interchange and preprocessing between pathway databases and analysis software. 
00011  - Quick prototyping of pathway analysis algorithms
00012 
00013 The basic object in the Bio.Pathway model is Interaction, which represents an arbitrary
00014 interaction between any number of biochemical species.
00015 
00016 Network objects are used to represent the connectivity between species in pathways
00017 and reaction networks.
00018 
00019 For applications where it is not neccessary to explicitly represent network connectivity,
00020 the specialized classes Reaction and System should be used in place of Interacton and
00021 Network.
00022 
00023 The Bio.Pathway classes, especially Interaction, are intentionally
00024 desgined to be very flexible. Their intended use are as wrappers around database
00025 specific records, such as BIND objects. The value-added in this module is a
00026 framework for representing collections of reactions in a way that supports
00027 graph theoretic and numeric analysis.
00028 
00029 Note: This module should be regarded as a prototype only. API changes are likely.
00030       Comments and feature requests are most welcome.
00031 """
00032 
00033 from Bio.Pathway.Rep.MultiGraph import *
00034 
00035 
00036 class Reaction(object):
00037     """Abstraction for a biochemical transformation.
00038 
00039     This class represents a (potentially reversible) biochemical
00040     transformation of the type:
00041 
00042       a S1 + b S2 + ... --> c P1 + d P2 + ...
00043 
00044     where
00045     - a, b, c, d ... are positive numeric stochiometric coefficients,
00046     - S1, S2, ... are substrates
00047     - P1, P2, ... are products
00048 
00049     A Reaction should be viewed as the net result of one or more individual
00050     reaction steps, where each step is potentially facilitated by a different
00051     catalyst. Support for 'Reaction algebra' will be added at some point in
00052     the future.
00053 
00054     Attributes:
00055 
00056     reactants   -- map of involved species to their stochiometric coefficients:
00057                      reactants[S] = stochiometric constant for S
00058     catalysts   -- list of tuples of catalysts required for this reaction
00059     reversible  -- true iff reaction is reversible
00060     data        -- reference to arbitrary additional data
00061 
00062     Invariants:
00063 
00064     for all S in reactants: reactants[S] != 0
00065     for all C in catalysts: catalysts[C] != 0
00066 
00067     """
00068     
00069     def __init__(self, reactants = {}, catalysts = [],
00070                  reversible = 0, data = None):
00071         """Initializes a new Reaction object."""
00072         # enforce invariants on reactants:
00073         self.reactants = reactants.copy()
00074         # loop over original, edit the copy
00075         for r, value in reactants.iteritems():
00076             if value == 0:
00077                 del self.reactants[r]
00078         self.catalysts  = sorted(set(catalysts))
00079         self.data       = data
00080         self.reversible = reversible
00081 
00082     def __eq__(self, r):
00083         """Returns true iff self is equal to r."""
00084         return isinstance(r, Reaction) and \
00085                self.reactants == r.reactants and \
00086                self.catalysts == r.catalysts and \
00087                self.data == r.data and \
00088                self.reversible == r.reversible
00089         
00090     def __ne__(self, r):
00091         """Returns true iff self is not equal to r."""
00092         return not self.__eq__(r)
00093 
00094     def __hash__(self):
00095         """Returns a hashcode for self."""
00096         t = tuple(self.species())
00097         return hash(t)
00098 
00099     def __repr__(self):
00100         """Returns a debugging string representation of self."""
00101         return "Reaction(" + \
00102                ",".join(map(repr,[self.reactants,
00103                                   self.catalysts,
00104                                   self.data,
00105                                   self.reversible])) + ")"
00106 
00107     def __str__(self):
00108         """Returns a string representation of self."""
00109         substrates = ""
00110         products   = ""
00111         all_species = sorted(self.reactants)
00112         for species in all_species:
00113             stoch = self.reactants[species]
00114             if stoch < 0:
00115                 # species is a substrate:
00116                 if substrates != "":
00117                     substrates = substrates + " + "
00118                 if stoch != -1:
00119                     substrates = substrates + str(abs(stoch)) + " "
00120                 substrates = substrates + str(species)
00121             elif stoch > 0:
00122                 # species is a product:
00123                 if products != "":
00124                     products = products + " + "
00125                 if stoch != 1:
00126                     products = products + str(stoch) + " "
00127                 products = products + str(species)
00128             else:
00129                 raise AttributeError("Invalid 0 coefficient in Reaction.reactants")
00130         if self.reversible:
00131             return substrates + " <=> " + products
00132         else:
00133             return substrates + " --> " + products
00134 
00135     def reverse(self):
00136         """Returns a new Reaction that is the reverse of self."""
00137         reactants = {}
00138         for r in self.reactants:
00139             reactants[r] = - self.reactants[r]
00140         return Reaction(reactants, self.catalysts,
00141                         self.reversible, self.data)
00142 
00143     def species(self):
00144         """Returns a list of all Species involved in self."""
00145         return self.reactants.keys()
00146 
00147 
00148 class System(object):
00149     """Abstraction for a collection of reactions.
00150 
00151     This class is used in the Bio.Pathway framework to represent an arbitrary
00152     collection of reactions without explicitly defined links.
00153 
00154     Attributes:
00155 
00156     None    
00157     """
00158     
00159     def __init__(self, reactions = []):
00160         """Initializes a new System object."""
00161         self.__reactions = set(reactions)
00162 
00163     def __repr__(self):
00164         """Returns a debugging string representation of self."""
00165         return "System(" + ",".join(map(repr,self.__reactions)) + ")"
00166     
00167     def __str__(self):
00168         """Returns a string representation of self."""
00169         return "System of " + str(len(self.__reactions)) + \
00170                " reactions involving " + str(len(self.species())) + \
00171                " species"
00172 
00173     def add_reaction(self, reaction):
00174         """Adds reaction to self."""
00175         self.__reactions.add(reaction)
00176 
00177     def remove_reaction(self, reaction):
00178         """Removes reaction from self."""
00179         self.__reactions.remove(reaction)
00180 
00181     def reactions(self):
00182         """Returns a list of the reactions in this system.
00183         
00184         Note the order is arbitrary!
00185         """
00186         #TODO - Define __lt__ so that Reactions can be sorted on Python?
00187         return list(self.__reactions)
00188 
00189     def species(self):
00190         """Returns a list of the species in this system."""
00191         return sorted(set(reduce(lambda s,x: s + x,
00192                           [x.species() for x in self.reactions()], [])))
00193 
00194     def stochiometry(self):
00195         """Computes the stoichiometry matrix for self.
00196 
00197         Returns (species, reactions, stoch) where
00198 
00199             species    = ordered list of species in this system
00200             reactions  = ordered list of reactions in this system
00201             stoch      = 2D array where stoch[i][j] is coef of the
00202                          jth species in the ith reaction, as defined
00203                          by species and reactions above
00204         """
00205         # Note: This an inefficient and ugly temporary implementation.
00206         #       To be practical, stochiometric matrices should probably
00207         #       be implemented by sparse matrices, which would require
00208         #       NumPy dependencies.
00209         #
00210         # PS: We should implement automatic checking for NumPy here.
00211         species = self.species()
00212         reactions = self.reactions()
00213         stoch = [] * len(reactions)
00214         for i in range(len(reactions)):
00215             stoch[i] = 0 * len(species)
00216             for s in reactions[i].species():
00217                 stoch[species.index(s)] = reactions[i].reactants[s]
00218         return (species, reactions, stoch)
00219 
00220 
00221 class Interaction(object):
00222     """An arbitrary interaction between any number of species.
00223 
00224     This class definition is inteded solely as a minimal wrapper interface that should
00225     be implemented and extended by more specific abstractions.
00226 
00227     Attributes:
00228 
00229     data      -- reference to arbitrary additional data
00230     """
00231 
00232     def __init_(self, data):
00233         self.data = data
00234 
00235     def __hash__(self):
00236         """Returns a hashcode for self."""
00237         return hash(self.data)
00238 
00239     def __repr__(self):
00240         """Returns a debugging string representation of self.""" 
00241         return "Interaction(" + repr(self.data) + ")"
00242 
00243     def __str__(self):
00244         """Returns a string representation of self."""
00245         return "<" + str(self.data) + ">"
00246     
00247 
00248 class Network(object):
00249     """A set of species that are explicitly linked by interactions.
00250 
00251     The network is a directed multigraph with labeled edges. The nodes in the graph
00252     are the biochemical species involved. The edges represent an interaction between
00253     two species, and the edge label is a reference to the associated Interaction
00254     object.
00255 
00256     Attributes:
00257 
00258     None
00259     
00260     """
00261 
00262     def __init__(self, species = []):
00263         """Initializes a new Network object."""
00264         self.__graph = MultiGraph(species)
00265 
00266     def __repr__(self):
00267         """Returns a debugging string representation of this network."""
00268         return "<Network: __graph: " + repr(self.__graph) + ">"
00269 
00270     def __str__(self):
00271         """Returns a string representation of this network."""
00272         return "Network of " + str(len(self.species())) + " species and " + \
00273                str(len(self.interactions())) + " interactions."
00274 
00275     def add_species(self, species):
00276         """Adds species to this network."""
00277         self.__graph.add_node(species)
00278 
00279     def add_interaction(self, source, sink, interaction):
00280         """Adds interaction to this network."""
00281         self.__graph.add_edge(source, sink, interaction)
00282 
00283     def source(self, species):
00284         """Returns list of unique sources for species."""
00285         return self.__graph.parents(species)
00286 
00287     def source_interactions(self, species):
00288         """Returns list of (source, interaction) pairs for species."""
00289         return self.__graph.parent_edges(species)
00290 
00291     def sink(self, species):
00292         """Returns list of unique sinks for species."""
00293         return self.__graph.children(species)
00294 
00295     def sink_interactions(self, species):
00296         """Returns list of (sink, interaction) pairs for species."""
00297         return self.__graph.child_edges(species)
00298 
00299     def species(self):
00300         """Returns list of the species in this network."""
00301         return self.__graph.nodes()
00302 
00303     def interactions(self):
00304         """Returns list of the unique interactions in this network."""
00305         return self.__graph.labels()
00306 
00307 
00308 
00309 
00310