Package specific_analyses :: Package model_free :: Module macro_base
[hide private]
[frames] | no frames]

Source Code for Module specific_analyses.model_free.macro_base

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2013 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """The Molmol and Pymol base macro methods of the specific API for model-free analysis.""" 
 24   
 25  # Python module imports. 
 26  from math import pi 
 27  from re import search 
 28   
 29  # relax module imports. 
 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   
38 -class Macro:
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 # Generate the macro header. 77 ############################ 78 79 self.classic_header() 80 81 82 # S2. 83 ##### 84 85 if data_type == 's2': 86 # Loop over the spins. 87 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 88 # Skip deselected spins or spins with no model information set. 89 if not spin.select or not hasattr(spin, 'model'): 90 continue 91 92 # Skip spins which don't have an S2 value. 93 if not hasattr(spin, 's2') or spin.s2 == None: 94 continue 95 96 # S2 width and colour for the backbone NH. 97 if spin.name == 'N': 98 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list) 99 100 101 # S2f. 102 ###### 103 104 elif data_type == 's2f': 105 # Loop over the spins. 106 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 107 # Skip deselected spins or spins with no model information set. 108 if not spin.select or not hasattr(spin, 'model'): 109 continue 110 111 # The backbone NH. 112 if spin.name == 'N': 113 # Colour residues which don't have an S2f value white. 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 # S2f width and colour. 118 else: 119 self.classic_order_param(res_num, spin.s2f, colour_start, colour_end, colour_list) 120 121 122 # S2s. 123 ###### 124 125 elif data_type == 's2s': 126 # Loop over the spins. 127 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 128 # Skip deselected spins or spins with no model information set. 129 if not spin.select or not hasattr(spin, 'model'): 130 continue 131 132 # The backbone NH. 133 if spin.name == 'N': 134 # Colour residues which don't have an S2s value white. 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 # S2s width and colour. 139 else: 140 self.classic_order_param(res_num, spin.s2s, colour_start, colour_end, colour_list) 141 142 143 # Amplitude of fast motions. 144 ############################ 145 146 elif data_type == 'amp_fast': 147 # Loop over the spins. 148 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 149 # Skip deselected spins or spins with no model information set. 150 if not spin.select or not hasattr(spin, 'model'): 151 continue 152 153 # The model. 154 if search('tm[0-9]', spin.model): 155 model = spin.model[1:] 156 else: 157 model = spin.model 158 159 # The backbone NH. 160 if spin.name == 'N': 161 # S2f width and colour (for models m5 to m8). 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 # S2 width and colour (for models m1 and m3). 166 elif model == 'm1' or model == 'm3': 167 self.classic_order_param(res_num, spin.s2, colour_start, colour_end, colour_list) 168 169 # S2 width and colour (for models m2 and m4 when te <= 200 ps). 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 # White bonds (for models m2 and m4 when te > 200 ps). 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 # Amplitude of slow motions. 179 ############################ 180 181 elif data_type == 'amp_slow': 182 # Loop over the spins. 183 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 184 # Skip deselected spins or spins with no model information set. 185 if not spin.select or not hasattr(spin, 'model'): 186 continue 187 188 # The model. 189 if search('tm[0-9]', spin.model): 190 model = spin.model[1:] 191 else: 192 model = spin.model 193 194 # The backbone NH. 195 if spin.name == 'N': 196 # S2 width and colour (for models m5 to m8). 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 # S2 width and colour (for models m2 and m4 when te > 200 ps). 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 # White bonds for fast motions. 205 else: 206 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1]) 207 208 # te. 209 ##### 210 211 elif data_type == 'te': 212 # Loop over the spins. 213 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 214 # Skip deselected spins or spins with no model information set. 215 if not spin.select or not hasattr(spin, 'model'): 216 continue 217 218 # Skip spins which don't have a te value. 219 if not hasattr(spin, 'te') or spin.te == None: 220 continue 221 222 # te width and colour (backbone NH). 223 if spin.name == 'N': 224 self.classic_correlation_time(res_num, spin.te, colour_start, colour_end, colour_list) 225 226 227 # tf. 228 ##### 229 230 elif data_type == 'tf': 231 # Loop over the spins. 232 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 233 # Skip deselected spins or spins with no model information set. 234 if not spin.select or not hasattr(spin, 'model'): 235 continue 236 237 # Skip spins which don't have a tf value. 238 if not hasattr(spin, 'tf') or spin.tf == None: 239 continue 240 241 # tf width and colour (backbone NH). 242 if spin.name == 'N': 243 self.classic_correlation_time(res_num, spin.tf, colour_start, colour_end, colour_list) 244 245 246 # ts. 247 ##### 248 249 elif data_type == 'ts': 250 # Loop over the spins. 251 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 252 # Skip deselected spins or spins with no model information set. 253 if not spin.select or not hasattr(spin, 'model'): 254 continue 255 256 # Skip spins which don't have a ts value. 257 if not hasattr(spin, 'ts') or spin.ts == None: 258 continue 259 260 # The default start and end colours. 261 if colour_start == None: 262 colour_start = 'blue' 263 if colour_end == None: 264 colour_end = 'black' 265 266 # ts width and colour (backbone NH). 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 # Timescale of fast motions. 272 ############################ 273 274 elif data_type == 'time_fast': 275 # Loop over the spins. 276 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 277 # Skip deselected spins or spins with no model information set. 278 if not spin.select or not hasattr(spin, 'model'): 279 continue 280 281 # The model. 282 if search('tm[0-9]', spin.model): 283 model = spin.model[1:] 284 else: 285 model = spin.model 286 287 # The backbone NH. 288 if spin.name == 'N': 289 # tf width and colour (for models m5 to m8). 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 # te width and colour (for models m2 and m4 when te <= 200 ps). 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 # All other residues are assumed to have a fast correlation time of zero (statistically zero, not real zero!). 298 # Colour these bonds white. 299 else: 300 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1]) 301 302 303 # Timescale of slow motions. 304 ############################ 305 306 elif data_type == 'time_slow': 307 # Loop over the spins. 308 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 309 # Skip deselected spins or spins with no model information set. 310 if not spin.select or not hasattr(spin, 'model'): 311 continue 312 313 # The model. 314 if search('tm[0-9]', spin.model): 315 model = spin.model[1:] 316 else: 317 model = spin.model 318 319 # The default start and end colours. 320 if colour_start == None: 321 colour_start = 'blue' 322 if colour_end == None: 323 colour_end = 'black' 324 325 # The backbone NH. 326 if spin.name == 'N': 327 # ts width and colour (for models m5 to m8). 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 # te width and colour (for models m2 and m4 when te > 200 ps). 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 # White bonds for the rest. 336 else: 337 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1]) 338 339 340 # Rex. 341 ###### 342 343 elif data_type == 'rex': 344 # Loop over the spins. 345 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True): 346 # Skip deselected spins or spins with no model information set. 347 if not spin.select or not hasattr(spin, 'model'): 348 continue 349 350 # The backbone NH. 351 if spin.name == 'N': 352 # Residues which chemical exchange. 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 # White bonds for the rest. 357 else: 358 self.classic_colour(res_num=res_num, width=0.3, rgb_array=[1, 1, 1]) 359 360 361 # Unknown data type. 362 #################### 363 364 else: 365 raise RelaxUnknownDataTypeError(data_type)
366 367
368 - def classic_correlation_time(self, res_num, te, colour_start, colour_end, colour_list):
369 """Function for generating the bond width and colours for correlation times.""" 370 371 # The te value in picoseconds. 372 te = te * 1e12 373 374 # The bond width (aiming for a width range of 2 to 0 for te values of 0 to 10 ns). 375 width = 2.0 - 200.0 / (te + 100.0) 376 377 # Catch invalid widths. 378 if width <= 0.0: 379 width = 0.001 380 381 # Colour value (hyperbolic). 382 colour_value = 1.0 / (te / 100.0 + 1.0) 383 384 # Catch invalid colours. 385 if colour_value < 0.0: 386 colour_value = 0.0 387 elif colour_value > 1.0: 388 colour_value = 1.0 389 390 # Default colours. 391 if colour_start == None: 392 colour_start = 'turquoise' 393 if colour_end == None: 394 colour_end = 'blue' 395 396 # Get the RGB colour array (swap the colours because of the inverted hyperbolic colour value). 397 rgb_array = linear_gradient(colour_value, colour_end, colour_start, colour_list) 398 399 # Colour the peptide bond. 400 self.classic_colour(res_num, width, rgb_array)
401 402
403 - def classic_order_param(self, res_num, s2, colour_start, colour_end, colour_list):
404 """Function for generating the bond width and colours for order parameters.""" 405 406 # The bond width (aiming for a width range of 2 to 0 for S2 values of 0.0 to 1.0). 407 if s2 <= 0.0: 408 width = 2.0 409 else: 410 width = 2.0 * (1.0 - s2**2) 411 412 # Catch invalid widths. 413 if width <= 0.0: 414 width = 0.001 415 416 # Colour value (quartic). 417 colour_value = s2 ** 4 418 419 # Catch invalid colours. 420 if colour_value < 0.0: 421 colour_value = 0.0 422 elif colour_value > 1.0: 423 colour_value = 1.0 424 425 # Default colours. 426 if colour_start == None: 427 colour_start = 'red' 428 if colour_end == None: 429 colour_end = 'yellow' 430 431 # Get the RGB colour array. 432 rgb_array = linear_gradient(colour_value, colour_start, colour_end, colour_list) 433 434 # Colour the peptide bond. 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 # The 1st spectrometer frequency. 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: # Take the highest frequency, if all else fails. 447 frqs = sorted(cdp.spectrometer_frq.values()) 448 frq = frqs[-1] 449 450 # The Rex value. 451 rex = rex * (2.0 * pi * frq)**2 452 453 # The bond width (aiming for a width range of 2 to 0 for Rex values of 0 to 25 s^-1). 454 width = 2.0 - 2.0 / (rex/5.0 + 1.0) 455 456 # Catch invalid widths. 457 if width <= 0.0: 458 width = 0.001 459 460 # Colour value (hyperbolic). 461 colour_value = 1.0 / (rex + 1.0) 462 463 # Catch invalid colours. 464 if colour_value < 0.0: 465 colour_value = 0.0 466 elif colour_value > 1.0: 467 colour_value = 1.0 468 469 # Default colours. 470 if colour_start == None: 471 colour_start = 'yellow' 472 if colour_end == None: 473 colour_end = 'red' 474 475 # Get the RGB colour array (swap the colours because of the inverted hyperbolic colour value). 476 rgb_array = linear_gradient(colour_value, colour_end, colour_start, colour_list) 477 478 # Colour the peptide bond. 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 # Initialise. 500 self.commands = [] 501 502 # The classic style. 503 if style == 'classic': 504 self.classic_style(data_type, colour_start, colour_end, colour_list, spin_id) 505 506 # Unknown style. 507 else: 508 raise RelaxStyleError(style) 509 510 # Return the command array. 511 return self.commands
512