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