Back to index

python-biopython  1.60
DisplayRepresentation.py
Go to the documentation of this file.
00001 """Represent information for graphical display.
00002 
00003 Classes in this module are designed to hold information in a way that
00004 makes it easy to draw graphical figures.
00005 """
00006 # reportlab
00007 from reportlab.lib import colors
00008 
00009 # local stuff
00010 from Bio.Graphics.BasicChromosome import ChromosomeSegment
00011 from Bio.Graphics.BasicChromosome import TelomereSegment
00012 
00013 # --- constants
00014 # This is a default color scheme based on the light spectrum.
00015 # Based on my vague recollections from biology, this is our friend ROY G. BIV
00016 RAINBOW_COLORS = {(1, 1)  : colors.violet,
00017                   (2, 2)  : colors.indigo,
00018                   (3, 3)  : colors.blue,
00019                   (4, 4)  : colors.green,
00020                   (5, 5)  : colors.yellow,
00021                   (6, 6)  : colors.orange,
00022                   (7, 20) : colors.red}
00023 
00024 class ChromosomeCounts(object):
00025     """Represent a chromosome with count information.
00026 
00027     This is used to display information about counts along a chromosome.
00028     The segments are expected to have different count information, which
00029     will be displayed using a color scheme.
00030 
00031     I envision using this class when you think that certain regions of
00032     the chromosome will be especially abundant in the counts, and you
00033     want to pick those out.
00034     """
00035     def __init__(self, segment_names, color_scheme = RAINBOW_COLORS):
00036         """Initialize a representation of chromosome counts.
00037 
00038         Arguments:
00039 
00040         o segment_names - An ordered list of all segment names along
00041         the chromosome. The count and other information will be added to
00042         these.
00043 
00044         o color_scheme - A coloring scheme to use in the counts. This should
00045         be a dictionary mapping count ranges to colors (specified in
00046         reportlab.lib.colors).
00047         """
00048         self._names = segment_names
00049         self._count_info = {}
00050         self._label_info = {}
00051         self._scale_info = {}
00052         for name in self._names:
00053             self._count_info[name] = 0
00054             self._label_info[name] = None
00055             self._scale_info[name] = 1
00056         
00057         self._color_scheme = color_scheme
00058 
00059     def add_count(self, segment_name, count = 1):
00060         """Add counts to the given segment name.
00061 
00062         Arguments:
00063 
00064         o segment_name - The name of the segment we should add counts to.
00065         If the name is not present, a KeyError will be raised.
00066 
00067         o count - The counts to add the current segment. This defaults to
00068         a single count.
00069         """
00070         try:
00071             self._count_info[segment_name] += count
00072         except KeyError:
00073             raise KeyError("Segment name %s not found." % segment_name)
00074 
00075     def scale_segment_value(self, segment_name, scale_value = None):
00076         """Divide the counts for a segment by some kind of scale value.
00077 
00078         This is useful if segments aren't represented by raw counts, but
00079         are instead counts divided by some number.
00080         """
00081         try:
00082             self._count_info[segment_name] = \
00083               float(self._count_info[segment_name]) / float(scale_value)
00084         except KeyError:
00085             raise KeyError("Segment name %s not found." % segment_name)
00086 
00087     def add_label(self, segment_name, label):
00088         """Add a label to a specfic segment.
00089 
00090         Raises a KeyError is the specified segment name is not found.
00091         """
00092         if segment_name in self._label_info:
00093             self._label_info[segment_name] = label
00094         else:
00095             raise KeyError("Segment name %s not found." % segment_name)
00096 
00097     def set_scale(self, segment_name, scale):
00098         """Set the scale for a specific chromosome segment.
00099 
00100         By default all segments have the same scale -- this allows scaling
00101         by the size of the segment.
00102 
00103         Raises a KeyError is the specified segment name is not found.
00104         """
00105         if segment_name in self._label_info:
00106             self._scale_info[segment_name] = scale
00107         else:
00108             raise KeyError("Segment name %s not found." % segment_name)
00109 
00110     def get_segment_info(self):
00111         """Retrieve the color and label info about the segments.
00112 
00113         Returns a list consiting of two tuples specifying the counts and
00114         label name for each segment. The list is ordered according to the
00115         original listing of names. Labels are set as None if no label
00116         was specified.
00117         """
00118         order_info = []
00119 
00120         for seg_name in self._names:
00121             order_info.append((self._count_info[seg_name],
00122                                self._label_info[seg_name]))
00123 
00124         return order_info
00125 
00126     def fill_chromosome(self, chromosome):
00127         """Add the collected segment information to a chromosome for drawing.
00128 
00129         Arguments:
00130 
00131         o chromosome - A Chromosome graphics object that we can add
00132         chromosome segments to.
00133 
00134         This creates ChromosomeSegment (and TelomereSegment) objects to
00135         fill in the chromosome. The information is derived from the
00136         label and count information, with counts transformed to the
00137         specified color map.
00138 
00139         Returns the chromosome with all of the segments added.
00140         """
00141         for seg_num in range(len(self._names)):
00142             is_end_segment = 0
00143             # make the top and bottom telomeres
00144             if seg_num == 0:
00145                 cur_segment = TelomereSegment()
00146                 is_end_segment = 1
00147             elif seg_num == len(self._names) - 1:
00148                 cur_segment = TelomereSegment(1)
00149                 is_end_segment = 1
00150             # otherwise, they are just regular segments
00151             else:
00152                 cur_segment = ChromosomeSegment()
00153 
00154             seg_name = self._names[seg_num]
00155             if self._count_info[seg_name] > 0:
00156                 color = self._color_from_count(self._count_info[seg_name])
00157                 cur_segment.fill_color = color
00158             
00159             if self._label_info[seg_name] is not None:
00160                 cur_segment.label = self._label_info[seg_name]
00161 
00162             # give end segments extra size so they look right
00163             if is_end_segment:
00164                 cur_segment.scale = 3
00165             else:
00166                 cur_segment.scale = self._scale_info[seg_name]
00167 
00168             chromosome.add(cur_segment)
00169 
00170         return chromosome
00171 
00172     def _color_from_count(self, count):
00173         """Translate the given count into a color using the color scheme.
00174         """
00175         for count_start, count_end in self._color_scheme:
00176             if count >= count_start and count <= count_end:
00177                 return self._color_scheme[(count_start, count_end)]
00178 
00179         # if we got here we didn't find a color for the count
00180         raise ValueError("Count value %s was not found in the color scheme."
00181                          % count)
00182         
00183         
00184