1 """@namespace IMP.pmi.output
2 Classes for writing output files and processing them.
26 """Map indices to multi-character chain IDs.
27 We label the first 26 chains A-Z, then we move to two-letter
28 chain IDs: AA through AZ, then BA through BZ, through to ZZ.
29 This continues with longer chain IDs."""
30 def __getitem__(self, ind):
31 chars = string.ascii_uppercase
35 ids.append(chars[ind % lc])
37 ids.append(chars[ind])
38 return "".join(reversed(ids))
42 """Base class for capturing a modeling protocol.
43 Unlike simple output of model coordinates, a complete
44 protocol includes the input data used, details on the restraints,
45 sampling, and clustering, as well as output models.
46 Use via IMP.pmi.topology.System.add_protocol_output().
48 @see IMP.pmi.mmcif.ProtocolOutput for a concrete subclass that outputs
56 if isinstance(elt, (tuple, list)):
57 for elt2
in _flatten(elt):
63 def _disambiguate_chain(chid, seen_chains):
64 """Make sure that the chain ID is unique; warn and correct if it isn't"""
69 if chid
in seen_chains:
70 warnings.warn(
"Duplicate chain ID '%s' encountered" % chid,
73 for suffix
in itertools.count(1):
74 new_chid = chid +
"%d" % suffix
75 if new_chid
not in seen_chains:
76 seen_chains.add(new_chid)
82 def _write_pdb_internal(flpdb, particle_infos_for_pdb, geometric_center,
83 write_all_residues_per_bead):
84 for n, tupl
in enumerate(particle_infos_for_pdb):
85 (xyz, atom_type, residue_type,
86 chain_id, residue_index, all_indexes, radius) = tupl
88 atom_type = IMP.atom.AT_CA
89 if write_all_residues_per_bead
and all_indexes
is not None:
90 for residue_number
in all_indexes:
92 IMP.atom.get_pdb_string((xyz[0] - geometric_center[0],
93 xyz[1] - geometric_center[1],
94 xyz[2] - geometric_center[2]),
95 n+1, atom_type, residue_type,
96 chain_id[:1], residue_number,
' ',
100 IMP.atom.get_pdb_string((xyz[0] - geometric_center[0],
101 xyz[1] - geometric_center[1],
102 xyz[2] - geometric_center[2]),
103 n+1, atom_type, residue_type,
104 chain_id[:1], residue_index,
' ',
106 flpdb.write(
"ENDMDL\n")
109 _Entity = collections.namedtuple(
'_Entity', (
'id',
'seq'))
110 _ChainInfo = collections.namedtuple(
'_ChainInfo', (
'entity',
'name'))
113 def _get_chain_info(chains, root_hier):
117 for mol
in IMP.atom.get_by_type(root_hier, IMP.atom.MOLECULE_TYPE):
119 chain_id = chains[molname]
121 seq = chain.get_sequence()
122 if seq
not in entities:
123 entities[seq] = e = _Entity(id=len(entities)+1, seq=seq)
124 all_entities.append(e)
125 entity = entities[seq]
126 info = _ChainInfo(entity=entity, name=molname)
127 chain_info[chain_id] = info
128 return chain_info, all_entities
131 def _write_mmcif_internal(flpdb, particle_infos_for_pdb, geometric_center,
132 write_all_residues_per_bead, chains, root_hier):
134 chain_info, entities = _get_chain_info(chains, root_hier)
136 writer = ihm.format.CifWriter(flpdb)
137 writer.start_block(
'model')
138 with writer.category(
"_entry")
as lp:
141 with writer.loop(
"_entity", [
"id",
"type"])
as lp:
143 lp.write(id=e.id, type=
"polymer")
145 with writer.loop(
"_entity_poly",
146 [
"entity_id",
"pdbx_seq_one_letter_code"])
as lp:
148 lp.write(entity_id=e.id, pdbx_seq_one_letter_code=e.seq)
150 with writer.loop(
"_struct_asym", [
"id",
"entity_id",
"details"])
as lp:
152 for chid
in sorted(chains.values(), key=
lambda x: (len(x.strip()), x)):
153 ci = chain_info[chid]
154 lp.write(id=chid, entity_id=ci.entity.id, details=ci.name)
156 with writer.loop(
"_atom_site",
157 [
"group_PDB",
"type_symbol",
"label_atom_id",
158 "label_comp_id",
"label_asym_id",
"label_seq_id",
160 "Cartn_x",
"Cartn_y",
"Cartn_z",
"label_entity_id",
161 "pdbx_pdb_model_num",
164 for n, tupl
in enumerate(particle_infos_for_pdb):
165 (xyz, atom_type, residue_type,
166 chain_id, residue_index, all_indexes, radius) = tupl
167 ci = chain_info[chain_id]
168 if atom_type
is None:
169 atom_type = IMP.atom.AT_CA
170 c = (xyz[0] - geometric_center[0],
171 xyz[1] - geometric_center[1],
172 xyz[2] - geometric_center[2])
173 if write_all_residues_per_bead
and all_indexes
is not None:
174 for residue_number
in all_indexes:
175 lp.write(group_PDB=
'ATOM',
177 label_atom_id=atom_type.get_string(),
178 label_comp_id=residue_type.get_string(),
179 label_asym_id=chain_id,
180 label_seq_id=residue_index,
181 auth_seq_id=residue_index, Cartn_x=c[0],
182 Cartn_y=c[1], Cartn_z=c[2], id=ordinal,
183 pdbx_pdb_model_num=1,
184 label_entity_id=ci.entity.id)
187 lp.write(group_PDB=
'ATOM', type_symbol=
'C',
188 label_atom_id=atom_type.get_string(),
189 label_comp_id=residue_type.get_string(),
190 label_asym_id=chain_id,
191 label_seq_id=residue_index,
192 auth_seq_id=residue_index, Cartn_x=c[0],
193 Cartn_y=c[1], Cartn_z=c[2], id=ordinal,
194 pdbx_pdb_model_num=1,
195 label_entity_id=ci.entity.id)
200 """Class for easy writing of PDBs, RMFs, and stat files
202 @note Model should be updated prior to writing outputs.
204 def __init__(self, ascii=True, atomistic=False):
205 self.dictionary_pdbs = {}
207 self.dictionary_rmfs = {}
208 self.dictionary_stats = {}
209 self.dictionary_stats2 = {}
210 self.best_score_list =
None
211 self.nbestscoring =
None
213 self.replica_exchange =
False
218 self.chainids =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
219 "abcdefghijklmnopqrstuvwxyz0123456789"
221 self.multi_chainids = _ChainIDs()
223 self.particle_infos_for_pdb = {}
224 self.atomistic = atomistic
227 """Get a list of all PDB files being output by this instance"""
228 return list(self.dictionary_pdbs.keys())
230 def get_rmf_names(self):
231 return list(self.dictionary_rmfs.keys())
233 def get_stat_names(self):
234 return list(self.dictionary_stats.keys())
236 def _init_dictchain(self, name, prot, multichar_chain=False, mmcif=False):
237 self.dictchain[name] = {}
241 self.atomistic =
True
242 for n, mol
in enumerate(IMP.atom.get_by_type(
243 prot, IMP.atom.MOLECULE_TYPE)):
245 if not mmcif
and len(chid) > 1:
247 "The system contains at least one chain ID (%s) that "
248 "is more than 1 character long; this cannot be "
249 "represented in PDB. Either write mmCIF files "
250 "instead, or assign 1-character IDs to all chains "
251 "(this can be done with the `chain_ids` argument to "
252 "BuildSystem.add_state())." % chid)
253 chid = _disambiguate_chain(chid, seen_chains)
255 self.dictchain[name][molname] = chid
259 @param name The PDB filename
260 @param prot The hierarchy to write to this pdb file
261 @param mmcif If True, write PDBs in mmCIF format
262 @note if the PDB name is 'System' then will use Selection
265 flpdb = open(name,
'w')
267 self.dictionary_pdbs[name] = prot
268 self._pdb_mmcif[name] = mmcif
269 self._init_dictchain(name, prot, mmcif=mmcif)
271 def write_psf(self, filename, name):
272 flpsf = open(filename,
'w')
273 flpsf.write(
"PSF CMAP CHEQ" +
"\n")
274 index_residue_pair_list = {}
275 (particle_infos_for_pdb, geometric_center) = \
276 self.get_particle_infos_for_pdb_writing(name)
277 nparticles = len(particle_infos_for_pdb)
278 flpsf.write(str(nparticles) +
" !NATOM" +
"\n")
279 for n, p
in enumerate(particle_infos_for_pdb):
284 flpsf.write(
'{0:8d}{1:1s}{2:4s}{3:1s}{4:4s}{5:1s}{6:4s}{7:1s}'
285 '{8:4s}{9:1s}{10:4s}{11:14.6f}{12:14.6f}{13:8d}'
286 '{14:14.6f}{15:14.6f}'.format(
287 atom_index,
" ", chain,
" ", str(resid),
" ",
288 '"'+residue_type.get_string()+
'"',
" ",
"C",
289 " ",
"C", 1.0, 0.0, 0, 0.0, 0.0))
291 if chain
not in index_residue_pair_list:
292 index_residue_pair_list[chain] = [(atom_index, resid)]
294 index_residue_pair_list[chain].append((atom_index, resid))
298 for chain
in sorted(index_residue_pair_list.keys()):
300 ls = index_residue_pair_list[chain]
302 ls = sorted(ls, key=
lambda tup: tup[1])
304 indexes = [x[0]
for x
in ls]
307 indexes, lmin=2, lmax=2))
308 nbonds = len(indexes_pairs)
309 flpsf.write(str(nbonds)+
" !NBOND: bonds"+
"\n")
312 for i
in range(0, len(indexes_pairs), 4):
313 for bond
in indexes_pairs[i:i+4]:
314 flpsf.write(
'{0:8d}{1:8d}'.format(*bond))
317 del particle_infos_for_pdb
320 def write_pdb(self, name, appendmode=True,
321 translate_to_geometric_center=
False,
322 write_all_residues_per_bead=
False):
324 (particle_infos_for_pdb,
325 geometric_center) = self.get_particle_infos_for_pdb_writing(name)
327 if not translate_to_geometric_center:
328 geometric_center = (0, 0, 0)
330 filemode =
'a' if appendmode
else 'w'
331 with open(name, filemode)
as flpdb:
332 if self._pdb_mmcif[name]:
333 _write_mmcif_internal(flpdb, particle_infos_for_pdb,
335 write_all_residues_per_bead,
336 self.dictchain[name],
337 self.dictionary_pdbs[name])
339 _write_pdb_internal(flpdb, particle_infos_for_pdb,
341 write_all_residues_per_bead)
344 """Get the protein name from the particle.
345 This is done by traversing the hierarchy."""
348 def get_particle_infos_for_pdb_writing(self, name):
358 particle_infos_for_pdb = []
360 geometric_center = [0, 0, 0]
365 and self.dictionary_pdbs[name].get_number_of_children() == 0):
369 ps = sel.get_selected_particles()
371 for n, p
in enumerate(ps):
374 if protname
not in resindexes_dict:
375 resindexes_dict[protname] = []
379 rt = residue.get_residue_type()
380 resind = residue.get_index()
384 geometric_center[0] += xyz[0]
385 geometric_center[1] += xyz[1]
386 geometric_center[2] += xyz[2]
388 particle_infos_for_pdb.append(
389 (xyz, atomtype, rt, self.dictchain[name][protname],
390 resind,
None, radius))
391 resindexes_dict[protname].append(resind)
396 resind = residue.get_index()
399 if resind
in resindexes_dict[protname]:
402 resindexes_dict[protname].append(resind)
403 rt = residue.get_residue_type()
406 geometric_center[0] += xyz[0]
407 geometric_center[1] += xyz[1]
408 geometric_center[2] += xyz[2]
410 particle_infos_for_pdb.append(
411 (xyz,
None, rt, self.dictchain[name][protname], resind,
416 resind = resindexes[len(resindexes) // 2]
417 if resind
in resindexes_dict[protname]:
420 resindexes_dict[protname].append(resind)
424 geometric_center[0] += xyz[0]
425 geometric_center[1] += xyz[1]
426 geometric_center[2] += xyz[2]
428 particle_infos_for_pdb.append(
429 (xyz,
None, rt, self.dictchain[name][protname], resind,
436 if len(resindexes) > 0:
437 resind = resindexes[len(resindexes) // 2]
440 geometric_center[0] += xyz[0]
441 geometric_center[1] += xyz[1]
442 geometric_center[2] += xyz[2]
444 particle_infos_for_pdb.append(
445 (xyz,
None, rt, self.dictchain[name][protname],
446 resind, resindexes, radius))
449 geometric_center = (geometric_center[0] / atom_count,
450 geometric_center[1] / atom_count,
451 geometric_center[2] / atom_count)
455 particle_infos_for_pdb = sorted(particle_infos_for_pdb,
456 key=
lambda x: (len(x[3]), x[3], x[4]))
458 return (particle_infos_for_pdb, geometric_center)
460 def write_pdbs(self, appendmode=True, mmcif=False):
461 for pdb
in self.dictionary_pdbs.keys():
462 self.write_pdb(pdb, appendmode)
465 replica_exchange=
False, mmcif=
False,
466 best_score_file=
'best.scores.rex.py'):
467 """Prepare for writing best-scoring PDBs (or mmCIFs) for a
470 @param prefix Initial part of each PDB filename (e.g. 'model').
471 @param prot The top-level Hierarchy to output.
472 @param nbestscoring The number of best-scoring files to output.
473 @param replica_exchange Whether to combine best scores from a
474 replica exchange run.
475 @param mmcif If True, output models in mmCIF format. If False
476 (the default) output in legacy PDB format.
477 @param best_score_file The filename to use for replica
481 self._pdb_best_scoring_mmcif = mmcif
482 fileext =
'.cif' if mmcif
else '.pdb'
483 self.prefixes.append(prefix)
484 self.replica_exchange = replica_exchange
485 if not self.replica_exchange:
489 self.best_score_list = []
493 self.best_score_file_name = best_score_file
494 self.best_score_list = []
495 with open(self.best_score_file_name,
"w")
as best_score_file:
496 best_score_file.write(
497 "self.best_score_list=" + str(self.best_score_list) +
"\n")
499 self.nbestscoring = nbestscoring
500 for i
in range(self.nbestscoring):
501 name = prefix +
"." + str(i) + fileext
502 flpdb = open(name,
'w')
504 self.dictionary_pdbs[name] = prot
505 self._pdb_mmcif[name] = mmcif
506 self._init_dictchain(name, prot, mmcif=mmcif)
508 def write_pdb_best_scoring(self, score):
509 if self.nbestscoring
is None:
510 print(
"Output.write_pdb_best_scoring: init_pdb_best_scoring "
513 mmcif = self._pdb_best_scoring_mmcif
514 fileext =
'.cif' if mmcif
else '.pdb'
516 if self.replica_exchange:
518 with open(self.best_score_file_name)
as fh:
519 self.best_score_list = ast.literal_eval(
520 fh.read().split(
'=')[1])
522 if len(self.best_score_list) < self.nbestscoring:
523 self.best_score_list.append(score)
524 self.best_score_list.sort()
525 index = self.best_score_list.index(score)
526 for prefix
in self.prefixes:
527 for i
in range(len(self.best_score_list) - 2, index - 1, -1):
528 oldname = prefix +
"." + str(i) + fileext
529 newname = prefix +
"." + str(i + 1) + fileext
531 if os.path.exists(newname):
533 os.rename(oldname, newname)
534 filetoadd = prefix +
"." + str(index) + fileext
535 self.write_pdb(filetoadd, appendmode=
False)
538 if score < self.best_score_list[-1]:
539 self.best_score_list.append(score)
540 self.best_score_list.sort()
541 self.best_score_list.pop(-1)
542 index = self.best_score_list.index(score)
543 for prefix
in self.prefixes:
544 for i
in range(len(self.best_score_list) - 1,
546 oldname = prefix +
"." + str(i) + fileext
547 newname = prefix +
"." + str(i + 1) + fileext
548 os.rename(oldname, newname)
549 filenametoremove = prefix + \
550 "." + str(self.nbestscoring) + fileext
551 os.remove(filenametoremove)
552 filetoadd = prefix +
"." + str(index) + fileext
553 self.write_pdb(filetoadd, appendmode=
False)
555 if self.replica_exchange:
557 with open(self.best_score_file_name,
"w")
as best_score_file:
558 best_score_file.write(
559 "self.best_score_list=" + str(self.best_score_list) +
'\n')
561 def init_rmf(self, name, hierarchies, rs=None, geometries=None,
564 Initialize an RMF file
566 @param name the name of the RMF file
567 @param hierarchies the hierarchies to be included (it is a list)
568 @param rs optional, the restraint sets (it is a list)
569 @param geometries optional, the geometries (it is a list)
570 @param listofobjects optional, the list of objects for the stat
573 rh = RMF.create_rmf_file(name)
576 outputkey_rmfkey =
None
580 if geometries
is not None:
583 callable_objects = []
584 if listofobjects
is not None:
585 cat = rh.get_category(
"stat")
586 outputkey_rmfkey = {}
587 for o
in listofobjects:
588 if not hasattr(o,
"get_output"):
590 "Output: object %s doesn't have get_output() method"
594 output = o.get_output()
596 callable_objects.append(output)
597 output = output(
None)
599 dict_objects.append(o)
600 for outputkey
in output:
601 rmftag = RMF.string_tag
602 if isinstance(output[outputkey], float):
603 rmftag = RMF.float_tag
604 elif isinstance(output[outputkey], int):
606 elif isinstance(output[outputkey], str):
607 rmftag = RMF.string_tag
609 rmftag = RMF.string_tag
610 rmfkey = rh.get_key(cat, outputkey, rmftag)
611 outputkey_rmfkey[outputkey] = rmfkey
612 outputkey_rmfkey[
"rmf_file"] = \
613 rh.get_key(cat,
"rmf_file", RMF.string_tag)
614 outputkey_rmfkey[
"rmf_frame_index"] = \
615 rh.get_key(cat,
"rmf_frame_index", RMF.int_tag)
617 self.dictionary_rmfs[name] = (rh, cat, outputkey_rmfkey,
618 dict_objects, callable_objects)
620 def add_restraints_to_rmf(self, name, objectlist):
621 for o
in _flatten(objectlist):
623 rs = o.get_restraint_for_rmf()
624 if not isinstance(rs, (list, tuple)):
627 rs = [o.get_restraint()]
629 self.dictionary_rmfs[name][0], rs)
631 def add_geometries_to_rmf(self, name, objectlist):
633 geos = o.get_geometries()
636 def add_particle_pair_from_restraints_to_rmf(self, name, objectlist):
639 pps = o.get_particle_pairs()
642 self.dictionary_rmfs[name][0],
645 def write_rmf(self, name):
647 if self.dictionary_rmfs[name][1]
is not None:
648 outputkey_rmfkey = self.dictionary_rmfs[name][2]
649 dict_objects = self.dictionary_rmfs[name][3]
650 callable_objects = self.dictionary_rmfs[name][4]
653 for obj
in dict_objects:
654 yield obj.get_output()
655 for obj
in callable_objects:
658 for output
in all_output():
659 for outputkey
in output:
660 rmfkey = outputkey_rmfkey[outputkey]
662 n = self.dictionary_rmfs[name][0].get_root_node()
663 n.set_value(rmfkey, output[outputkey])
664 except NotImplementedError:
666 rmfkey = outputkey_rmfkey[
"rmf_file"]
667 self.dictionary_rmfs[name][0].get_root_node().set_value(
669 rmfkey = outputkey_rmfkey[
"rmf_frame_index"]
671 self.dictionary_rmfs[name][0].get_root_node().set_value(
673 self.dictionary_rmfs[name][0].flush()
675 def close_rmf(self, name):
676 rh = self.dictionary_rmfs[name][0]
677 del self.dictionary_rmfs[name]
680 def write_rmfs(self):
681 for rmfinfo
in self.dictionary_rmfs.keys():
682 self.write_rmf(rmfinfo[0])
684 def set_output_entry(self, key, value):
685 self.initoutput.update({key: value})
687 def get_stat(self, name):
689 for obj
in self.dictionary_stats[name]:
690 output.update(obj.get_output())
693 def write_test(self, name, listofobjects):
694 flstat = open(name,
'w')
695 output = self.initoutput
696 for o
in listofobjects:
697 if (
not hasattr(o,
"get_test_output")
698 and not hasattr(o,
"get_output")):
700 "Output: object %s doesn't have get_output() or "
701 "get_test_output() method" % str(o))
702 self.dictionary_stats[name] = listofobjects
704 for obj
in self.dictionary_stats[name]:
706 d = obj.get_test_output()
707 except AttributeError:
713 dfiltered = dict((k, v)
for k, v
in d.items()
if k[0] !=
"_")
714 output.update(dfiltered)
715 flstat.write(
"%s \n" % output)
718 def test(self, name, listofobjects, tolerance=1e-5):
719 output = self.initoutput
720 for o
in listofobjects:
721 if (
not hasattr(o,
"get_test_output")
722 and not hasattr(o,
"get_output")):
724 "Output: object %s doesn't have get_output() or "
725 "get_test_output() method" % str(o))
726 for obj
in listofobjects:
728 out = obj.get_test_output()
729 except AttributeError:
730 out = obj.get_output()
736 flstat = open(name,
'r')
740 test_dict = ast.literal_eval(fl)
743 old_value = str(test_dict[k])
744 new_value = str(output[k])
752 fold = float(old_value)
753 fnew = float(new_value)
754 diff = abs(fold - fnew)
756 print(
"%s: test failed, old value: %s new value %s; "
757 "diff %f > %f" % (str(k), str(old_value),
758 str(new_value), diff,
759 tolerance), file=sys.stderr)
761 elif test_dict[k] != output[k]:
762 if len(old_value) < 50
and len(new_value) < 50:
763 print(
"%s: test failed, old value: %s new value %s"
764 % (str(k), old_value, new_value),
768 print(
"%s: test failed, omitting results (too long)"
769 % str(k), file=sys.stderr)
773 print(
"%s from old objects (file %s) not in new objects"
774 % (str(k), str(name)), file=sys.stderr)
778 def get_environment_variables(self):
780 return str(os.environ)
782 def get_versions_of_relevant_modules(self):
789 versions[
"ISD2_VERSION"] = IMP.isd2.get_module_version()
794 versions[
"ISD_EMXL_VERSION"] = IMP.isd_emxl.get_module_version()
800 listofsummedobjects=
None, jax_model=
None, append=
False):
801 """Write the header for a stat file in v2 format.
802 Lines can then be written to the stat file by calling write_stat2()
803 with the same file name.
805 @param name The file name to write to.
806 @param listofobjects PMI objects that will be reported in the file.
807 Each object must implement the get_output() method.
808 This can either return a dict containing data from the
809 current state of the model, or a callable which returns
810 a similar dict of data each time it is called.
818 if listofsummedobjects
is None:
819 listofsummedobjects = []
820 if extralabels
is None:
823 stat2_keywords = {
"STAT2HEADER":
"STAT2HEADER"}
824 stat2_keywords.update(
825 {
"STAT2HEADER_ENVIRON": str(self.get_environment_variables())})
826 stat2_keywords.update(
827 {
"STAT2HEADER_IMP_VERSIONS":
828 str(self.get_versions_of_relevant_modules())})
832 callable_objects = []
833 for obj
in listofobjects:
834 if not hasattr(obj,
"get_output"):
836 "Output: object %s doesn't have get_output() method"
843 callable_objects.append(d)
846 dict_objects.append(obj)
848 dfiltered = dict((k, v)
849 for k, v
in d.items()
if k[0] !=
"_")
850 output.update(dfiltered)
853 for obj
in listofsummedobjects:
855 if not hasattr(t,
"get_output"):
857 "Output: object %s doesn't have get_output() method"
860 if "_TotalScore" not in t.get_output():
862 "Output: object %s doesn't have _TotalScore "
863 "entry to be summed" % str(t))
865 output.update({obj[1]: 0.0})
867 for k
in extralabels:
868 output.update({k: 0.0})
870 for n, k
in enumerate(output):
871 stat2_keywords.update({n: k})
872 stat2_inverse.update({k: n})
875 self._check_append_header(name, stat2_keywords)
877 with open(name,
'w')
as flstat:
878 flstat.write(
"%s \n" % stat2_keywords)
880 self.dictionary_stats2[name] = (
881 dict_objects, callable_objects,
886 def _check_append_header(self, name, stat2_keywords):
887 """Verify that existing file header matches our data structure"""
888 with open(name)
as flstat:
889 header = flstat.readline()
890 d = ast.literal_eval(header)
891 if not isinstance(d, dict)
or 'STAT2HEADER' not in d:
893 f
"stat file {name} first line is not a valid header")
894 d = {k: v
for (k, v)
in d.items()
if isinstance(k, int)}
895 newd = {k: v
for (k, v)
in stat2_keywords.items()
896 if isinstance(k, int)}
899 f
"stat file {name} header does not match append data")
901 def _count_stat2_nframe(self, name, nframe_key, nframe):
902 """Count the number of stat file lines up to the given frame"""
903 with open(name,
"r") as flstat:
904 header = flstat.readline()
905 d = ast.literal_eval(header)
906 keymap = {v: k for (k, v)
in d.items()
if isinstance(k, int)}
907 nframe_key = keymap[nframe_key]
910 line = flstat.readline()
914 nframe_file = int(ast.literal_eval(line)[nframe_key])
915 if nframe_file >= nframe:
918 def _truncate_stat2_nline(self, name, nline):
919 """Truncate the given stat file to have exactly `nline` non-header
923 with open(name,
"rb+")
as flstat:
924 _ = flstat.readline()
925 for _
in range(nline):
926 _ = flstat.readline()
927 flstat.truncate(flstat.tell())
930 """Write a single line to a stat file previously created
933 @param name The file name to write to.
936 (dict_objects, callable_objects, stat2_inverse, listofsummedobjects,
937 extralabels) = self.dictionary_stats2[name]
940 for obj
in dict_objects:
941 yield obj.get_output()
942 for obj
in callable_objects:
946 for od
in all_output():
947 dfiltered = dict((k, v)
for k, v
in od.items()
if k[0] !=
"_")
949 output.update({stat2_inverse[k]: od[k]})
952 for so
in listofsummedobjects:
956 partial_score += float(d[
"_TotalScore"])
957 output.update({stat2_inverse[so[1]]: str(partial_score)})
960 for k
in extralabels:
961 if k
in self.initoutput:
962 output.update({stat2_inverse[k]: self.initoutput[k]})
964 output.update({stat2_inverse[k]:
"None"})
966 with open(name,
'a' if appendmode
else 'w')
as flstat:
967 flstat.write(
"%s \n" % output)
969 def write_stats2(self):
970 for stat
in self.dictionary_stats2.keys():
975 """Collect statistics from ProcessOutput.get_fields().
976 Counters of the total number of frames read, plus the models that
977 passed the various filters used in get_fields(), are provided."""
980 self.passed_get_every = 0
981 self.passed_filterout = 0
982 self.passed_filtertuple = 0
986 """A class for reading stat files (either rmf or ascii v1 and v2)"""
987 def __init__(self, filename):
988 self.filename = filename
993 if self.filename
is None:
994 raise ValueError(
"No file name provided. Use -h for help")
998 rh = RMF.open_rmf_file_read_only(self.filename)
1000 cat = rh.get_category(
'stat')
1001 rmf_klist = rh.get_keys(cat)
1002 self.rmf_names_keys = dict([(rh.get_name(k), k)
1003 for k
in rmf_klist])
1007 f = open(self.filename,
"r")
1010 for line
in f.readlines():
1011 d = ast.literal_eval(line)
1012 self.klist = list(d.keys())
1014 if "STAT2HEADER" in self.klist:
1016 for k
in self.klist:
1017 if "STAT2HEADER" in str(k):
1023 for k
in sorted(stat2_dict.items(),
1024 key=operator.itemgetter(1))]
1026 for k
in sorted(stat2_dict.items(),
1027 key=operator.itemgetter(1))]
1028 self.invstat2_dict = {}
1030 self.invstat2_dict.update({stat2_dict[k]: k})
1033 "statfile v1 is deprecated. "
1034 "Please convert to statfile v2.\n")
1043 return sorted(self.rmf_names_keys.keys())
1047 def show_keys(self, ncolumns=2, truncate=65):
1048 IMP.pmi.tools.print_multicolumn(self.get_keys(), ncolumns, truncate)
1050 def get_fields(self, fields, filtertuple=None, filterout=None, get_every=1,
1053 Get the desired field names, and return a dictionary.
1054 Namely, "fields" are the queried keys in the stat file
1055 (eg. ["Total_Score",...])
1056 The returned data structure is a dictionary, where each key is
1057 a field and the value is the time series (ie, frame ordered series)
1058 of that field (ie, {"Total_Score":[Score_0,Score_1,Score_2,,...],....})
1060 @param fields (list of strings) queried keys in the stat file
1061 (eg. "Total_Score"....)
1062 @param filterout specify if you want to "grep" out something from
1063 the file, so that it is faster
1064 @param filtertuple a tuple that contains
1065 ("TheKeyToBeFiltered",relationship,value)
1066 where relationship = "<", "==", or ">"
1067 @param get_every only read every Nth line from the file
1068 @param statistics if provided, accumulate statistics in an
1069 OutputStatistics object
1072 if statistics
is None:
1075 for field
in fields:
1080 rh = RMF.open_rmf_file_read_only(self.filename)
1081 nframes = rh.get_number_of_frames()
1082 for i
in range(nframes):
1083 statistics.total += 1
1085 statistics.passed_get_every += 1
1086 statistics.passed_filterout += 1
1087 rh.set_current_frame(RMF.FrameID(i))
1088 if filtertuple
is not None:
1089 keytobefiltered = filtertuple[0]
1090 relationship = filtertuple[1]
1091 value = filtertuple[2]
1092 datavalue = rh.get_root_node().get_value(
1093 self.rmf_names_keys[keytobefiltered])
1094 if self.isfiltered(datavalue, relationship, value):
1097 statistics.passed_filtertuple += 1
1098 for field
in fields:
1099 outdict[field].append(rh.get_root_node().get_value(
1100 self.rmf_names_keys[field]))
1103 f = open(self.filename,
"r")
1106 for line
in f.readlines():
1107 statistics.total += 1
1108 if filterout
is not None:
1109 if filterout
in line:
1111 statistics.passed_filterout += 1
1114 if line_number % get_every != 0:
1115 if line_number == 1
and self.isstat2:
1116 statistics.total -= 1
1117 statistics.passed_filterout -= 1
1119 statistics.passed_get_every += 1
1121 d = ast.literal_eval(line)
1123 print(
"# Warning: skipped line number " + str(line_number)
1124 +
" not a valid line")
1129 if filtertuple
is not None:
1130 keytobefiltered = filtertuple[0]
1131 relationship = filtertuple[1]
1132 value = filtertuple[2]
1133 datavalue = d[keytobefiltered]
1134 if self.isfiltered(datavalue, relationship, value):
1137 statistics.passed_filtertuple += 1
1138 [outdict[field].append(d[field])
for field
in fields]
1141 if line_number == 1:
1142 statistics.total -= 1
1143 statistics.passed_filterout -= 1
1144 statistics.passed_get_every -= 1
1147 if filtertuple
is not None:
1148 keytobefiltered = filtertuple[0]
1149 relationship = filtertuple[1]
1150 value = filtertuple[2]
1151 datavalue = d[self.invstat2_dict[keytobefiltered]]
1152 if self.isfiltered(datavalue, relationship, value):
1155 statistics.passed_filtertuple += 1
1156 [outdict[field].append(d[self.invstat2_dict[field]])
1157 for field
in fields]
1163 def isfiltered(self, datavalue, relationship, refvalue):
1166 _ = float(datavalue)
1168 raise ValueError(
"ProcessOutput.filter: datavalue cannot be "
1169 "converted into a float")
1171 if relationship ==
"<":
1172 if float(datavalue) >= refvalue:
1174 if relationship ==
">":
1175 if float(datavalue) <= refvalue:
1177 if relationship ==
"==":
1178 if float(datavalue) != refvalue:
1184 """ class to allow more advanced handling of RMF files.
1185 It is both a container and a IMP.atom.Hierarchy.
1186 - it is iterable (while loading the corresponding frame)
1187 - Item brackets [] load the corresponding frame
1188 - slice create an iterator
1189 - can relink to another RMF file
1193 @param model: the IMP.Model()
1194 @param rmf_file_name: str, path of the rmf file
1198 self.rh_ref = RMF.open_rmf_file_read_only(rmf_file_name)
1200 raise TypeError(
"Wrong rmf file name or type: %s"
1201 % str(rmf_file_name))
1204 self.root_hier_ref = hs[0]
1205 super().
__init__(self.root_hier_ref)
1207 self.ColorHierarchy =
None
1211 Link to another RMF file
1213 self.rh_ref = RMF.open_rmf_file_read_only(rmf_file_name)
1215 if self.ColorHierarchy:
1216 self.ColorHierarchy.method()
1217 RMFHierarchyHandler.set_frame(self, 0)
1219 def set_frame(self, index):
1223 print(
"skipping frame %s:%d\n" % (self.current_rmf, index))
1227 return self.rh_ref.get_number_of_frames()
1229 def __getitem__(self, int_slice_adaptor):
1230 if isinstance(int_slice_adaptor, int):
1231 self.set_frame(int_slice_adaptor)
1232 return int_slice_adaptor
1233 elif isinstance(int_slice_adaptor, slice):
1234 return self.__iter__(int_slice_adaptor)
1236 raise TypeError(
"Unknown Type")
1239 return self.get_number_of_frames()
1241 def __iter__(self, slice_key=None):
1242 if slice_key
is None:
1243 for nframe
in range(len(self)):
1246 for nframe
in list(range(len(self)))[slice_key]:
1250 class CacheHierarchyCoordinates:
1251 def __init__(self, StatHierarchyHandler):
1258 self.current_index =
None
1259 self.rmfh = StatHierarchyHandler
1261 self.model = self.rmfh.get_model()
1266 self.nrms.append(nrm)
1269 self.xyzs.append(fb)
1271 def do_store(self, index):
1272 self.rb_trans[index] = {}
1273 self.nrm_coors[index] = {}
1274 self.xyz_coors[index] = {}
1276 self.rb_trans[index][rb] = rb.get_reference_frame()
1277 for nrm
in self.nrms:
1278 self.nrm_coors[index][nrm] = nrm.get_internal_coordinates()
1279 for xyz
in self.xyzs:
1280 self.xyz_coors[index][xyz] = xyz.get_coordinates()
1281 self.current_index = index
1283 def do_update(self, index):
1284 if self.current_index != index:
1286 rb.set_reference_frame(self.rb_trans[index][rb])
1287 for nrm
in self.nrms:
1288 nrm.set_internal_coordinates(self.nrm_coors[index][nrm])
1289 for xyz
in self.xyzs:
1290 xyz.set_coordinates(self.xyz_coors[index][xyz])
1291 self.current_index = index
1295 return len(self.rb_trans.keys())
1297 def __getitem__(self, index):
1298 if isinstance(index, int):
1299 return index
in self.rb_trans.keys()
1301 raise TypeError(
"Unknown Type")
1304 return self.get_number_of_frames()
1308 """ class to link stat files to several rmf files """
1309 def __init__(self, model=None, stat_file=None,
1310 number_best_scoring_models=
None, score_key=
None,
1311 StatHierarchyHandler=
None, cache=
None):
1314 @param model: IMP.Model()
1315 @param stat_file: either 1) a list or 2) a single stat file names
1316 (either rmfs or ascii, or pickled data or pickled cluster),
1317 3) a dictionary containing an rmf/ascii
1318 stat file name as key and a list of frames as values
1319 @param number_best_scoring_models:
1320 @param StatHierarchyHandler: copy constructor input object
1321 @param cache: cache coordinates and rigid body transformations.
1324 if StatHierarchyHandler
is not None:
1328 self.model = StatHierarchyHandler.model
1329 self.data = StatHierarchyHandler.data
1330 self.number_best_scoring_models = \
1331 StatHierarchyHandler.number_best_scoring_models
1332 self.is_setup =
True
1333 self.current_rmf = StatHierarchyHandler.current_rmf
1334 self.current_frame =
None
1335 self.current_index =
None
1336 self.score_threshold = StatHierarchyHandler.score_threshold
1337 self.score_key = StatHierarchyHandler.score_key
1338 self.cache = StatHierarchyHandler.cache
1339 super().
__init__(self.model, self.current_rmf)
1341 self.cache = CacheHierarchyCoordinates(self)
1350 self.number_best_scoring_models = number_best_scoring_models
1353 if score_key
is None:
1354 self.score_key =
"Total_Score"
1356 self.score_key = score_key
1357 self.is_setup =
None
1358 self.current_rmf =
None
1359 self.current_frame =
None
1360 self.current_index =
None
1361 self.score_threshold =
None
1363 if isinstance(stat_file, str):
1364 self.add_stat_file(stat_file)
1365 elif isinstance(stat_file, list):
1367 self.add_stat_file(f)
1369 def add_stat_file(self, stat_file):
1371 '''check that it is not a pickle file with saved data
1372 from a previous calculation'''
1373 self.load_data(stat_file)
1375 if self.number_best_scoring_models:
1376 scores = self.get_scores()
1377 max_score = sorted(scores)[
1378 0:min(len(self), self.number_best_scoring_models)][-1]
1379 self.do_filter_by_score(max_score)
1381 except pickle.UnpicklingError:
1382 '''alternatively read the ascii stat files'''
1384 scores, rmf_files, rmf_frame_indexes, features = \
1385 self.get_info_from_stat_file(stat_file,
1386 self.score_threshold)
1387 except (KeyError, SyntaxError):
1392 rh = RMF.open_rmf_file_read_only(stat_file)
1393 nframes = rh.get_number_of_frames()
1394 scores = [0.0]*nframes
1395 rmf_files = [stat_file]*nframes
1396 rmf_frame_indexes = range(nframes)
1401 if len(set(rmf_files)) > 1:
1402 raise (
"Multiple RMF files found")
1405 print(
"StatHierarchyHandler: Error: Trying to set none as "
1406 "rmf_file (probably empty stat file), aborting")
1409 for n, index
in enumerate(rmf_frame_indexes):
1410 featn_dict = dict([(k, features[k][n])
for k
in features])
1412 stat_file, rmf_files[n], index, scores[n], featn_dict))
1414 if self.number_best_scoring_models:
1415 scores = self.get_scores()
1416 max_score = sorted(scores)[
1417 0:min(len(self), self.number_best_scoring_models)][-1]
1418 self.do_filter_by_score(max_score)
1420 if not self.is_setup:
1421 RMFHierarchyHandler.__init__(
1422 self, self.model, self.get_rmf_names()[0])
1424 self.cache = CacheHierarchyCoordinates(self)
1427 self.is_setup =
True
1428 self.current_rmf = self.get_rmf_names()[0]
1432 def save_data(self, filename='data.pkl'):
1433 with open(filename,
'wb')
as fl:
1434 pickle.dump(self.data, fl)
1436 def load_data(self, filename='data.pkl'):
1437 with open(filename,
'rb')
as fl:
1438 data_structure = pickle.load(fl)
1440 if not isinstance(data_structure, list):
1442 "%filename should contain a list of IMP.pmi.output.DataEntry "
1443 "or IMP.pmi.output.Cluster" % filename)
1446 for item
in data_structure):
1447 self.data = data_structure
1449 for item
in data_structure):
1451 for cluster
in data_structure:
1452 nmodels += len(cluster)
1453 self.data = [
None]*nmodels
1454 for cluster
in data_structure:
1455 for n, data
in enumerate(cluster):
1456 index = cluster.members[n]
1457 self.data[index] = data
1460 "%filename should contain a list of IMP.pmi.output.DataEntry "
1461 "or IMP.pmi.output.Cluster" % filename)
1463 def set_frame(self, index):
1464 if self.cache
is not None and self.cache[index]:
1465 self.cache.do_update(index)
1467 nm = self.data[index].rmf_name
1468 fidx = self.data[index].rmf_index
1469 if nm != self.current_rmf:
1471 self.current_rmf = nm
1472 self.current_frame = -1
1473 if fidx != self.current_frame:
1474 RMFHierarchyHandler.set_frame(self, fidx)
1475 self.current_frame = fidx
1476 if self.cache
is not None:
1477 self.cache.do_store(index)
1479 self.current_index = index
1481 def __getitem__(self, int_slice_adaptor):
1482 if isinstance(int_slice_adaptor, int):
1483 self.set_frame(int_slice_adaptor)
1484 return self.data[int_slice_adaptor]
1485 elif isinstance(int_slice_adaptor, slice):
1486 return self.__iter__(int_slice_adaptor)
1488 raise TypeError(
"Unknown Type")
1491 return len(self.data)
1493 def __iter__(self, slice_key=None):
1494 if slice_key
is None:
1495 for i
in range(len(self)):
1498 for i
in range(len(self))[slice_key]:
1501 def do_filter_by_score(self, maximum_score):
1502 self.data = [d
for d
in self.data
if d.score <= maximum_score]
1504 def get_scores(self):
1505 return [d.score
for d
in self.data]
1507 def get_feature_series(self, feature_name):
1508 return [d.features[feature_name]
for d
in self.data]
1510 def get_feature_names(self):
1511 return self.data[0].features.keys()
1513 def get_rmf_names(self):
1514 return [d.rmf_name
for d
in self.data]
1516 def get_stat_files_names(self):
1517 return [d.stat_file
for d
in self.data]
1519 def get_rmf_indexes(self):
1520 return [d.rmf_index
for d
in self.data]
1522 def get_info_from_stat_file(self, stat_file, score_threshold=None):
1526 [stat_file], score_key=self.score_key, feature_keys=fs,
1527 rmf_file_key=
"rmf_file", rmf_file_frame_key=
"rmf_frame_index",
1528 prefiltervalue=score_threshold, get_every=1)
1530 scores = [float(y)
for y
in models[2]]
1531 rmf_files = models[0]
1532 rmf_frame_indexes = models[1]
1533 features = models[3]
1534 return scores, rmf_files, rmf_frame_indexes, features
1539 A class to store data associated to a model
1541 def __init__(self, stat_file=None, rmf_name=None, rmf_index=None,
1542 score=
None, features=
None):
1543 self.rmf_name = rmf_name
1544 self.rmf_index = rmf_index
1546 self.features = features
1547 self.stat_file = stat_file
1550 s =
"IMP.pmi.output.DataEntry\n"
1551 s +=
"---- stat file %s \n" % (self.stat_file)
1552 s +=
"---- rmf file %s \n" % (self.rmf_name)
1553 s +=
"---- rmf index %s \n" % (str(self.rmf_index))
1554 s +=
"---- score %s \n" % (str(self.score))
1555 s +=
"---- number of features %s \n" % (str(len(self.features.keys())))
1561 A container for models organized into clusters
1563 def __init__(self, cid=None):
1564 self.cluster_id = cid
1566 self.precision =
None
1567 self.center_index =
None
1568 self.members_data = {}
1570 def add_member(self, index, data=None):
1571 self.members.append(index)
1572 self.members_data[index] = data
1573 self.average_score = self.compute_score()
1575 def compute_score(self):
1577 score = sum([d.score
for d
in self])/len(self)
1578 except AttributeError:
1583 s =
"IMP.pmi.output.Cluster\n"
1584 s +=
"---- cluster_id %s \n" % str(self.cluster_id)
1585 s +=
"---- precision %s \n" % str(self.precision)
1586 s +=
"---- average score %s \n" % str(self.average_score)
1587 s +=
"---- number of members %s \n" % str(len(self.members))
1588 s +=
"---- center index %s \n" % str(self.center_index)
1591 def __getitem__(self, int_slice_adaptor):
1592 if isinstance(int_slice_adaptor, int):
1593 index = self.members[int_slice_adaptor]
1594 return self.members_data[index]
1595 elif isinstance(int_slice_adaptor, slice):
1596 return self.__iter__(int_slice_adaptor)
1598 raise TypeError(
"Unknown Type")
1601 return len(self.members)
1603 def __iter__(self, slice_key=None):
1604 if slice_key
is None:
1605 for i
in range(len(self)):
1608 for i
in range(len(self))[slice_key]:
1611 def __add__(self, other):
1612 self.members += other.members
1613 self.members_data.update(other.members_data)
1614 self.average_score = self.compute_score()
1615 self.precision =
None
1616 self.center_index =
None
1620 def plot_clusters_populations(clusters):
1623 for cluster
in clusters:
1624 indexes.append(cluster.cluster_id)
1625 populations.append(len(cluster))
1627 import matplotlib.pyplot
as plt
1628 fig, ax = plt.subplots()
1629 ax.bar(indexes, populations, 0.5, color=
'r')
1630 ax.set_ylabel('Population')
1631 ax.set_xlabel((
'Cluster index'))
1635 def plot_clusters_precisions(clusters):
1638 for cluster
in clusters:
1639 indexes.append(cluster.cluster_id)
1641 prec = cluster.precision
1642 print(cluster.cluster_id, prec)
1645 precisions.append(prec)
1647 import matplotlib.pyplot
as plt
1648 fig, ax = plt.subplots()
1649 ax.bar(indexes, precisions, 0.5, color=
'r')
1650 ax.set_ylabel('Precision [A]')
1651 ax.set_xlabel((
'Cluster index'))
1655 def plot_clusters_scores(clusters):
1658 for cluster
in clusters:
1659 indexes.append(cluster.cluster_id)
1661 for data
in cluster:
1662 values[-1].append(data.score)
1665 valuename=
"Scores", positionname=
"Cluster index",
1666 xlabels=
None, scale_plot_length=1.0)
1669 class CrossLinkIdentifierDatabase:
1673 def check_key(self, key):
1674 if key
not in self.clidb:
1675 self.clidb[key] = {}
1677 def set_unique_id(self, key, value):
1679 self.clidb[key][
"XLUniqueID"] = str(value)
1681 def set_protein1(self, key, value):
1683 self.clidb[key][
"Protein1"] = str(value)
1685 def set_protein2(self, key, value):
1687 self.clidb[key][
"Protein2"] = str(value)
1689 def set_residue1(self, key, value):
1691 self.clidb[key][
"Residue1"] = int(value)
1693 def set_residue2(self, key, value):
1695 self.clidb[key][
"Residue2"] = int(value)
1697 def set_idscore(self, key, value):
1699 self.clidb[key][
"IDScore"] = float(value)
1701 def set_state(self, key, value):
1703 self.clidb[key][
"State"] = int(value)
1705 def set_sigma1(self, key, value):
1707 self.clidb[key][
"Sigma1"] = str(value)
1709 def set_sigma2(self, key, value):
1711 self.clidb[key][
"Sigma2"] = str(value)
1713 def set_psi(self, key, value):
1715 self.clidb[key][
"Psi"] = str(value)
1717 def get_unique_id(self, key):
1718 return self.clidb[key][
"XLUniqueID"]
1720 def get_protein1(self, key):
1721 return self.clidb[key][
"Protein1"]
1723 def get_protein2(self, key):
1724 return self.clidb[key][
"Protein2"]
1726 def get_residue1(self, key):
1727 return self.clidb[key][
"Residue1"]
1729 def get_residue2(self, key):
1730 return self.clidb[key][
"Residue2"]
1732 def get_idscore(self, key):
1733 return self.clidb[key][
"IDScore"]
1735 def get_state(self, key):
1736 return self.clidb[key][
"State"]
1738 def get_sigma1(self, key):
1739 return self.clidb[key][
"Sigma1"]
1741 def get_sigma2(self, key):
1742 return self.clidb[key][
"Sigma2"]
1744 def get_psi(self, key):
1745 return self.clidb[key][
"Psi"]
1747 def set_float_feature(self, key, value, feature_name):
1749 self.clidb[key][feature_name] = float(value)
1751 def set_int_feature(self, key, value, feature_name):
1753 self.clidb[key][feature_name] = int(value)
1755 def set_string_feature(self, key, value, feature_name):
1757 self.clidb[key][feature_name] = str(value)
1759 def get_feature(self, key, feature_name):
1760 return self.clidb[key][feature_name]
1762 def write(self, filename):
1763 with open(filename,
'wb')
as handle:
1764 pickle.dump(self.clidb, handle)
1766 def load(self, filename):
1767 with open(filename,
'rb')
as handle:
1768 self.clidb = pickle.load(handle)
1772 """Plot the given fields and save a figure as `output`.
1773 The fields generally are extracted from a stat file
1774 using ProcessOutput.get_fields()."""
1775 import matplotlib
as mpl
1777 import matplotlib.pyplot
as plt
1779 plt.rc(
'lines', linewidth=4)
1780 fig, axs = plt.subplots(nrows=len(fields))
1781 fig.set_size_inches(10.5, 5.5 * len(fields))
1786 if framemin
is None:
1788 if framemax
is None:
1789 framemax = len(fields[key])
1790 x = list(range(framemin, framemax))
1791 y = [float(y)
for y
in fields[key][framemin:framemax]]
1794 axs[n].set_title(key, size=
"xx-large")
1795 axs[n].tick_params(labelsize=18, pad=10)
1798 axs.set_title(key, size=
"xx-large")
1799 axs.tick_params(labelsize=18, pad=10)
1803 plt.subplots_adjust(hspace=0.3)
1808 colors=
None, format=
"png", reference_xline=
None,
1809 yplotrange=
None, xplotrange=
None, normalized=
True,
1811 '''Plot a list of histograms from a value list.
1812 @param name the name of the plot
1813 @param values_lists the list of list of values eg: [[...],[...],[...]]
1814 @param valuename the y-label
1815 @param bins the number of bins
1816 @param colors If None, will use rainbow. Else will use specific list
1817 @param format output format
1818 @param reference_xline plot a reference line parallel to the y-axis
1819 @param yplotrange the range for the y-axis
1820 @param normalized whether the histogram is normalized or not
1821 @param leg_names names for the legend
1824 import matplotlib
as mpl
1826 import matplotlib.pyplot
as plt
1827 import matplotlib.cm
as cm
1828 plt.figure(figsize=(18.0, 9.0))
1831 colors = cm.rainbow(np.linspace(0, 1, len(values_lists)))
1832 for nv, values
in enumerate(values_lists):
1834 if leg_names
is not None:
1835 label = leg_names[nv]
1840 [float(y)
for y
in values], bins=bins, color=col,
1841 density=normalized, histtype=
'step', lw=4, label=label)
1842 except AttributeError:
1844 [float(y)
for y
in values], bins=bins, color=col,
1845 normed=normalized, histtype=
'step', lw=4, label=label)
1848 plt.tick_params(labelsize=12, pad=10)
1849 if valuename
is None:
1850 plt.xlabel(name, size=
"xx-large")
1852 plt.xlabel(valuename, size=
"xx-large")
1853 plt.ylabel(
"Frequency", size=
"xx-large")
1855 if yplotrange
is not None:
1857 if xplotrange
is not None:
1858 plt.xlim(xplotrange)
1862 if reference_xline
is not None:
1869 plt.savefig(name +
"." + format, dpi=150, transparent=
True)
1873 valuename=
"None", positionname=
"None",
1874 xlabels=
None, scale_plot_length=1.0):
1876 Plot time series as boxplots.
1877 fields is a list of time series, positions are the x-values
1878 valuename is the y-label, positionname is the x-label
1881 import matplotlib
as mpl
1883 import matplotlib.pyplot
as plt
1886 fig = plt.figure(figsize=(float(len(positions))*scale_plot_length, 5.0))
1887 fig.canvas.manager.set_window_title(name)
1889 ax1 = fig.add_subplot(111)
1891 plt.subplots_adjust(left=0.1, right=0.990, top=0.95, bottom=0.4)
1893 bps.append(plt.boxplot(values, notch=0, sym=
'', vert=1,
1894 whis=1.5, positions=positions))
1896 plt.setp(bps[-1][
'boxes'], color=
'black', lw=1.5)
1897 plt.setp(bps[-1][
'whiskers'], color=
'black', ls=
":", lw=1.5)
1899 if frequencies
is not None:
1900 for n, v
in enumerate(values):
1901 plist = [positions[n]]*len(v)
1902 ax1.plot(plist, v,
'gx', alpha=0.7, markersize=7)
1905 if xlabels
is not None:
1906 ax1.set_xticklabels(xlabels)
1907 plt.xticks(rotation=90)
1908 plt.xlabel(positionname)
1909 plt.ylabel(valuename)
1911 plt.savefig(name +
".pdf", dpi=150)
1915 def plot_xy_data(x, y, title=None, out_fn=None, display=True,
1916 set_plot_yaxis_range=
None, xlabel=
None, ylabel=
None):
1917 import matplotlib
as mpl
1919 import matplotlib.pyplot
as plt
1920 plt.rc(
'lines', linewidth=2)
1922 fig, ax = plt.subplots(nrows=1)
1923 fig.set_size_inches(8, 4.5)
1924 if title
is not None:
1925 fig.canvas.manager.set_window_title(title)
1927 ax.plot(x, y, color=
'r')
1928 if set_plot_yaxis_range
is not None:
1929 x1, x2, y1, y2 = plt.axis()
1930 y1 = set_plot_yaxis_range[0]
1931 y2 = set_plot_yaxis_range[1]
1932 plt.axis((x1, x2, y1, y2))
1933 if title
is not None:
1935 if xlabel
is not None:
1936 ax.set_xlabel(xlabel)
1937 if ylabel
is not None:
1938 ax.set_ylabel(ylabel)
1939 if out_fn
is not None:
1940 plt.savefig(out_fn +
".pdf")
1946 def plot_scatter_xy_data(x, y, labelx="None", labely="None",
1947 xmin=
None, xmax=
None, ymin=
None, ymax=
None,
1948 savefile=
False, filename=
"None.eps", alpha=0.75):
1950 import matplotlib
as mpl
1952 import matplotlib.pyplot
as plt
1953 from matplotlib
import rc
1954 rc(
'font', **{
'family':
'sans-serif',
'sans-serif': [
'Helvetica']})
1956 fig, axs = plt.subplots(1)
1960 axs0.set_xlabel(labelx, size=
"xx-large")
1961 axs0.set_ylabel(labely, size=
"xx-large")
1962 axs0.tick_params(labelsize=18, pad=10)
1966 plot2.append(axs0.plot(x, y,
'o', color=
'k', lw=2, ms=0.1, alpha=alpha,
1976 fig.set_size_inches(8.0, 8.0)
1977 fig.subplots_adjust(left=0.161, right=0.850, top=0.95, bottom=0.11)
1978 if (ymin
is not None)
and (ymax
is not None):
1979 axs0.set_ylim(ymin, ymax)
1980 if (xmin
is not None)
and (xmax
is not None):
1981 axs0.set_xlim(xmin, xmax)
1984 fig.savefig(filename, dpi=300)
1987 def get_graph_from_hierarchy(hier):
1991 (graph, depth, depth_dict) = recursive_graph(
1992 hier, graph, depth, depth_dict)
1995 node_labels_dict = {}
1996 for key
in depth_dict:
1997 if depth_dict[key] < 3:
1998 node_labels_dict[key] = key
2000 node_labels_dict[key] =
""
2001 draw_graph(graph, labels_dict=node_labels_dict)
2004 def recursive_graph(hier, graph, depth, depth_dict):
2007 index = str(hier.get_particle().
get_index())
2008 name1 = nameh +
"|#" + index
2009 depth_dict[name1] = depth
2013 if len(children) == 1
or children
is None:
2015 return (graph, depth, depth_dict)
2019 (graph, depth, depth_dict) = recursive_graph(
2020 c, graph, depth, depth_dict)
2022 index = str(c.get_particle().
get_index())
2023 namec = nameh +
"|#" + index
2024 graph.append((name1, namec))
2027 return (graph, depth, depth_dict)
2030 def draw_graph(graph, labels_dict=None, graph_layout='spring',
2031 node_size=5, node_color=
None, node_alpha=0.3,
2032 node_text_size=11, fixed=
None, pos=
None,
2033 edge_color=
'blue', edge_alpha=0.3, edge_thickness=1,
2035 validation_edges=
None,
2036 text_font=
'sans-serif',
2039 import matplotlib
as mpl
2041 import networkx
as nx
2042 import matplotlib.pyplot
as plt
2043 from math
import sqrt, pi
2049 if isinstance(edge_thickness, list):
2050 for edge, weight
in zip(graph, edge_thickness):
2051 G.add_edge(edge[0], edge[1], weight=weight)
2054 G.add_edge(edge[0], edge[1])
2056 if node_color
is None:
2057 node_color_rgb = (0, 0, 0)
2058 node_color_hex =
"000000"
2063 for node
in G.nodes():
2064 cctuple = cc.rgb(node_color[node])
2065 tmpcolor_rgb.append((cctuple[0]/255,
2068 tmpcolor_hex.append(node_color[node])
2069 node_color_rgb = tmpcolor_rgb
2070 node_color_hex = tmpcolor_hex
2073 if isinstance(node_size, dict):
2075 for node
in G.nodes():
2076 size = sqrt(node_size[node])/pi*10.0
2077 tmpsize.append(size)
2080 for n, node
in enumerate(G.nodes()):
2081 color = node_color_hex[n]
2083 nx.set_node_attributes(
2085 {node: {
'type':
'ellipse',
'w': size,
'h': size,
2086 'fill':
'#' + color,
'label': node}})
2087 nx.set_node_attributes(
2089 {node: {
'type':
'text',
'text': node,
'color':
'#000000',
2090 'visible':
'true'}})
2092 for edge
in G.edges():
2093 nx.set_edge_attributes(
2095 {edge: {
'width': 1,
'fill':
'#000000'}})
2097 for ve
in validation_edges:
2099 if (ve[0], ve[1])
in G.edges():
2100 print(
"found forward")
2101 nx.set_edge_attributes(
2103 {ve: {
'width': 1,
'fill':
'#00FF00'}})
2104 elif (ve[1], ve[0])
in G.edges():
2105 print(
"found backward")
2106 nx.set_edge_attributes(
2108 {(ve[1], ve[0]): {
'width': 1,
'fill':
'#00FF00'}})
2110 G.add_edge(ve[0], ve[1])
2112 nx.set_edge_attributes(
2114 {ve: {
'width': 1,
'fill':
'#FF0000'}})
2118 if graph_layout ==
'spring':
2120 graph_pos = nx.spring_layout(G, k=1.0/8.0, fixed=fixed, pos=pos)
2121 elif graph_layout ==
'spectral':
2122 graph_pos = nx.spectral_layout(G)
2123 elif graph_layout ==
'random':
2124 graph_pos = nx.random_layout(G)
2126 graph_pos = nx.shell_layout(G)
2129 nx.draw_networkx_nodes(G, graph_pos, node_size=node_size,
2130 alpha=node_alpha, node_color=node_color_rgb,
2132 nx.draw_networkx_edges(G, graph_pos, width=edge_thickness,
2133 alpha=edge_alpha, edge_color=edge_color)
2134 nx.draw_networkx_labels(
2135 G, graph_pos, labels=labels_dict, font_size=node_text_size,
2136 font_family=text_font)
2138 plt.savefig(out_filename)
2139 nx.write_gml(G,
'out.gml')
2147 from ipyD3
import d3object
2148 from IPython.display
import display
2150 d3 = d3object(width=800,
2155 title=
'Example table with d3js',
2156 desc=
'An example table created created with d3js with '
2157 'data generated with Python.')
2158 data = [[1277.0, 654.0, 288.0, 1976.0, 3281.0, 3089.0, 10336.0, 4650.0,
2159 4441.0, 4670.0, 944.0, 110.0],
2160 [1318.0, 664.0, 418.0, 1952.0, 3581.0, 4574.0, 11457.0, 6139.0,
2161 7078.0, 6561.0, 2354.0, 710.0],
2162 [1783.0, 774.0, 564.0, 1470.0, 3571.0, 3103.0, 9392.0, 5532.0,
2163 5661.0, 4991.0, 2032.0, 680.0],
2164 [1301.0, 604.0, 286.0, 2152.0, 3282.0, 3369.0, 10490.0, 5406.0,
2165 4727.0, 3428.0, 1559.0, 620.0],
2166 [1537.0, 1714.0, 724.0, 4824.0, 5551.0, 8096.0, 16589.0, 13650.0,
2167 9552.0, 13709.0, 2460.0, 720.0],
2168 [5691.0, 2995.0, 1680.0, 11741.0, 16232.0, 14731.0, 43522.0,
2169 32794.0, 26634.0, 31400.0, 7350.0, 3010.0],
2170 [1650.0, 2096.0, 60.0, 50.0, 1180.0, 5602.0, 15728.0, 6874.0,
2171 5115.0, 3510.0, 1390.0, 170.0],
2172 [72.0, 60.0, 60.0, 10.0, 120.0, 172.0, 1092.0, 675.0, 408.0,
2173 360.0, 156.0, 100.0]]
2174 data = [list(i)
for i
in zip(*data)]
2175 sRows = [[
'January',
2187 sColumns = [[
'Prod {0}'.format(i)
for i
in range(1, 9)],
2188 [
None,
'',
None,
None,
'Group 1',
None,
None,
'Group 2']]
2189 d3.addSimpleTable(data,
2190 fontSizeCells=[12, ],
2193 sRowsMargins=[5, 50, 0],
2194 sColsMargins=[5, 20, 10],
2197 addOutsideBorders=-1,
2201 html = d3.render(mode=[
'html',
'show'])
static bool get_is_setup(const IMP::ParticleAdaptor &p)
A container for models organized into clusters.
A class for reading stat files (either rmf or ascii v1 and v2)
atom::Hierarchies create_hierarchies(RMF::FileConstHandle fh, Model *m)
RMF::FrameID save_frame(RMF::FileHandle file, std::string name="")
Save the current state of the linked objects as a new RMF frame.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
def plot_field_histogram
Plot a list of histograms from a value list.
def plot_fields_box_plots
Plot time series as boxplots.
Utility classes and functions for reading and storing PMI files.
def get_best_models
Given a list of stat files, read them all and find the best models.
A class to store data associated to a model.
void handle_use_deprecated(std::string message)
Break in this method in gdb to find deprecated uses at runtime.
std::string get_module_version()
Return the version of this module, as a string.
void write_pdb(const Selection &mhd, TextOutput out, unsigned int model=1)
Collect statistics from ProcessOutput.get_fields().
static bool get_is_setup(const IMP::ParticleAdaptor &p)
def get_fields
Get the desired field names, and return a dictionary.
Warning related to handling of structures.
static bool get_is_setup(Model *m, ParticleIndex pi)
def link_to_rmf
Link to another RMF file.
std::string get_molecule_name_and_copy(atom::Hierarchy h)
Walk up a PMI2 hierarchy/representations and get the "molname.copynum".
The standard decorator for manipulating molecular structures.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
def init_pdb
Init PDB Writing.
int get_number_of_frames(const ::npctransport_proto::Assignment &config, double time_step)
A decorator for a particle representing an atom.
Base class for capturing a modeling protocol.
def write_stat2
Write a single line to a stat file previously created with init_stat2().
void load_frame(RMF::FileConstHandle file, RMF::FrameID frame)
Load the given RMF frame into the state of the linked objects.
A decorator for a particle with x,y,z coordinates.
void add_hierarchies(RMF::NodeHandle fh, const atom::Hierarchies &hs)
Class for easy writing of PDBs, RMFs, and stat files.
void add_geometries(RMF::NodeHandle parent, const display::GeometriesTemp &r)
Add geometries to a given parent node.
void add_restraints(RMF::NodeHandle fh, const Restraints &hs)
A decorator for a particle that is part of a rigid body but not rigid.
Display a segment connecting a pair of particles.
A decorator for a residue.
Basic functionality that is expected to be used by a wide variety of IMP users.
def get_pdb_names
Get a list of all PDB files being output by this instance.
def get_prot_name_from_particle
Get the protein name from the particle.
class to link stat files to several rmf files
class to allow more advanced handling of RMF files.
void link_hierarchies(RMF::FileConstHandle fh, const atom::Hierarchies &hs)
def plot_fields
Plot the given fields and save a figure as output.
void add_geometry(RMF::FileHandle file, display::Geometry *r)
Add a single geometry to the file.
Store info for a chain of a protein.
Python classes to represent, score, sample and analyze models.
def init_pdb_best_scoring
Prepare for writing best-scoring PDBs (or mmCIFs) for a sampling run.
Functionality for loading, creating, manipulating and scoring atomic structures.
Select hierarchy particles identified by the biological name.
def init_rmf
Initialize an RMF file.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
def init_stat2
Write the header for a stat file in v2 format.
std::string get_module_version()
Return the version of this module, as a string.
A decorator for a particle with x,y,z coordinates and a radius.