1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """Module for interfacing with Grace (also known as Xmgrace, Xmgr, and ace)."""
25
26
27 from numpy import array, ndarray
28 from os import system
29 from warnings import warn
30
31
32 import generic_fns
33 from generic_fns.mol_res_spin import count_molecules, count_residues, count_spins, exists_mol_res_spin_data, generate_spin_id, spin_loop
34 from generic_fns import pipes
35 from relax_errors import RelaxError, RelaxNoSequenceError, RelaxNoSimError
36 from relax_io import get_file_path, open_write_file, test_binary
37 from relax_warnings import RelaxWarning
38 import specific_fns
39 from status import Status; status = Status()
40
41
43 """Determine the spin sequence data type.
44
45 The purpose is to identify systems whereby only spins or only residues exist.
46
47 @keyword spin_id: The spin identification string.
48 @type spin_id: str
49 @return: The spin sequence data type. This can be one of 'spin', 'res,' or 'mixed'.
50 @rtype: str
51 """
52
53
54 num_mol = count_molecules(spin_id)
55 num_res = count_residues(spin_id)
56 num_spin = count_spins(spin_id)
57
58
59 if num_mol == 1 and num_spin == 1:
60 return 'res'
61
62
63 if num_mol == 1 and num_res == 1:
64 return 'spin'
65
66
67 return 'mixed'
68
69
70 -def get_data(spin_id=None, x_data_type=None, y_data_type=None, plot_data=None):
71 """Return all the xy data, along with the graph type and names for the graph sets.
72
73 @keyword spin_id: The spin identification string.
74 @type spin_id: str
75 @keyword x_data_type: The category of the X-axis data.
76 @type x_data_type: str
77 @keyword y_data_type: The category of the Y-axis data.
78 @type y_data_type: str
79 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
80 @type plot_data: str
81 @return: The 4D graph numerical data structure, the graph type (i.e. on of 'xy', 'xydy', or 'xydxdy'), and the labels for the graph sets.
82 @rtype: list of lists of lists of float, str, and list of str
83 """
84
85
86 data = [[]]
87 set_labels = []
88 x_err_flag = False
89 y_err_flag = False
90 data_list = False
91 data_dict = False
92
93
94 x_return_value = y_return_value = specific_fns.setup.get_specific_fn('return_value', pipes.get_type())
95 x_return_conversion_factor = y_return_conversion_factor = specific_fns.setup.get_specific_fn('return_conversion_factor', pipes.get_type())
96
97
98 if x_data_type != 'spin' and generic_fns.minimise.return_data_name(x_data_type):
99 x_return_value = generic_fns.minimise.return_value
100 x_return_conversion_factor = generic_fns.minimise.return_conversion_factor
101
102
103 if y_data_type != 'spin' and generic_fns.minimise.return_data_name(y_data_type):
104 y_return_value = generic_fns.minimise.return_value
105 y_return_conversion_factor = generic_fns.minimise.return_conversion_factor
106
107
108 if plot_data == 'sim':
109 sets = cdp.sim_number
110 else:
111 sets = 1
112
113
114 for i in range(sets):
115
116 set_label = ''
117 if plot_data == 'sim':
118 set_label = "Sim: %i" % i
119
120
121 sim = None
122 if plot_data == 'sim':
123 sim = i
124
125
126 spin_names = []
127
128
129 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True):
130
131 if not spin.select:
132 continue
133
134
135 if x_data_type == 'spin':
136 x_val = res_num
137 x_err = None
138
139
140 else:
141
142 x_val, x_err = x_return_value(spin, x_data_type, sim=sim)
143
144
145 if y_data_type == 'spin':
146 y_val = res_num
147 y_err = None
148
149
150 else:
151
152 y_val, y_err = y_return_value(spin, y_data_type, sim=sim)
153
154
155 if x_val == None or y_val == None:
156 continue
157
158
159 if data_list or isinstance(x_val, list):
160
161 data[0].append([])
162 set_labels.append("Spin %s" % id)
163
164
165 index = len(data[0]) - 1
166
167
168 if x_err == None:
169 x_err = [None]*len(x_val)
170 if y_err == None:
171 y_err = [None]*len(y_val)
172
173
174 data_list = True
175
176
177 if data_dict or isinstance(x_val, dict):
178
179 data[0].append([])
180 set_labels.append("Spin %s" % id)
181
182
183 index = len(data[0]) - 1
184
185
186 list_data = []
187 for key in x_val.keys():
188 list_data.append([x_val[key], y_val[key]])
189 list_data.sort()
190
191
192 x_val = []
193 y_val = []
194 for i in range(len(list_data)):
195 x_val.append(list_data[i][0])
196 y_val.append(list_data[i][1])
197
198
199 if x_err == None:
200 x_err = [None]*len(x_val)
201 if y_err == None:
202 y_err = [None]*len(y_val)
203
204
205 data_dict = True
206
207
208 else:
209 x_val = [x_val]
210 y_val = [y_val]
211 x_err = [x_err]
212 y_err = [y_err]
213
214
215 if not data_list and not data_dict and spin.name not in spin_names:
216
217 data[0].append([])
218
219
220 set_labels.append("%s spins. " % spin.name + set_label)
221
222
223 spin_names.append(spin.name)
224
225
226 index = i * len(spin_names) + spin_names.index(spin.name)
227
228
229 for j in range(len(x_val)):
230
231 data[0][index].append([])
232 point = data[0][index][-1]
233
234
235 x_val[j] = x_val[j] / x_return_conversion_factor(x_data_type)
236 if x_err[j]:
237 x_err[j] = x_err[j] / x_return_conversion_factor(x_data_type)
238 y_val[j] = y_val[j] / y_return_conversion_factor(y_data_type)
239 if y_err[j]:
240 y_err[j] = y_err[j] / y_return_conversion_factor(y_data_type)
241
242
243 point.append(x_val[j])
244 point.append(y_val[j])
245 point.append(x_err[j])
246 point.append(y_err[j])
247
248
249 if x_err[j] and not x_err_flag:
250 x_err_flag = True
251 if y_err[j] and not y_err_flag:
252 y_err_flag = True
253
254
255 graph_type = 'xy'
256 if x_err_flag:
257 graph_type = graph_type + 'dx'
258 if y_err_flag:
259 graph_type = graph_type + 'dy'
260
261
262 new_data = []
263 for i in range(len(data)):
264 new_data.append([])
265 for j in range(len(data[i])):
266 new_data[i].append([])
267 for k in range(len(data[i][j])):
268
269 new_data[i][j].append([])
270 new_data[i][j][k].append(data[i][j][k][0])
271 new_data[i][j][k].append(data[i][j][k][1])
272
273
274 if graph_type in ['xydx', 'xydxdy']:
275 new_data[i][j][k].append(data[i][j][k][2])
276
277
278 if graph_type in ['xydy', 'xydxdy']:
279 new_data[i][j][k].append(data[i][j][k][3])
280
281
282 return new_data, set_labels, graph_type
283
284
285 -def view(file=None, dir=None, grace_exe='xmgrace'):
286 """Execute Grace.
287
288 @keyword file: The name of the file to open in Grace.
289 @type file: str
290 @keyword dir: The optional directory containing the file.
291 @type dir: str
292 @keyword grace_exe: The name of the Grace executable file. This should be located within the
293 system path.
294 @type grace_exe: str
295 """
296
297
298 test_binary(grace_exe)
299
300
301 file_path = get_file_path(file, dir)
302
303
304 system(grace_exe + " " + file_path + " &")
305
306
307 -def write(x_data_type='spin', y_data_type=None, spin_id=None, plot_data='value', file=None, dir=None, force=False, norm=True):
308 """Writing data to a file.
309
310 @keyword x_data_type: The category of the X-axis data.
311 @type x_data_type: str
312 @keyword y_data_type: The category of the Y-axis data.
313 @type y_data_type: str
314 @keyword spin_id: The spin identification string.
315 @type spin_id: str
316 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
317 @type plot_data: str
318 @keyword file: The name of the Grace file to create.
319 @type file: str
320 @keyword dir: The optional directory to place the file into.
321 @type dir: str
322 @param force: Boolean argument which if True causes the file to be overwritten if it
323 already exists.
324 @type force: bool
325 @keyword norm: The normalisation flag which if set to True will cause all graphs to be
326 normalised to a starting value of 1.
327 @type norm: bool
328 """
329
330
331 pipes.test()
332
333
334 if not exists_mol_res_spin_data():
335 raise RelaxNoSequenceError
336
337
338 if plot_data not in ['value', 'error', 'sim']:
339 raise RelaxError("The plot data argument " + repr(plot_data) + " must be set to either 'value', 'error', 'sim'.")
340
341
342 if plot_data == 'sim' and not hasattr(cdp, 'sim_number'):
343 raise RelaxNoSimError
344
345
346 file_path = get_file_path(file, dir)
347 file = open_write_file(file, dir, force)
348
349
350 data, set_names, graph_type = get_data(spin_id, x_data_type=x_data_type, y_data_type=y_data_type, plot_data=plot_data)
351
352
353 if not len(data) or not len(data[0]) or not len(data[0][0]):
354 warn(RelaxWarning("No data could be found, creating an empty file."))
355 file.close()
356 return
357
358
359 seq_type = [None, None]
360 if x_data_type == 'spin':
361 seq_type[0] = 'res'
362 if y_data_type == 'spin':
363 seq_type[1] = 'res'
364
365
366 write_xy_header(sets=len(data[0]), file=file, data_type=[x_data_type, y_data_type], seq_type=seq_type, set_names=set_names, norm=norm)
367
368
369 write_xy_data(data, file=file, graph_type=graph_type, norm=norm)
370
371
372 file.close()
373
374
375 if not hasattr(cdp, 'result_files'):
376 cdp.result_files = []
377 cdp.result_files.append(['grace', 'Grace', file_path])
378 status.observers.result_file.notify()
379
380
381
383 """Write the data into the Grace xy-scatter plot.
384
385 The numerical data should be supplied as a 4 dimensional list or array object. The first dimension corresponds to the graphs, Gx. The second corresponds the sets of each graph, Sx. The third corresponds to the data series (i.e. each data point). The forth is a list of the information about each point, it is a list where the first element is the x value, the second is the y value, the third is the optional dx or dy error (either dx or dy dependent upon the graph_type arg), and the forth is the optional dy error when graph_type is xydxdy (the third position is then dx).
386
387
388 @param data: The 4D structure of numerical data to graph (see docstring).
389 @type data: list of lists of lists of float
390 @keyword file: The file object to write the data to.
391 @type file: file object
392 @keyword graph_type: The graph type which can be one of xy, xydy, xydx, or xydxdy.
393 @type graph_type: str
394 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1.
395 @type norm: bool
396 """
397
398
399 comment_col = 2
400 if graph_type in ['xydx', 'xydy']:
401 comment_col = 3
402 elif graph_type == 'xydxdy':
403 comment_col = 4
404
405
406 for gi in range(len(data)):
407
408 for si in range(len(data[gi])):
409
410 file.write("@target G%s.S%s\n" % (gi, si))
411 file.write("@type %s\n" % graph_type)
412
413
414 norm_fact = 1.0
415 if norm:
416 norm_fact = data[gi][si][0][1]
417
418
419 for point in data[gi][si]:
420
421 if point[0] == None or point[1] == None:
422 continue
423
424
425 file.write("%-30s %-30s" % (point[0], point[1]/norm_fact))
426
427
428 if graph_type in ['xydx', 'xydy', 'xydxdy']:
429
430 error = point[2]
431 if error == None:
432 error = 0.0
433
434
435 file.write(" %-30s" % (error/norm_fact))
436
437
438 if graph_type == 'xydxdy':
439
440 error = point[3]
441 if error == None:
442 error = 0.0
443
444
445 file.write(" %-30s" % (error/norm_fact))
446
447
448 try:
449 file.write("%30s \"# %s\"" % ('', point[comment_col]))
450 except IndexError:
451 pass
452
453
454 file.write("\n")
455
456
457 file.write("&\n")
458
459
461 """Write the grace header for xy-scatter plots.
462
463 Many of these keyword arguments should be supplied in a [X, Y] list format, where the first element corresponds to the X data, and the second the Y data. Defaults will be used for any non-supplied args (or lists with elements set to None).
464
465
466 @keyword file: The file object to write the data to.
467 @type file: file object
468 @keyword paper_size: The paper size, i.e. 'A4'. If set to None, this will default to letter size.
469 @type paper_size: str
470 @keyword title: The title of the graph.
471 @type title: None or str
472 @keyword subtitle: The sub-title of the graph.
473 @type subtitle: None or str
474 @keyword view: List of 4 coordinates defining the graph view port.
475 @type view: None or list of float
476 @keyword sets: The number of data sets in the graph G0.
477 @type sets: int
478 @keyword set_names: The names associated with each graph data set G0.Sx. For example this can be a list of spin identification strings.
479 @type set_names: None or list of str
480 @keyword set_colours: The colours for each graph data set G0.Sx.
481 @type set_colours: None or list of int
482 @keyword symbols: The symbol style for each graph data set G0.Sx.
483 @type symbols: None or list of int
484 @keyword symbol_sizes: The symbol size for each graph data set G0.Sx.
485 @type symbol_sizes: None or list of int
486 @keyword symbol_fill: The symbol file style for each graph data set G0.Sx.
487 @type symbol_fill: None or list of int
488 @keyword linestyle: The line style for each graph data set G0.Sx.
489 @type linestyle: None or list of int
490 @keyword linetype: The line type for each graph data set G0.Sx.
491 @type linetype: None or list of int
492 @keyword linewidth: The line width for all elements of each graph data set G0.Sx.
493 @type linewidth: None or float
494 @keyword data_type: The axis data category (in the [X, Y] list format).
495 @type data_type: None or list of str
496 @keyword seq_type: The sequence data type (in the [X, Y] list format). This is for molecular sequence specific data and can be one of 'res', 'spin', or 'mixed'.
497 @type seq_type: None or list of str
498 @keyword axis_labels: The labels for the axes (in the [X, Y] list format).
499 @type axis_labels: None or list of str
500 @keyword axis_min: The minimum values for specifying the graph ranges (in the [X, Y] list format).
501 @type axis_min: None or list of str
502 @keyword axis_max: The maximum values for specifying the graph ranges (in the [X, Y] list format).
503 @type axis_max: None or list of str
504 @keyword legend_pos: The position of the legend, e.g. [0.3, 0.8].
505 @type legend_pos: None or list of float
506 @keyword legend: If True, the legend will be visible.
507 @type legend: bool
508 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1.
509 @type norm: bool
510 """
511
512
513 if not data_type:
514 data_type = [None, None]
515 if not seq_type:
516 seq_type = [None, None]
517 if not axis_labels:
518 axis_labels = [None, None]
519 if not axis_min:
520 axis_min = [None, None]
521 if not axis_max:
522 axis_max = [None, None]
523
524
525 file.write("@version 50121\n")
526
527
528 if paper_size == 'A4':
529 file.write("@page size 842, 595\n")
530
531
532 file.write("@with g0\n")
533
534
535 if not view:
536 view = [0.15, 0.15, 1.28, 0.85]
537 file.write("@ view %s, %s, %s, %s\n" % (view[0], view[1], view[2], view[3]))
538
539
540 if title:
541 file.write("@ title \"%s\"\n" % title)
542 if subtitle:
543 file.write("@ subtitle \"%s\"\n" % subtitle)
544
545
546 axes = ['x', 'y']
547 for i in range(2):
548
549 analysis_spec = False
550 if pipes.cdp_name():
551
552 analysis_spec = True
553
554
555 return_units = specific_fns.setup.get_specific_fn('return_units', pipes.get_type())
556 return_grace_string = specific_fns.setup.get_specific_fn('return_grace_string', pipes.get_type())
557
558
559 if data_type[i] and data_type[i] != 'spin' and generic_fns.minimise.return_data_name(data_type[i]):
560 return_units = generic_fns.minimise.return_units
561 return_grace_string = generic_fns.minimise.return_grace_string
562
563
564 if data_type[i] == 'spin':
565
566 if seq_type[i] == 'res':
567
568 if not axis_min[i]:
569 axis_min[i] = repr(cdp.mol[0].res[0].num - 1)
570 if not axis_max[i]:
571 axis_max[i] = repr(cdp.mol[0].res[-1].num + 1)
572
573
574 if not axis_labels[i]:
575 axis_labels[i] = "Residue number"
576
577
578 if seq_type[i] == 'spin':
579
580 if not axis_min[i]:
581 axis_min[i] = repr(cdp.mol[0].res[0].spin[0].num - 1)
582 if not axis_max[i]:
583 axis_max[i] = repr(cdp.mol[0].res[0].spin[-1].num + 1)
584
585
586 if not axis_labels[i]:
587 axis_labels[i] = "Spin number"
588
589
590 if seq_type[i] == 'mixed':
591
592 if not axis_labels[i]:
593 axis_labels[i] = "Spin identification string"
594
595
596 else:
597
598 if analysis_spec and not axis_labels[i]:
599
600 units = return_units(data_type[i])
601
602
603 axis_labels[i] = return_grace_string(data_type[i])
604
605
606 if units:
607 axis_labels[i] = axis_labels[i] + "\\N (" + units + ")"
608
609
610 if norm and axes[i] == 'y':
611 axis_labels[i] = axis_labels[i] + " \\N\\q(normalised)\\Q"
612
613
614 if axis_min[i] != None:
615 file.write("@ world %smin %s\n" % (axes[i], axis_min[i]))
616 if axis_max[i] != None:
617 file.write("@ world %smax %s\n" % (axes[i], axis_max[i]))
618 if axis_labels[i]:
619 file.write("@ %saxis label \"%s\"\n" % (axes[i], axis_labels[i]))
620 file.write("@ %saxis label char size 1.48\n" % axes[i])
621 file.write("@ %saxis tick major size 0.75\n" % axes[i])
622 file.write("@ %saxis tick major linewidth %s\n" % (axes[i], linewidth))
623 file.write("@ %saxis tick minor linewidth %s\n" % (axes[i], linewidth))
624 file.write("@ %saxis tick minor size 0.45\n" % axes[i])
625 file.write("@ %saxis ticklabel char size 1.00\n" % axes[i])
626
627
628 if legend_pos:
629 file.write("@ legend %s, %s\n" % (legend_pos[0], legend_pos[1]))
630 if legend:
631 file.write("@ legend off\n")
632
633
634 file.write("@ frame linewidth %s\n" % linewidth)
635
636
637 for i in range(sets):
638
639 if symbols:
640 file.write("@ s%i symbol %i\n" % (i, symbols[i]))
641 else:
642
643 num = (i+1) - (i+1) / 11 * 10
644
645
646 file.write("@ s%i symbol %i\n" % (i, num))
647
648
649 if symbol_sizes:
650 file.write("@ s%i symbol size %s\n" % (i, symbol_sizes[i]))
651 else:
652 file.write("@ s%i symbol size 0.45\n" % i)
653
654
655 if symbol_fill:
656 file.write("@ s%i symbol fill pattern %i\n" % (i, symbol_fill[i]))
657
658
659 file.write("@ s%i symbol linewidth %s\n" % (i, linewidth))
660
661
662 if set_colours:
663 file.write("@ s%i symbol color %s\n" % (i, set_colours[i]))
664
665
666 file.write("@ s%i errorbar size 0.5\n" % i)
667 file.write("@ s%i errorbar linewidth %s\n" % (i, linewidth))
668 file.write("@ s%i errorbar riser linewidth %s\n" % (i, linewidth))
669
670
671 if linestyle:
672 file.write("@ s%i line linestyle %s\n" % (i, linestyle[i]))
673
674
675 if linetype:
676 file.write("@ s%i line type %s\n" % (i, linetype[i]))
677
678
679 if set_colours:
680 file.write("@ s%i line color %s\n" % (i, set_colours[i]))
681
682
683 if set_names and set_names[i]:
684 file.write("@ s%i legend \"%s\"\n" % (i, set_names[i]))
685