1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """The Molmol and Pymol base macro methods of the specific API for model-free analysis."""
24
25
26 from math import pi
27 from re import search
28
29
30 from colour import linear_gradient
31 from lib.errors import RelaxError, RelaxStyleError, RelaxUnknownDataTypeError
32 from pipe_control.mol_res_spin import spin_loop
33 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
34 from user_functions.objects import Desc_container
35
36
37
39 """The base class for the model-free analysis Molmol and PyMOL macro creation."""
40
41 classic_style_doc = Desc_container("Model-free classic style")
42 classic_style_doc.add_paragraph("Creator: Edward d'Auvergne")
43 classic_style_doc.add_paragraph("Argument string: \"classic\"")
44 classic_style_doc.add_paragraph("Description: The classic style draws the backbone of a protein in a cylindrical bond style. Rather than colouring the amino acids to which the NH bond belongs, the three covalent bonds of the peptide bond from Ca to Ca in which the NH bond is located are coloured. Deselected residues are shown as black lines.")
45 classic_style_doc.add_paragraph("Supported data types:")
46 table = uf_tables.add_table(label="table: model-free macro classic style", caption="The model-free classic style for mapping model spin specific data onto 3D molecular structures using either PyMOL or Molmol.", caption_short="The model-free classic style for PyMOL and Molmol data mapping.")
47 table.add_headings(["Data type", "String", "Description"])
48 table.add_row(["S2.", "'s2'", "The standard model-free order parameter, equal to S2f.S2s for the two timescale models. The default colour gradient starts at 'yellow' and ends at 'red'."])
49 table.add_row(["S2f.", "'s2f'", "The order parameter of the faster of two internal motions. Residues which are described by model-free models m1 to m4, the single timescale models, are illustrated as white neon bonds. The default colour gradient is the same as that for the S2 data type."])
50 table.add_row(["S2s.", "'s2s'", "The order parameter of the slower of two internal motions. This functions exactly as S2f except that S2s is plotted instead."])
51 table.add_row(["Amplitude of fast motions.", "'amp_fast'", "Model independent display of the amplite of fast motions. For residues described by model-free models m5 to m8, the value plotted is that of S2f. However, for residues described by models m1 to m4, what is shown is dependent on the timescale of the motions. This is because these single timescale models can, at times, be perfect approximations to the more complex two timescale models. Hence if te is less than 200 ps, S2 is plotted. Otherwise the peptide bond is coloured white. The default colour gradient is the same as that for S2."])
52 table.add_row(["Amplitude of slow motions.", "'amp_slow'", "Model independent display of the amplite of slow motions, arbitrarily defined as motions slower than 200 ps. For residues described by model-free models m5 to m8, the order parameter S2 is plotted if ts > 200 ps. For models m1 to m4, S2 is plotted if te > 200 ps. The default colour gradient is the same as that for S2."])
53 table.add_row(["te.", "'te'", "The correlation time, te. The default colour gradient starts at 'turquoise' and ends at 'blue'."])
54 table.add_row(["tf.", "'tf'", "The correlation time, tf. The default colour gradient is the same as that of te."])
55 table.add_row(["ts.", "'ts'", "The correlation time, ts. The default colour gradient starts at 'blue' and ends at 'black'."])
56 table.add_row(["Timescale of fast motions", "'time_fast'", "Model independent display of the timescale of fast motions. For models m5 to m8, only the parameter tf is plotted. For models m2 and m4, the parameter te is plotted only if it is less than 200 ps. All other residues are assumed to have a correlation time of zero. The default colour gradient is the same as that of te."])
57 table.add_row(["Timescale of slow motions", "'time_slow'", "Model independent display of the timescale of slow motions. For models m5 to m8, only the parameter ts is plotted. For models m2 and m4, the parameter te is plotted only if it is greater than 200 ps. All other residues are coloured white. The default colour gradient is the same as that of ts."])
58 table.add_row(["Chemical exchange", "'rex'", "The chemical exchange, Rex. Residues which experience no chemical exchange are coloured white. The default colour gradient starts at 'yellow' and finishes at 'red'."])
59 classic_style_doc.add_table(table.label)
60
61 - def classic_style(self, data_type=None, colour_start=None, colour_end=None, colour_list=None, spin_id=None):
62 """The classic macro style.
63
64 @keyword data_type: The parameter name or data type.
65 @type data_type: str
66 @keyword colour_start: The starting colour (must be a MOLMOL or X11 name).
67 @type colour_start: str
68 @keyword colour_end: The ending colour (must be a MOLMOL or X11 name).
69 @type colour_end: str
70 @keyword colour_list: The colour list used, either 'molmol' or 'x11'.
71 @type colour_list: str
72 @keyword spin_id: The spin identification string.
73 @type spin_id: str
74 """
75
76
77
78
79 self.classic_header()
80
81
82
83
84
85 if data_type == 's2':
86
87 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
88
89 if not spin.select or not hasattr(spin, 'model'):
90 continue
91
92
93 if not hasattr(spin, 's2') or spin.s2 == None:
94 continue
95
96
97 if spin.name == 'N':
98 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list)
99
100
101
102
103
104 elif data_type == 's2f':
105
106 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
107
108 if not spin.select or not hasattr(spin, 'model'):
109 continue
110
111
112 if spin.name == 'N':
113
114 if not hasattr(spin, 's2f') or spin.s2f == None:
115 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
116
117
118 else:
119 self.classic_order_param(res_num, spin.s2f, colour_start, colour_end, colour_list)
120
121
122
123
124
125 elif data_type == 's2s':
126
127 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
128
129 if not spin.select or not hasattr(spin, 'model'):
130 continue
131
132
133 if spin.name == 'N':
134
135 if not hasattr(spin, 's2s') or spin.s2s == None:
136 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
137
138
139 else:
140 self.classic_order_param(res_num, spin.s2s, colour_start, colour_end, colour_list)
141
142
143
144
145
146 elif data_type == 'amp_fast':
147
148 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
149
150 if not spin.select or not hasattr(spin, 'model'):
151 continue
152
153
154 if search('tm[0-9]', spin.model):
155 model = spin.model[1:]
156 else:
157 model = spin.model
158
159
160 if spin.name == 'N':
161
162 if hasattr(spin, 's2f') and spin.s2f != None:
163 self.classic_order_param(res_num, spin.s2f, colour_start, colour_end, colour_list)
164
165
166 elif model == 'm1' or model == 'm3':
167 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list)
168
169
170 elif (model == 'm2' or model == 'm4') and spin.te <= 200e-12:
171 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list)
172
173
174 elif (model == 'm2' or model == 'm4') and spin.te > 200e-12:
175 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
176
177
178
179
180
181 elif data_type == 'amp_slow':
182
183 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
184
185 if not spin.select or not hasattr(spin, 'model'):
186 continue
187
188
189 if search('tm[0-9]', spin.model):
190 model = spin.model[1:]
191 else:
192 model = spin.model
193
194
195 if spin.name == 'N':
196
197 if hasattr(spin, 'ts') and spin.ts != None:
198 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list)
199
200
201 elif (model == 'm2' or model == 'm4') and spin.te > 200 * 1e-12:
202 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list)
203
204
205 else:
206 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
207
208
209
210
211 elif data_type == 'te':
212
213 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
214
215 if not spin.select or not hasattr(spin, 'model'):
216 continue
217
218
219 if not hasattr(spin, 'te') or spin.te == None:
220 continue
221
222
223 if spin.name == 'N':
224 self.classic_correlation_time(res_num, spin.te, colour_start, colour_end, colour_list)
225
226
227
228
229
230 elif data_type == 'tf':
231
232 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
233
234 if not spin.select or not hasattr(spin, 'model'):
235 continue
236
237
238 if not hasattr(spin, 'tf') or spin.tf == None:
239 continue
240
241
242 if spin.name == 'N':
243 self.classic_correlation_time(res_num, spin.tf, colour_start, colour_end, colour_list)
244
245
246
247
248
249 elif data_type == 'ts':
250
251 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
252
253 if not spin.select or not hasattr(spin, 'model'):
254 continue
255
256
257 if not hasattr(spin, 'ts') or spin.ts == None:
258 continue
259
260
261 if colour_start == None:
262 colour_start = 'blue'
263 if colour_end == None:
264 colour_end = 'black'
265
266
267 if spin.name == 'N':
268 self.classic_correlation_time(res_num, spin.ts / 10.0, colour_start, colour_end, colour_list)
269
270
271
272
273
274 elif data_type == 'time_fast':
275
276 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
277
278 if not spin.select or not hasattr(spin, 'model'):
279 continue
280
281
282 if search('tm[0-9]', spin.model):
283 model = spin.model[1:]
284 else:
285 model = spin.model
286
287
288 if spin.name == 'N':
289
290 if hasattr(spin, 'tf') and spin.tf != None:
291 self.classic_correlation_time(res_num, spin.tf, colour_start, colour_end, colour_list)
292
293
294 elif (model == 'm2' or model == 'm4') and spin.te <= 200e-12:
295 self.classic_correlation_time(res_num, spin.te, colour_start, colour_end, colour_list)
296
297
298
299 else:
300 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
301
302
303
304
305
306 elif data_type == 'time_slow':
307
308 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
309
310 if not spin.select or not hasattr(spin, 'model'):
311 continue
312
313
314 if search('tm[0-9]', spin.model):
315 model = spin.model[1:]
316 else:
317 model = spin.model
318
319
320 if colour_start == None:
321 colour_start = 'blue'
322 if colour_end == None:
323 colour_end = 'black'
324
325
326 if spin.name == 'N':
327
328 if hasattr(spin, 'ts') and spin.ts != None:
329 self.classic_correlation_time(res_num, spin.ts / 10.0, colour_start, colour_end, colour_list)
330
331
332 elif (model == 'm2' or model == 'm4') and spin.te > 200e-12:
333 self.classic_correlation_time(res_num, spin.te / 10.0, colour_start, colour_end, colour_list)
334
335
336 else:
337 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
338
339
340
341
342
343 elif data_type == 'rex':
344
345 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
346
347 if not spin.select or not hasattr(spin, 'model'):
348 continue
349
350
351 if spin.name == 'N':
352
353 if hasattr(spin, 'rex') and spin.rex != None:
354 self.classic_rex(res_num, spin.rex, colour_start, colour_end, colour_list)
355
356
357 else:
358 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1])
359
360
361
362
363
364 else:
365 raise RelaxUnknownDataTypeError(data_type)
366
367
369 """Function for generating the bond width and colours for correlation times."""
370
371
372 te = te * 1e12
373
374
375 width = 2.0 - 200.0 / (te + 100.0)
376
377
378 if width <= 0.0:
379 width = 0.001
380
381
382 colour_value = 1.0 / (te / 100.0 + 1.0)
383
384
385 if colour_value < 0.0:
386 colour_value = 0.0
387 elif colour_value > 1.0:
388 colour_value = 1.0
389
390
391 if colour_start == None:
392 colour_start = 'turquoise'
393 if colour_end == None:
394 colour_end = 'blue'
395
396
397 rgb_array = linear_gradient(colour_value, colour_end, colour_start, colour_list)
398
399
400 self.classic_colour(res_num, width, rgb_array)
401
402
404 """Function for generating the bond width and colours for order parameters."""
405
406
407 if s2 <= 0.0:
408 width = 2.0
409 else:
410 width = 2.0 * (1.0 - s2**2)
411
412
413 if width <= 0.0:
414 width = 0.001
415
416
417 colour_value = s2 ** 4
418
419
420 if colour_value < 0.0:
421 colour_value = 0.0
422 elif colour_value > 1.0:
423 colour_value = 1.0
424
425
426 if colour_start == None:
427 colour_start = 'red'
428 if colour_end == None:
429 colour_end = 'yellow'
430
431
432 rgb_array = linear_gradient(colour_value, colour_start, colour_end, colour_list)
433
434
435 self.classic_colour(res_num, width, rgb_array)
436
437
438 - def classic_rex(self, res_num, rex, colour_start, colour_end, colour_list):
439 """Function for generating the bond width and colours for correlation times."""
440
441
442 if not hasattr(cdp, 'spectrometer_frq'):
443 raise RelaxError("No spectrometer frequency information is present in the current data pipe.")
444 if hasattr(cdp, 'ri_ids'):
445 frq = cdp.spectrometer_frq[cdp.ri_ids[0]]
446 else:
447 frqs = sorted(cdp.spectrometer_frq.values())
448 frq = frqs[-1]
449
450
451 rex = rex * (2.0 * pi * frq)**2
452
453
454 width = 2.0 - 2.0 / (rex/5.0 + 1.0)
455
456
457 if width <= 0.0:
458 width = 0.001
459
460
461 colour_value = 1.0 / (rex + 1.0)
462
463
464 if colour_value < 0.0:
465 colour_value = 0.0
466 elif colour_value > 1.0:
467 colour_value = 1.0
468
469
470 if colour_start == None:
471 colour_start = 'yellow'
472 if colour_end == None:
473 colour_end = 'red'
474
475
476 rgb_array = linear_gradient(colour_value, colour_end, colour_start, colour_list)
477
478
479 self.classic_colour(res_num, width, rgb_array)
480
481
482 - def create_macro(self, data_type, style=None, colour_start=None, colour_end=None, colour_list=None, spin_id=None):
483 """Create and return an array of macros of the model-free parameters.
484
485 @param data_type: The parameter name or data type.
486 @type data_type: str
487 @keyword style: The Molmol style.
488 @type style: None or str
489 @keyword colour_start: The starting colour (must be a MOLMOL or X11 name).
490 @type colour_start: str
491 @keyword colour_end: The ending colour (must be a MOLMOL or X11 name).
492 @type colour_end: str
493 @keyword colour_list: The colour list used, either 'molmol' or 'x11'.
494 @type colour_list: str
495 @keyword spin_id: The spin identification string.
496 @type spin_id: str
497 """
498
499
500 self.commands = []
501
502
503 if style == 'classic':
504 self.classic_style(data_type, colour_start, colour_end, colour_list, spin_id)
505
506
507 else:
508 raise RelaxStyleError(style)
509
510
511 return self.commands
512