Package Bio :: Package Graphics :: Package GenomeDiagram :: Module _Diagram
[hide private]
[frames] | no frames]

Source Code for Module Bio.Graphics.GenomeDiagram._Diagram

  1  # Copyright 2003-2008 by Leighton Pritchard.  All rights reserved. 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license.  Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5  # 
  6  # Contact:       Leighton Pritchard, Scottish Crop Research Institute, 
  7  #                Invergowrie, Dundee, Scotland, DD2 5DA, UK 
  8  #                L.Pritchard@scri.ac.uk 
  9  ################################################################################ 
 10   
 11  """ Diagram module 
 12   
 13      Provides: 
 14   
 15      o Diagram -   Container for information concerning the tracks to be 
 16                      drawn in a diagram, and the interface for defining the 
 17                      diagram (possibly split these functions in later version?) 
 18   
 19      For drawing capabilities, this module uses reportlab to draw and write 
 20      the diagram: 
 21   
 22      http://www.reportlab.com 
 23   
 24      For dealing with biological information, the package expects BioPython 
 25      objects - namely SeqRecord ojbects containing SeqFeature objects. 
 26  """ 
 27   
 28  #------------------------------------------------------------------------------ 
 29  # IMPORTS 
 30   
 31  # ReportLab 
 32  from reportlab.graphics import renderPS, renderPDF, renderSVG 
 33  try: 
 34      from reportlab.graphics import renderPM 
 35  except ImportError: 
 36      #This is an optional part of ReportLab, so may not be installed. 
 37      renderPM=None 
 38  from reportlab.lib import pagesizes 
 39   
 40  # GenomeDiagram 
 41  from _LinearDrawer import LinearDrawer 
 42  from _CircularDrawer import CircularDrawer 
 43  from _Track import Track 
 44   
 45  # Builtins 
 46  import sys 
 47   
 48  from Bio.Graphics import _write 
 49   
 50  #------------------------------------------------------------------------------ 
 51  # CLASSES 
 52   
 53  #------------------------------------------------------------ 
 54  # Diagram 
 55   
