1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 """
29 List of Complex objects.
30 """
31
32 import numpy.oldnumeric as N
33 import types
34 import biggles
35 import random
36
37 import Biskit.tools as t
38 from Biskit import PDBError, EHandler
39 from Biskit.Errors import BiskitError
40
41 from Biskit.Dock.Complex import Complex
42 from Biskit.Dock.ComplexModelRegistry import ComplexModelRegistry
43
44
46 pass
47
49 pass
50
52 pass
53
55 pass
56
57
59 """
60 List of Complex objects. Special support is given to access and use
61 entries in the Complexes' info dictionaries for filtering and sorting.
62 Some care is taken to avoid the adding of non-Complex objects (but
63 somehow it is, certainly, still possible).
64
65 The different rec- and lig_models of all Complexes are centrally kept in a
66 ComplexModelRegistry. Before adding a Complex, we check
67 whether its rec- or lig_model are equivalent (same fileName and unchanged)
68 to one in the registy. If so, they are replaced to
69 avoid that each Complex points to its own copy of essentially the same
70 PDBmodel. This does only work with PDBModels that have been pickled to
71 disc (see PDBModel.saveAs ) and haven't been changed since. It's a very
72 good idea to do this if you want to perform any distributed calculation
73 on the ComplexList. Saved PDBModels cause only little PVM traffic (not much
74 more than the file name is transmitted). By contrast, unsaved ones will
75 severly slow down the job distribution.
76
77 @todo: Removing items with pop(), del, remove() etc. will not remove
78 unused PDBModels from rec_models or lig_models.
79 """
80
82 """
83 @param lst: list of Complexes
84 @type lst: [Complex]
85 """
86
87 self.models = ComplexModelRegistry()
88
89 self.initVersion = t.dateString() + ' ' + self.version()
90
91 if lst != []:
92 self.extend( lst )
93
94
96 """
97 Version of class.
98
99 @return: class version number
100 @rtype: str
101 """
102 return 'ComplexList $Revision: 2.13 $'
103
104
106 """
107 called for unpickling the object.
108 """
109 self.__dict__ = state
110
111 self.__defaults()
112
113
115 self.models = getattr( self, 'models', ComplexModelRegistry() )
116 if getattr( self, 'rec_models', 0) != 0:
117 EHandler.warning(
118 're-creating model registry..re-pickle this list!')
119 for c in self.toList():
120 self.models.addComplex( c )
121 del self.rec_models
122 del self.lig_models
123
124
126 """
127 Make sure v is a Complex.
128
129 @raise ComplexListError: if not a Complex
130 """
131 if not isinstance(v, Complex):
132 raise ComplexListError(
133 str( v ) + " not allowed. ComplexList requires "+str(Complex))
134
135
137 """
138 Make sure lst is a list of Complexes.
139
140 @raise ComplexListError: if list contains non-Complex item.
141 """
142 if not isinstance( lst, list ):
143 raise ComplexListError("Wrong argument type: "+str(type(lst)))
144
145 if not isinstance( lst, ComplexList ):
146 for v in lst:
147 self.checkType( v )
148
149
151 """
152 Set value v of position i.
153 >>> lst[i] = v
154
155 @param i: list index
156 @type i: int
157 @param v: value
158 @type v: any
159 """
160 self.checkType( v )
161
162 if i < list.__len__( self ):
163 self.models.removeComplex( self[i] )
164 self.models.addComplex( v )
165
166 list.__setitem__( self, i, v)
167
168
170 """
171 New ComplexList with the two lists.
172
173 @return: new instance with simply one list appended to the other
174 @rtype: ComplexList
175 """
176 r = self.__class__( self )
177 r.extend( lst )
178 return r
179
180
182 """
183 List appendet to this ComplexList.
184
185 @return: this instance with lst appended
186 @rtype: ComplexList
187 """
188 self.extend( lst )
189 return self
190
191
193 """
194 Get all shared ligand PDBModels. Stray models (changed or unpickled)
195 are not returned.
196
197 @return: list of ligand models
198 @rtype: [PDBModel]
199 """
200 return self.models.ligModels()
201
202
204 """
205 Get all shared receptor PDBModels. Stray models (changed or unpickled)
206 are not returned.
207
208 @return: list of receptor models
209 @rtype: [PDBModel]
210 """
211 return self.models.recModels()
212
213
215 """
216 Add eithem to list of it is not already there.
217 """
218 if lst == None:
219 lst = []
220 if not item in lst:
221 lst.append( item )
222 return lst
223
224
226 """
227 Look for models that are not in model registry.
228
229 @return: { int|str:[ PDBModel ] }, { int|str:[ PDBModel ] }
230 @rtype: dict
231
232 @note: mostly for DEBUGGING
233 """
234 stray_ligs = {}
235 stray_recs = {}
236 known_recs = self.recModels()
237 known_ligs = self.ligModels()
238 for c in self:
239 if c.rec_model not in known_recs:
240 key = c.get( 'model1', None ) or c.rec_model.fileName \
241 or 1
242 stray_recs[ key ] = self.__add_once( c.rec_model,
243 stray_recs.get( key, []) )
244
245 if c.lig_model not in known_ligs:
246 key = c.get( 'model2', None ) or c.lig_model.fileName \
247 or 1
248 stray_ligs[ key ] = self.__add_once( c.lig_model,
249 stray_ligs.get( key, []) )
250
251 return stray_recs, stray_ligs
252
253
255 """
256 extend( list ). Add all items to (the end of) this instance
257 """
258 self.checkTypes( lst )
259
260 list.extend( self, lst )
261
262 for v in lst:
263 self.models.addComplex( v )
264
265
267 """
268 append( Complex ). Append Complex to the end of this list.
269 """
270 self.checkType( v )
271 self.models.addComplex( v )
272 list.append( self, v )
273
274
276 """
277 Slice list.
278
279 @param i: start index
280 @type i: int
281 @param j: end index
282 @type j: int
283
284 @return: new instance with only the given range of items
285 @rtype: ComplexList
286 """
287 r = self.__class__(super(ComplexList, self).__getslice__(i,j))
288 return r
289
290
292 """
293 Indices for key in random order::
294 argsortRandom() -> [ int ], indices in random order.
295
296 @return: indices in random order
297 @rtype: [int]
298 """
299 pairs = [(random.random(), i) for i in range(0, len(self))]
300 pairs.sort()
301 return [ x[1] for x in pairs ]
302
303
305 """
306 Indices sort order for values of key::
307 argsort( str_sortKey ) -> [ int ], indices after sorting
308
309 @param sortKey: key to use for sorting
310 @type sortKey: str
311
312 @return: indices after sorting
313 @rtype: [int]
314 """
315 pairs = [(self[i].info.get(sortKey), i) for i in range(0, len(self))]
316 pairs.sort()
317 return [ x[1] for x in pairs ]
318
319
321 """
322 Sort ComplexList by key::
323 sortBy( str_sortKey ) -> ComplexList (or sub-class)
324 sorted by info[ str_sortKey ]
325
326 @param sortKey: key to use for sorting
327 @type sortKey: str
328
329 @return: sorted ComplexList
330 @rtype: ComplexList
331 """
332 return self.take( self.argsort( sortKey ))
333
334
335 - def valuesOf(self, infoKey, default=None, indices=None, unique=0 ):
336 """
337 Get all values of a certain info record of all or some Complexes.
338
339 @param infoKey: key for info dict
340 @type infoKey: str
341 @param default: default value if infoKey is not found (None)
342 @type default: any
343 @param indices: list of int OR None(=all), indices of Complexes (None)
344 @type indices: [int] OR None
345 @param unique: report each value only once (set union), (default 0)
346 @type unique: 1|0
347
348 @return: list of values
349 @rtype: [any]
350 """
351 l = self
352 if indices != None:
353 l = N.take( N.array(l,'O'), indices )
354
355 if not unique:
356 return [ c.info.get(infoKey, default) for c in l ]
357
358 r = []
359 for c in l:
360 if c.info.get(infoKey, default) not in r:
361 r += [ c.info.get( infoKey ) ]
362 return r
363
364
366 """
367 Get indices of Complexes where vLow <= c.info[ infoKey ] <= vHigh.
368
369 Use::
370 filterRange( str_infoKey, vLow, vHigh )
371
372 @param infoKey: key for info dict
373 @type infoKey: str
374 @param vLow: upper value limit
375 @type vLow: float
376 @param vHigh: lower value limit
377 @type vHigh: float
378
379 @return: array of int
380 @rtype: [int]
381 """
382 vLst = self.valuesOf( infoKey )
383
384 maskL = N.greater_equal( vLst, vLow )
385 maskH = N.less_equal( vLst, vHigh )
386
387 return N.nonzero( maskL * maskH )
388
389
391 """
392 Get indices of Complexes where c.info[ infoKey ] in lst.
393
394 Use::
395 filterEqual( infoKey, lst )
396
397 @param infoKey: key for info dict
398 @type infoKey: str
399 @param lst: list of values to look for
400 @type lst: [any]
401
402 @return: array of int
403 @rtype: [int]
404 """
405 mask = [ c.info.get( infoKey ) in lst for c in self ]
406 return N.nonzero( mask )
407
408
410 """
411 Get indices of Complexes where f( c ) == 1.
412
413 Use::
414 filterFunct( f )
415
416 @param f: filterFunct
417 @type f: function
418
419 @return: array of int
420 @rtype: [int]
421 """
422 mask = [ f( c ) for c in self ]
423 return N.nonzero( mask )
424
425
426 - def filter( self, infoKey, cond ):
427 """
428 Complexes matching condition.
429
430 @param infoKey: key of Complex.info dict
431 (not used if cond is function )
432 @type infoKey: str
433 @param cond: filter condition::
434 - (vLow, vHigh) -> vLow <= c.info[ infoKey ] <= vHigh
435 - list -> c.info[ infoKey ] in cond
436 - function -> cond( c ) == 1
437 @type cond: any
438
439 @return: ComplexList (or sub-class)
440 @rtype: ComplexList
441
442 @raise ConditionError: if cond is neither list nor tuple nor function
443 """
444 indices = None
445
446 if type( cond ) == tuple:
447
448 indices = self.filterRange( infoKey, cond[0], cond[1] )
449
450 if type( cond ) == list:
451
452 indices = self.filterEqual( infoKey, cond )
453
454 if type( cond ) == types.FunctionType:
455
456 indices = self.filterFunct( cond )
457
458 if indices == None:
459 try:
460 indices = self.filterEqual( infoKey, [cond] )
461 except:
462 raise ConditionError( "Can't interprete filter condition.")
463
464 return self.take(indices)
465
466
468 """
469 Get index of complex c with highest c.infos[infokey] value
470
471 @param infoKey: key for info dict
472 @type infoKey: str
473
474 @return: index of complex c with highest c.infos[infokey] value
475 @rtype: int
476 """
477 vLst = self.valuesOf( infoKey )
478 return N.argmax( vLst )
479
480
481 - def max( self, infoKey ):
482 """
483 Get higest c.infos[infokey] value.
484
485 @param infoKey: key for info dict
486 @type infoKey: str
487
488 @return: with highest c.info['infoKey'] value
489 @rtype: Complex
490 """
491 return self[ self.argmax(infoKey) ]
492
493
495 """
496 Get index of complex c with lowest c.infos[infokey] value
497
498 @param infoKey: key for info dict
499 @type infoKey: str
500
501 @return: index of complex c with lowest c.infos[infokey] value
502 @rtype: int
503 """
504 vLst = self.valuesOf( infoKey )
505 return N.argmin( vLst )
506
507 - def min( self, infoKey ):
508 """
509 Get lowest c.infos[infokey] value.
510
511 @param infoKey: key for info dict
512 @type infoKey: str
513
514 @return: with lowest c.info['infoKey'] value
515 @rtype: Complex
516 """
517 return self[ self.argmin( infoKey ) ]
518
519
521 """
522 Get list position of Complex where c.info['infoKey'] == value
523
524 @param value: vaue to look for
525 @type value: any
526 @param infoKey: key for info dict
527 @type infoKey: str
528
529 @return: position in ComplexList where c.info['infoKey'] == value
530 @rtype: int
531
532 @raise AmbiguousMatch: ComplexNotFound,
533 if there are more or less than 1 matches
534 """
535 l = self.filterEqual( infoKey, [ value ] )
536
537 if len( l ) == 1:
538 return l[0]
539
540 if len( l ) > 1:
541 raise AmbiguousMatch('More than one Complexes match.')
542
543 raise ComplexNotFound("No matching Complex.")
544
545
546 - def getItem( self, infoKey, value ):
547 """
548 Get Complex from ComplexList where c.info['infoKey'] == value
549
550 @param value: vaue to look for
551 @type value: any
552 @param infoKey: key for info dict
553 @type infoKey: str
554
555 @return: Complex where c.info['infoKey'] == value
556 @rtype: Complex
557
558 @raise AmbiguousMatch: ComplexNotFound,
559 if there are more or less than 1 matches
560 """
561 return self[ self.getIndex( infoKey, value ) ]
562
563
564 - def take( self, indices ):
565 """
566 Take the complexes specified by indices.
567
568 @param indices: array/list of int, list positions
569 @type indices: [int]
570
571 @return: ComplexList with all items specified.
572 @rtype: ComplexList
573 """
574 r = self.__class__( [ self[i] for i in indices ] )
575
576 return r
577
578
580 """
581 Convert list into dict indexed by a certain info-record value.
582 If several Complexes have the same value, the result will have
583 a list registered for this key.
584
585 EXAMPLE:
586 >>> clst.toDict('soln') -> {1:Complex, 3:Complex, solnN:Complex}
587
588 @param infoKey: key of info dict in Complexes
589 @type infoKey: str
590
591 @return: { info1:Complex, info2:Complex, info3:[Complex, Complex].. }
592 @rtype: dict
593 """
594 result = {}
595 for c in self:
596 t.dictAdd( result, c.info[infoKey], c )
597
598 return result
599
600
602 """
603 Convert ComplexList to simple python list of Complexes
604
605 @return: simple python list of Complexes
606 @rtype: [Complex]
607 """
608 return list( self )
609
610
612 """
613 Take out positions from l1 and l2 that are None in either of them.
614
615 @param l1: first ComplexList
616 @type l1: ComplexList
617 @param l2: second ComplexList
618 @type l2: ComplexList
619
620 @return: (l1, l2) modified lists
621 @rtype: ComplexList, ComplexList
622 """
623 r1, r2 = [],[]
624
625 for i in range( len(l1)):
626 if l1[i] != None and l2[i] != None:
627 r1 += [ l1[i] ]
628 r2 += [ l2[i] ]
629
630 return r1, r2
631
632
633 - def plot( self, xkey, *ykey, **arg ):
634 """
635 Plot pairs of info values. The additional arg arguments are handed
636 over to biggles.Points().::
637 plot( xkey, [ykey1, ykey2..],[arg1=x, arg2=y]) -> biggles.FramedPlot
638
639 @param xkey: key specifying x-values
640 @type xkey: str
641 @param ykey: key specifying y-values
642 @type ykey: str OR [str]
643 @param arg: additional biggles arguments
644 @type arg: key=value
645
646 @return: biggles plot object
647 @rtype: biggles.FramedPlot()
648 """
649 plot = biggles.FramedPlot()
650
651 plot.xlabel = xkey
652
653 colors = t.colorSpectrum( len( ykey ) )
654
655 if not 'size' in arg:
656 arg['size'] = 1
657
658 for i in range( len(ykey)):
659
660 x = self.valuesOf( xkey )
661 y = self.valuesOf( ykey[i] )
662
663 x, y = self.__maskNone( x, y )
664
665 plot.add( biggles.Points( x, y, color=colors[i], **arg ) )
666
667 plot.add( biggles.PlotLabel( 0.2, 0.95-i/8.0, ykey[i],
668 color=colors[i] ) )
669
670 return plot
671
672
674 """
675 Plot pairs of info values.::
676 plot( xkey, [ykey1, ykey2..],[arg1=x, arg2=y]) -> biggles.FramedArray
677
678 @param xkey: key specifying x-values
679 @type xkey: str
680 @param ykey: key specifying y-values
681 @type ykey: str OR [str]
682 @param arg: additional biggles arguments
683 @type arg: key=value
684
685 @return: biggles plot object
686 @rtype: biggles.FramedArray
687 """
688 plot = biggles.FramedArray( len(ykey),1 )
689
690 plot.xlabel = xkey
691
692 colors = t.colorSpectrum( len( ykey ) )
693
694 if not 'size' in arg:
695 arg['size'] = 1
696
697 for i in range( len(ykey)):
698
699 x = self.valuesOf( xkey )
700 y = self.valuesOf( ykey[i] )
701
702 x, y = self.__maskNone( x, y )
703
704 plot[i,0].add( biggles.Points( x, y, color=colors[i], **arg ) )
705
706 plot[i,0].add( biggles.PlotLabel( 0.2, 0.95, ykey[i],
707 color=colors[i] ) )
708
709 return plot
710
711
712
713
714
715 import Biskit.test as BT
716
717 -class Test(BT.BiskitTest):
718 """Test case"""
719
721 """Dock.ComplexList test"""
722 self.cl = t.Load( t.testRoot() + "/dock/hex/complexes.cl" )
723
724
725 self.cl_sorted = self.cl.sortBy( 'rms' )
726 self.hex_clst = self.cl_sorted.valuesOf( 'hex_clst',
727 indices=range(100),
728 unique=1 )
729
730 if self.local:
731 self.p = self.cl.plot( 'rms', 'hex_eshape', 'hex_etotal' )
732 self.p.show()
733
734 self.assertEqual( len( self.hex_clst ), 36)
735
736 if __name__ == '__main__':
737
738 BT.localTest()
739