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 is None: 339 raise ValueError("Must specify track") 340 if track_level not in self.tracks: # No track at that level 341 self.tracks[track_level] = track # so just add it 342 else: # Already a track there, so shunt all higher tracks up one 343 occupied_levels = self.get_levels() # Get list of occupied levels... 344 occupied_levels.sort() # ...sort it... 345 occupied_levels.reverse() # ...reverse it (highest first) 346 for val in occupied_levels: 347 # If track value >= that to be added 348 if val >= track.track_level: 349 self.tracks[val+1] = self.tracks[val] # ...increment by 1 350 self.tracks[track_level] = track # And put the new track in 351 self.tracks[track_level].track_level = track_level
352 353
354 - def new_track(self, track_level, **args):
355 """ new_track(self, track_level) -> Track 356 357 o track_level Int, the level at which the track will be drawn 358 (above an arbitrary baseline) 359 360 Add a new Track to the diagram at a given level and returns it for 361 further user manipulation. 362 """ 363 newtrack = Track() 364 for key in args: 365 setattr(newtrack, key, args[key]) 366 if track_level not in self.tracks: # No track at that level 367 self.tracks[track_level] = newtrack # so just add it 368 else: # Already a track there, so shunt all higher tracks up one 369 occupied_levels = self.get_levels() # Get list of occupied levels... 370 occupied_levels.sort() # ...sort it... 371 occupied_levels.reverse() # ...reverse (highest first)... 372 for val in occupied_levels: 373 if val >= track_level: # Track value >= that to be added 374 self.tracks[val+1] = self.tracks[val] # ..increment by 1 375 self.tracks[track_level] = newtrack # And put the new track in 376 self.tracks[track_level].track_level = track_level 377 return newtrack
378 379
380 - def del_track(self, track_level):
381 """ del_track(self, track_level) 382 383 o track_level Int, the level of the track on the diagram to delete 384 385 Remove the track at the passed level from the diagram 386 """ 387 del self.tracks[track_level]
388 389
390 - def get_tracks(self):
391 """ get_tracks(self) -> list 392 393 Returns a list of the tracks contained in the diagram 394 """ 395 return self.tracks.values()
396 397
398 - def move_track(self, from_level, to_level):
399 """ move_track(self, from_level, to_level) 400 401 o from_level Int, the level at which the track to be moved is 402 found 403 404 o to_level Int, the level to move the track to 405 406 Moves a track from one level on the diagram to another 407 """ 408 aux = self.tracks[from_level] 409 del self.tracks[from_level] 410 self.add_track(aux, to_level)
411 412
413 - def renumber_tracks(self, low=1, step=1):
414 """ renumber_tracks(self, low=1, step=1) 415 416 o low Int, the track number to start from 417 418 o step Int, the track interval for separation of tracks 419 420 Reassigns all the tracks to run consecutively from the lowest 421 value (low) 422 """ 423 track = low # Start numbering from here 424 levels = self.get_levels() # 425 426 conversion = {} # Holds new set of levels 427 for level in levels: # Starting at low... 428 conversion[track] = self.tracks[level] # Add old tracks to new set 429 conversion[track].track_level = track 430 track += step # step interval 431 self.tracks = conversion # Replace old set of levels with new set
432
433 - def get_levels(self):
434 """ get_levels(self) -> [int, int, ...] 435 436 Return a sorted list of levels occupied by tracks in the diagram 437 """ 438 levels = self.tracks.keys() 439 levels.sort() 440 return levels
441 442
443 - def get_drawn_levels(self):
444 """ get_drawn_levels(self) -> [int, int, ...] 445 446 Return a sorted list of levels occupied by tracks that are not 447 explicitly hidden 448 """ 449 drawn_levels = [key for key in self.tracks.keys() if \ 450 not self.tracks[key].hide] # get list of shown levels 451 drawn_levels.sort() 452 return drawn_levels
453 454
455 - def range(self):
456 """ range(self) -> (int, int) 457 458 Returns the lowest and highest base (or mark) numbers containd in 459 track features as a tuple 460 """ 461 lows, highs = [], [] 462 for track in self.tracks.values(): # Get ranges for each track 463 low, high = track.range() 464 lows.append(low) 465 highs.append(high) 466 return (min(lows), max(highs)) # Return extremes from all tracks
467
468 - def __getitem__(self, key):
469 """ __getitem__(self, key) -> Track 470 471 o key The id of a track in the diagram 472 473 Return the Track object with the passed id 474 """ 475 return self.tracks[key]
476
477 - def __str__(self):
478 """ __str__(self) -> "" 479 480 Returns a formatted string with information about the diagram 481 """ 482 outstr = ["\n<%s: %s>" % (self.__class__, self.name)] 483 outstr.append("%d tracks" % len(self.tracks)) 484 for level in self.get_levels(): 485 outstr.append("Track %d: %s\n" % (level, self.tracks[level])) 486 outstr = '\n'.join(outstr) 487 return outstr
488