56 -class Diagram(object):
57 """ Diagram 58 59 Provides: 60 61 Attributes: 62 63 o name String, identifier for the diagram 64 65 o tracks List of Track objects comprising the diagram 66 67 o format String, format of the diagram (circular/linear) 68 69 o pagesize String, the pagesize of output 70 71 o orientation String, the page orientation (landscape/portrait) 72 73 o x Float, the proportion of the page to take up with even 74 X margins 75 76 o y Float, the proportion of the page to take up with even 77 Y margins 78 79 o xl Float, the proportion of the page to take up with the 80 left X margin 81 82 o xr Float, the proportion of the page to take up with the 83 right X margin 84 85 o yt Float, the proportion of the page to take up with the 86 top Y margin 87 88 o yb Float, the proportion of the page to take up with the 89 bottom Y margin 90 91 o start Int, the base/aa position to start the diagram at 92 93 o end Int, the base/aa position to end the diagram at 94 95 o tracklines Boolean, True if track guidelines are to be drawn 96 97 o fragments Int, for a linear diagram, the number of equal divisions 98 into which the sequence is divided 99 100 o fragment_size Float, the proportion of the space available to each 101 fragment that should be used in drawing 102 103 o track_size Float, the proportion of the space available to each 104 track that should be used in drawing 105 106 o circular Boolean, True if the genome/sequence to be drawn is, in 107 reality, circular. 108 109 Methods: 110 111 o __init__(self, name=None) Called on instantiation 112 113 o draw(self, format='circular', pagesize='A3', orientation='landscape', 114 x=0.05, y=0.05, xl=None, xr=None, yt=None, yb=None, 115 start=None, end=None, tracklines=0, fragments=10, 116 fragment_size=0.9, track_size=0.75) Instructs the package to draw 117 the diagram 118 119 o write(self, filename='test1.ps', output='PS') Writes the drawn 120 diagram to a specified file, in a specified format. 121 122 o add_track(self, track, track_level) Adds a Track object to the 123 diagram, with instructions to place it at a particular level on 124 the diagram 125 126 o del_track(self, track_level) Removes the track that is to be drawn 127 at a particular level on the diagram 128 129 o get_tracks(self) Returns the list of Track objects to be drawn 130 contained in the diagram 131 132 o renumber_tracks(self, low=1) Renumbers all tracks consecutively, 133 optionally from a passed lowest number 134 135 o get_levels(self) Returns a list of levels currently occupied by 136 Track objects 137 138 o get_drawn_levels(self) Returns a list of levels currently occupied 139 by Track objects that will be shown in the drawn diagram (i.e. 140 are not hidden) 141 142 o range(self) Returns the lowest- and highest-numbered positions 143 contained within features in all tracks on the diagram as a tuple. 144 145 o __getitem__(self, key) Returns the track contained at the level of 146 the passed key 147 148 o __str__(self) Returns a formatted string describing the diagram 149 150 """
151 - def __init__(self, name=None, format='circular', pagesize='A3', 152 orientation='landscape', x=0.05, y=0.05, xl=None, 153 xr=None, yt=None, yb=None, start=None, end=None, 154 tracklines=False, fragments=10, fragment_size=0.9, 155 track_size=0.75, circular=True):
156 """ __init__(self, name=None) 157 158 o name String describing the diagram 159 160 o format String: 'circular' or 'linear', depending on the sort of 161 diagram required 162 163 o pagesize String describing the ISO size of the image, or a tuple 164 of pixels 165 166 o orientation String describing the required orientation of the 167 final drawing ('landscape' or 'portrait') 168 169 o x Float (0->1) describing the relative size of the X 170 margins to the page 171 172 o y Float (0->1) describing the relative size of the Y 173 margins to the page 174 175 o xl Float (0->1) describing the relative size of the left X 176 margin to the page (overrides x) 177 178 o xl Float (0->1) describing the relative size of the left X 179 margin to the page (overrides x) 180 181 o xr Float (0->1) describing the relative size of the right X 182 margin to the page (overrides x) 183 184 o yt Float (0->1) describing the relative size of the top Y 185 margin to the page (overrides y) 186 187 o yb Float (0->1) describing the relative size of the lower Y 188 margin to the page (overrides y) 189 190 o start Int, the position to begin drawing the diagram at 191 192 193 o end Int, the position to stop drawing the diagram at 194 195 o tracklines Boolean flag to show (or not) lines delineating 196 tracks on the diagram 197 198 o fragments Int, for linear diagrams, the number of sections into 199 which to break the sequence being drawn 200 201 o fragment_size Float (0->1), for linear diagrams, describing 202 the proportion of space in a fragment to take 203 up with tracks 204 205 o track_size Float (0->1) describing the proportion of space 206 in a track to take up with sigils 207 208 o circular Boolean flag to indicate whether the sequence being 209 drawn is circular 210 211 212 """ 213 self.tracks = {} # Holds all Track objects, keyed by level 214 self.name = name # Description of the diagram 215 # Diagram page setup attributes 216 self.format = format 217 self.pagesize = pagesize 218 self.orientation = orientation 219 self.x = x 220 self.y = y 221 self.xl = xl 222 self.xr = xr 223 self.yt = yt 224 self.yb = yb 225 self.start = start 226 self.end = end 227 self.tracklines = tracklines 228 self.fragments = fragments 229 self.fragment_size = fragment_size 230 self.track_size = track_size 231 self.circular = circular
232
233 - def set_all_tracks(self, attr, value):
234 """ set_all_tracks(self, attr, value) 235 236 o attr An attribute of the Track class 237 238 o value The value to set that attribute 239 240 Set the passed attribute of all tracks in the set to the 241 passed value 242 """ 243 for track in self.tracks.values(): 244 if hasattr(track, attr): # If the feature has the attribute 245 if getattr(track, attr) != value: 246 setattr(track, attr, value) # set it to the passed value
247
248 - def draw(self, format=None, pagesize=None, orientation=None, 249 x=None, y=None, xl=None, xr=None, yt=None, yb=None, 250 start=None, end=None, tracklines=None, fragments=None, 251 fragment_size=None, track_size=None, circular=None):
252 """ draw(self, format=None, pagesize=None, orientation=None, 253 x=None, y=None, xl=None, xr=None, yt=None, yb=None, 254 start=None, end=None, tracklines=None, fragments=None, 255 fragment_size=None, track_size=None) 256 257 Draws the diagram using the passed parameters, if any, to override 258 previous settings for the diagram object. 259 """ 260 # Pass the parameters to the drawer objects that will build the 261 # diagrams. At the moment, we detect overrides with an or in the 262 # Instantiation arguments, but I suspect there's a neater way to do 263 # this. 264 if format == 'linear': 265 drawer = LinearDrawer(self, pagesize or self.pagesize, 266 orientation or self.orientation, 267 x or self.x, y or self.y, xl or self.xl, 268 xr or self.xr, yt or self.yt, 269 yb or self.yb, start or self.start, 270 end or self.end, 271 tracklines or self.tracklines, 272 fragments or self.fragments, 273 fragment_size or self.fragment_size, 274 track_size or self.track_size) 275 else: 276 drawer = CircularDrawer(self, pagesize or self.pagesize, 277 orientation or self.orientation, 278 x or self.x, y or self.y, xl or self.xl, 279 xr or self.xr, yt or self.yt, 280 yb or self.yb, start or self.start, 281 end or self.end, 282 tracklines or self.tracklines, 283 track_size or self.track_size, 284 circular or self.circular) 285 drawer.draw() # Tell the drawer to complete the drawing 286 self.drawing = drawer.drawing # Get the completed drawing
287
288 - def write(self, filename='test1.ps', output='PS', dpi=72):
289 """ write(self, filename='test1.ps', output='PS', dpi=72) 290 291 o filename String indicating the name of the output file, 292 or a handle to write to. 293 294 o output String indicating output format, one of PS, PDF, 295 SVG, or provided the ReportLab renderPM module is 296 installed, one of the bitmap formats JPG, BMP, 297 GIF, PNG, TIFF or TIFF. The format can be given 298 in upper or lower case. 299 300 o dpi Resolution (dots per inch) for bitmap formats. 301 302 Write the completed drawing out to a file in a prescribed format 303 304 No return value. 305 """ 306 return _write(self.drawing, filename, output, dpi=dpi)
307
308 - def write_to_string(self, output='PS', dpi=72):
309 """ write(self, output='PS') 310 311 o output String indicating output format, one of PS, PDF, 312 SVG, JPG, BMP, GIF, PNG, TIFF or TIFF (as 313 specified for the write method). 314 315 o dpi Resolution (dots per inch) for bitmap formats. 316 317 Return the completed drawing as a string in a prescribed format 318 """ 319 #The ReportLab drawToString method, which this function used to call, 320 #just uses a cStringIO or StringIO handle with the drawToFile method. 321 #In order to put all our complicated file format specific code in one 322 #place we'll just use a StringIO handle here: 323 from StringIO import StringIO 324 handle = StringIO() 325 self.write(handle, output, dpi) 326 return handle.getvalue()
327
328 - def add_track(self, track, track_level):
329 """ add_track(self, track, track_level) 330 331 o track Track object to draw 332 333 o track_level Int, the level at which the track will be drawn 334 (above an arbitrary baseline) 335 336 Add a pre-existing Track to the diagram at a given level 337 """ 338 if track_level not in self.tracks: # No track at that level 339 self.tracks[track_level] = track # so just add it 340 else: # Already a track there, so shunt all higher tracks up one 341 occupied_levels = self.get_levels() # Get list of occupied levels... 342 occupied_levels.sort() # ...sort it... 343 occupied_levels.reverse() # ...reverse it (highest first) 344 for val in occupied_levels: 345 if val >= track: # If track value >= that to be added 346 self.tracks[val+1] = self.tracks[val] # ...increment by 1 347 self.tracks[track_level] = track # And put the new track in 348 self.tracks[track_level].track_level = track_level
349 350
351 - def new_track(self, track_level, **args):
352 """ new_track(self, track_level) -> Track 353 354 o track_level Int, the level at which the track will be drawn 355 (above an arbitrary baseline) 356 357 Add a new Track to the diagram at a given level and returns it for 358 further user manipulation. 359 """ 360 newtrack = Track() 361 for key in args: 362 setattr(newtrack, key, args[key]) 363 if track_level not in self.tracks: # No track at that level 364 self.tracks[track_level] = newtrack # so just add it 365 else: # Already a track there, so shunt all higher tracks up one 366 occupied_levels = self.get_levels() # Get list of occupied levels... 367 occupied_levels.sort() # ...sort it... 368 occupied_levels.reverse() # ...reverse (highest first)... 369 for val in occupied_levels: 370 if val >= track_level: # Track value >= that to be added 371 self.tracks[val+1] = self.tracks[val] # ..increment by 1 372 self.tracks[track_level] = newtrack # And put the new track in 373 self.tracks[track_level].track_level = track_level 374 return newtrack
375 376
377 - def del_track(self, track_level):
378 """ del_track(self, track_level) 379 380 o track_level Int, the level of the track on the diagram to delete 381 382 Remove the track at the passed level from the diagram 383 """ 384 del self.tracks[track_level]
385 386
387 - def get_tracks(self):
388 """ get_tracks(self) -> list 389 390 Returns a list of the tracks contained in the diagram 391 """ 392 return self.tracks.values()
393 394
395 - def move_track(self, from_level, to_level):
396 """ move_track(self, from_level, to_level) 397 398 o from_level Int, the level at which the track to be moved is 399 found 400 401 o to_level Int, the level to move the track to 402 403 Moves a track from one level on the diagram to another 404 """ 405 aux = self.tracks[from_level] 406 del self.tracks[from_level] 407 self.add_track(aux, to_level)
408 409
410 - def renumber_tracks(self, low=1, step=1):
411 """ renumber_tracks(self, low=1, step=1) 412 413 o low Int, the track number to start from 414 415 o step Int, the track interval for separation of tracks 416 417 Reassigns all the tracks to run consecutively from the lowest 418 value (low) 419 """ 420 track = low # Start numbering from here 421 levels = self.get_levels() # 422 423 conversion = {} # Holds new set of levels 424 for level in levels: # Starting at low... 425 conversion[track] = self.tracks[level] # Add old tracks to new set 426 conversion[track].track_level = track 427 track += step # step interval 428 self.tracks = conversion # Replace old set of levels with new set
429
430 - def get_levels(self):
431 """ get_levels(self) -> [int, int, ...] 432 433 Return a sorted list of levels occupied by tracks in the diagram 434 """ 435 levels = self.tracks.keys() 436 levels.sort() 437 return levels
438 439
440 - def get_drawn_levels(self):
441 """ get_drawn_levels(self) -> [int, int, ...] 442 443 Return a sorted list of levels occupied by tracks that are not 444 explicitly hidden 445 """ 446 drawn_levels = [key for key in self.tracks.keys() if \ 447 not self.tracks[key].hide] # get list of shown levels 448 drawn_levels.sort() 449 return drawn_levels
450 451
452 - def range(self):
453 """ range(self) -> (int, int) 454 455 Returns the lowest and highest base (or mark) numbers containd in 456 track features as a tuple 457 """ 458 lows, highs = [], [] 459 for track in self.tracks.values(): # Get ranges for each track 460 low, high = track.range() 461 lows.append(low) 462 highs.append(high) 463 return (min(lows), max(highs)) # Return extremes from all tracks
464
465 - def __getitem__(self, key):
466 """ __getitem__(self, key) -> Track 467 468 o key The id of a track in the diagram 469 470 Return the Track object with the passed id 471 """ 472 return self.tracks[key]
473
474 - def __str__(self):
475 """ __str__(self) -> "" 476 477 Returns a formatted string with information about the diagram 478 """ 479 outstr = ["\n<%s: %s>" % (self.__class__, self.name)] 480 outstr.append("%d tracks" % len(self.tracks)) 481 for level in self.get_levels(): 482 outstr.append("Track %d: %s\n" % (level, self.tracks[level])) 483 outstr = '\n'.join(outstr) 484 return outstr
485