IMP logo
IMP Reference Guide  develop.d97d4ead1f,2024/11/21
The Integrative Modeling Platform
topology.py
1 import IMP
2 import RMF
3 import IMP.atom
4 import IMP.rmf
5 import IMP.pmi
6 import IMP.pmi.analysis
7 import IMP.pmi.output
8 from collections import defaultdict
9 
10 
12  """A class to read RMF files and make a network contact map"""
13  def __init__(self, model, selections, cutoff, frequency_cutoff,
14  colors=None, fixed=None, pos=None, proteomic_edges=None,
15  quantitative_proteomic_data=None):
16  """Set up a new graphXL object
17  @param model The IMP model
18  @param selections A dictionary containing component names.
19  Keys are labels
20  values are either moleculename or
21  start,stop,moleculename
22  @param cutoff The distance cutoff
23  @param frequency_cutoff The frequency cutoff
24  @param colors A dictionary of colors (HEX code,values)
25  for subunits (keywords)
26  @param fixed A list of subunits that are kept fixed
27  @param pos A dictionary with positions (tuple, values)
28  of subunits (keywords)
29  @param proteomic_edges A list edges to represent proteomic data
30  @param quantitative_proteomic_data A dictionary of edges to represent
31  quantitative proteomic data such as PE Scores,
32  or genetic interactions
33  """
34  import itertools
35 
36  self.model = model
37  self.selections = selections
38  self.contact_counts = {}
39  self.edges = defaultdict(int)
40  for (name1, name2) in itertools.combinations(self.selections.keys(),
41  2):
42  self.edges[tuple(sorted((name1, name2)))] = 0
43  self.cutoff = cutoff
44  self.frequency_cutoff = frequency_cutoff
45  self.gcpf = IMP.core.GridClosePairsFinder()
46  self.gcpf.set_distance(self.cutoff)
47  self.names = list(self.selections.keys())
48  self.colors = colors
49  self.fixed = fixed
50  self.pos = pos
51  self.proteomic_edges = proteomic_edges
52  self.quantitative_proteomic_data = quantitative_proteomic_data
53  self.num_rmf = 0
54 
55  def add_rmf(self, rmf_fn, nframe):
56  """Add selections from an RMF file"""
57  print('reading from RMF file', rmf_fn)
58  rh = RMF.open_rmf_file_read_only(rmf_fn)
59  prots = IMP.rmf.create_hierarchies(rh, self.model)
60  hier = prots[0]
61  IMP.rmf.load_frame(rh, RMF.FrameID(0))
62  ps_per_component = defaultdict(list)
63  if self.num_rmf == 0:
64  self.size_per_component = defaultdict(int)
65  self.model.update()
66 
67  # gathers particles for all components
69  all_particles_by_resolution = []
70  for name in part_dict:
71  all_particles_by_resolution += part_dict[name]
72 
73  for component_name in self.selections:
74  for seg in self.selections[component_name]:
75  if isinstance(seg, str):
76  s = IMP.atom.Selection(hier, molecule=seg)
77  elif isinstance(seg, tuple):
79  hier, molecule=seg[2],
80  residue_indexes=range(seg[0], seg[1] + 1))
81  else:
82  raise Exception('could not understand selection tuple '
83  + str(seg))
84  parts = list(set(s.get_selected_particles())
85  & set(all_particles_by_resolution))
86  ps_per_component[component_name] += IMP.get_indexes(parts)
87  if self.num_rmf == 0:
88  self.size_per_component[component_name] += \
90  for p in parts)
91 
92  for n1, name1 in enumerate(self.names):
93  for name2 in self.names[n1+1:]:
94  ncontacts = len(self.gcpf.get_close_pairs(
95  self.model, ps_per_component[name1],
96  ps_per_component[name2]))
97  if ncontacts > 0:
98  self.edges[tuple(sorted((name1, name2)))] += 1.0
99 
100  self.num_rmf += 1
101 
102  def make_plot(self, groups, out_fn, quantitative_proteomic_data=False):
103  '''
104  plot the interaction matrix
105  @param groups is the list of groups of domains, eg,
106  [["protA_1-10","prot1A_11-100"],["protB"]....]
107  it will plot a space between different groups
108  @param out_fn name of the plot file
109  @param quantitative_proteomic_data plot the quantitative proteomic data
110  '''
111  import matplotlib.pyplot as plt
112 
113  ax = plt.gca()
114  ax.set_aspect('equal', 'box')
115  ax.xaxis.set_major_locator(plt.NullLocator())
116  ax.yaxis.set_major_locator(plt.NullLocator())
117 
118  largespace = 0.6
119  smallspace = 0.5
120  squaredistance = 1.0
121  squaresize = 0.99
122  domain_xlocations = {}
123  domain_ylocations = {}
124 
125  xoffset = squaredistance
126  yoffset = squaredistance
127  for group in groups:
128  xoffset += largespace
129  yoffset += largespace
130  for subgroup in group:
131  xoffset += smallspace
132  yoffset += smallspace
133  for domain in subgroup:
134  domain_xlocations[domain] = xoffset
135  domain_ylocations[domain] = yoffset
136  xoffset += squaredistance
137  yoffset += squaredistance
138 
139  for edge, count in self.edges.items():
140 
141  if quantitative_proteomic_data:
142  # normalize
143  maxqpd = max(self.quantitative_proteomic_data.values())
144  minqpd = min(self.quantitative_proteomic_data.values())
145  if edge in self.quantitative_proteomic_data:
146  value = self.quantitative_proteomic_data[edge]
147  elif (edge[1], edge[0]) in self.quantitative_proteomic_data:
148  value = self.quantitative_proteomic_data[(edge[1],
149  edge[0])]
150  else:
151  value = 0.0
152  print(minqpd, maxqpd)
153  density = (1.0-(value-minqpd)/(maxqpd-minqpd))
154  else:
155  density = (1.0-float(count)/self.num_rmf)
156  color = (density, density, 1.0)
157  x = domain_xlocations[edge[0]]
158  y = domain_ylocations[edge[1]]
159  if x > y:
160  xtmp = y
161  ytmp = x
162  x = xtmp
163  y = ytmp
164  rect = plt.Rectangle([x - squaresize / 2, y - squaresize / 2],
165  squaresize, squaresize,
166  facecolor=color, edgecolor='Gray',
167  linewidth=0.1)
168  ax.add_patch(rect)
169  rect = plt.Rectangle([y - squaresize / 2, x - squaresize / 2],
170  squaresize, squaresize,
171  facecolor=color, edgecolor='Gray',
172  linewidth=0.1)
173  ax.add_patch(rect)
174 
175  ax.autoscale_view()
176  plt.savefig(out_fn)
177  plt.show()
178  exit()
179 
180  def make_graph(self, out_fn):
181  edges = []
182  weights = []
183  print('num edges', len(self.edges))
184  for edge, count in self.edges.items():
185  # filter if frequency of contacts is greater than frequency_cutoff
186  if float(count)/self.num_rmf > self.frequency_cutoff:
187  print(count, edge)
188  edges.append(edge)
189  weights.append(count)
190  for nw, w in enumerate(weights):
191  weights[nw] = float(weights[nw])/max(weights)
192  IMP.pmi.output.draw_graph(edges,
193  node_size=dict(self.size_per_component),
194  node_color=self.colors,
195  fixed=self.fixed,
196  pos=self.pos,
197  edge_thickness=1, # weights,
198  edge_alpha=0.3,
199  edge_color='gray',
200  out_filename=out_fn,
201  validation_edges=self.proteomic_edges)
202 
203 
204 def draw_component_composition(DegreesOfFreedom, max=1000,
205  draw_pdb_names=False, show=True):
206  """A function to plot the representation on the sequence
207  @param DegreesOfFreedom input a IMP.pmi.dof.DegreesOfFreedom instance"""
208  import matplotlib as mpl
209  mpl.use('Agg')
210  from matplotlib import pyplot
211  from operator import itemgetter
212  import IMP.pmi.tools
213 
214  # first build the movers dictionary
215  movers_mols_res = IMP.pmi.tools.OrderedDict()
216  for mv in DegreesOfFreedom.movers_particles_map:
217  hs = DegreesOfFreedom.movers_particles_map[mv]
218  res = []
219 
220  for h in hs:
222  res = [IMP.atom.Residue(h).get_index()]
224  res = list(IMP.atom.Fragment(h).get_residue_indexes())
225  if res:
226  is_molecule = False
227  hp = h
228  while not is_molecule:
229  hp = hp.get_parent()
230  is_molecule = IMP.atom.Molecule.get_is_setup(hp)
231  name = (IMP.atom.Molecule(hp).get_name() + "."
232  + str(IMP.atom.Copy(hp).get_copy_index()))
233  if mv not in movers_mols_res:
234  movers_mols_res[mv] = IMP.pmi.tools.OrderedDict()
235  movers_mols_res[mv][name] = IMP.pmi.tools.Segments(res)
236  else:
237  if name not in movers_mols_res[mv]:
238  movers_mols_res[mv][name] = IMP.pmi.tools.Segments(res)
239  else:
240  movers_mols_res[mv][name].add(res)
241  # then get all movers by type
242  fb_movers = []
243  rb_movers = []
244  srb_movers = []
245  for mv in movers_mols_res:
246  if type(mv) is IMP.core.RigidBodyMover:
247  rb_movers.append(mv)
248  if type(mv) is IMP.core.BallMover:
249  fb_movers.append(mv)
250  if type(mv) is IMP.pmi.TransformMover:
251  srb_movers.append(mv)
252 
253  # now remove residue assigned to BallMovers from RigidBodies
254  for mv in fb_movers:
255  for mol in movers_mols_res[mv]:
256  for i in movers_mols_res[mv][mol].get_flatten():
257  for mv_rb in rb_movers:
258  try:
259  movers_mols_res[mv_rb][mol].remove(i)
260  except (ValueError, KeyError):
261  continue
262 
263  elements = {}
264  rgb_colors = [(240, 163, 255), (0, 117, 220),
265  (153, 63, 0), (76, 0, 92), (25, 25, 25),
266  (0, 92, 49), (43, 206, 72), (255, 204, 153),
267  (128, 128, 128), (148, 255, 181), (143, 124, 0),
268  (157, 204, 0), (194, 0, 136), (0, 51, 128), (255, 164, 5),
269  (255, 168, 187), (66, 102, 0), (255, 0, 16), (94, 241, 242),
270  (0, 153, 143), (224, 255, 102), (116, 10, 255), (153, 0, 0),
271  (255, 255, 128), (255, 255, 0), (255, 80, 5)]
272  colors = [(float(c0)/255, float(c1)/255, float(c2)/255)
273  for (c0, c1, c2) in rgb_colors]
274  mvrb_color = {}
275  for mv in movers_mols_res:
276  if type(mv) is IMP.core.RigidBodyMover:
277  if mv not in mvrb_color:
278  color = colors[len(mvrb_color.keys())]
279  mvrb_color[mv] = color
280  for mol in movers_mols_res[mv]:
281  if mol not in elements:
282  elements[mol] = []
283  for seg in movers_mols_res[mv][mol].segs:
284  try:
285  elements[mol].append((seg[0], seg[-1], " ", "pdb",
286  mvrb_color[mv]))
287  except (KeyError, IndexError):
288  continue
289  if type(mv) is IMP.core.BallMover:
290  for mol in movers_mols_res[mv]:
291  if mol not in elements:
292  elements[mol] = []
293  for seg in movers_mols_res[mv][mol].segs:
294  elements[mol].append((seg[0], seg[-1], " ", "bead"))
295 
296  # sort everything
297  for mol in elements:
298  elements[mol].sort(key=lambda tup: tup[0])
299  elements[mol].append((elements[mol][-1][1],
300  elements[mol][-1][1], " ", "end"))
301 
302  for name in elements:
303  k = name
304  tmplist = sorted(elements[name], key=itemgetter(0))
305  try:
306  endres = tmplist[-1][1]
307  except IndexError:
308  print("draw_component_composition: missing information for "
309  "component %s" % name)
310  return
311  fig = pyplot.figure(figsize=(26.0 * float(endres) / max + 2, 2))
312  ax = fig.add_axes([0.05, 0.475, 0.9, 0.15])
313 
314  # Set the colormap and norm to correspond to the data for which
315  # the colorbar will be used.
316  cmap = mpl.cm.cool
317  norm = mpl.colors.Normalize(vmin=5, vmax=10)
318  bounds = [1]
319  colors = []
320 
321  for n, l in enumerate(tmplist):
322  if l[3] != "end":
323  if bounds[-1] != l[0]:
324  colors.append("white")
325  bounds.append(l[0])
326  if l[3] == "pdb":
327  colors.append("#99CCFF")
328  if l[3] == "bead":
329  colors.append("white")
330  if l[3] == "helix":
331  colors.append("#33CCCC")
332  if l[3] != "end":
333  bounds.append(l[1] + 1)
334  else:
335  if l[3] == "pdb":
336  colors.append(l[4])
337  if l[3] == "bead":
338  colors.append("white")
339  if l[3] == "helix":
340  colors.append("#33CCCC")
341  if l[3] != "end":
342  bounds.append(l[1] + 1)
343  else:
344  if bounds[-1] - 1 == l[0]:
345  bounds.pop()
346  bounds.append(l[0])
347  else:
348  colors.append("white")
349  bounds.append(l[0])
350 
351  bounds.append(bounds[-1])
352  colors.append("white")
353  cmap = mpl.colors.ListedColormap(colors)
354  cmap.set_over('0.25')
355  cmap.set_under('0.75')
356 
357  norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
358  cb2 = mpl.colorbar.ColorbarBase(ax, cmap=cmap,
359  norm=norm,
360  # to use 'extend', you must
361  # specify two extra boundaries:
362  boundaries=bounds,
363  ticks=bounds, # optional
364  spacing='proportional',
365  orientation='horizontal')
366 
367  extra_artists = []
368  npdb = 0
369 
370  if draw_pdb_names:
371  for tl in tmplist:
372  if tl[3] == "pdb":
373  npdb += 1
374  mid = 1.0 / endres * float(tl[0])
375  t = ax.annotate(
376  tl[2], xy=(mid, 1), xycoords='axes fraction',
377  xytext=(mid + 0.025, float(npdb - 1) / 2.0 + 1.5),
378  textcoords='axes fraction',
379  arrowprops=dict(
380  arrowstyle="->",
381  connectionstyle="angle,angleA=0,angleB=90,rad=10"))
382  extra_artists.append(t)
383 
384  # set the title of the bar
385  title = ax.text(-0.005, 0.5, k, ha="right", va="center", rotation=90,
386  size=20)
387 
388  extra_artists.append(title)
389  # changing the xticks labels
390  labels = len(bounds) * [" "]
391  ax.set_xticklabels(labels)
392  mid = 1.0 / endres * float(bounds[0])
393  t = ax.annotate(bounds[0], xy=(mid, 0), xycoords='axes fraction',
394  xytext=(mid - 0.01, -0.5), textcoords='axes fraction',)
395  extra_artists.append(t)
396  offsets = [0, -0.5, -1.0]
397  nclashes = 0
398  for n in range(1, len(bounds)):
399  if bounds[n] == bounds[n - 1]:
400  continue
401  mid = 1.0 / endres * float(bounds[n])
402  if (float(bounds[n]) - float(bounds[n - 1])) / max <= 0.01:
403  nclashes += 1
404  offset = offsets[nclashes % 3]
405  else:
406  nclashes = 0
407  offset = offsets[0]
408  if offset > -0.75:
409  t = ax.annotate(bounds[n], xy=(mid, 0),
410  xycoords='axes fraction',
411  xytext=(mid, -0.5 + offset),
412  textcoords='axes fraction')
413  else:
414  t = ax.annotate(bounds[n], xy=(mid, 0),
415  xycoords='axes fraction',
416  xytext=(mid, -0.5 + offset),
417  textcoords='axes fraction',
418  arrowprops=dict(arrowstyle="-"))
419  extra_artists.append(t)
420 
421  cb2.add_lines(bounds, ["black"] * len(bounds), [1] * len(bounds))
422  # cb2.set_label(k)
423 
424  pyplot.savefig(k + "structure.pdf")
425  if show:
426  pyplot.show()
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: Molecule.h:35
A class to read RMF files and make a network contact map.
Definition: topology.py:11
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Definition: Residue.h:158
A decorator to associate a particle with a part of a protein/DNA/RNA.
Definition: Fragment.h:20
atom::Hierarchies create_hierarchies(RMF::FileConstHandle fh, Model *m)
Miscellaneous utilities.
Definition: tools.py:1
Modify the transformation of a rigid body.
def make_plot
plot the interaction matrix
Definition: topology.py:102
This class stores integers in ordered compact lists eg: [[1,2,3],[6,7,8]] the methods help splitting ...
Definition: tools.py:610
Move continuous particle variables by perturbing them within a ball.
def add_rmf
Add selections from an RMF file.
Definition: topology.py:55
static bool get_is_setup(Model *m, ParticleIndex pi)
Definition: Fragment.h:46
A decorator for keeping track of copies of a molecule.
Definition: Copy.h:28
ParticleIndexPairs get_indexes(const ParticlePairsTemp &ps)
Get the indexes from a list of particle pairs.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
def __init__
Set up a new graphXL object.
Definition: topology.py:29
void load_frame(RMF::FileConstHandle file, RMF::FrameID frame)
Load the given RMF frame into the state of the linked objects.
def get_particles_at_resolution_one
Get particles at res 1, or any beads, based on the name.
Modify the transformation of a rigid body.
Tools for clustering and cluster analysis.
Definition: pmi/Analysis.py:1
Find all nearby pairs by testing all pairs.
Classes for writing output files and processing them.
Definition: output.py:1
A decorator for a residue.
Definition: Residue.h:137
The general base class for IMP exceptions.
Definition: exception.h:48
int get_copy_index(Hierarchy h)
Walk up the hierarchy to find the current copy index.
Python classes to represent, score, sample and analyze models.
Functionality for loading, creating, manipulating and scoring atomic structures.
A decorator for a molecule.
Definition: Molecule.h:24
Select hierarchy particles identified by the biological name.
Definition: Selection.h:70
Support for the RMF file format for storing hierarchical molecular data and markup.
def get_residue_indexes
Retrieve the residue indexes for the given particle.
Definition: tools.py:499