1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for interfacing with Grace (also known as Xmgrace, Xmgr, and ace)."""
24
25
26 from numpy import array, ndarray
27 from os import system
28 from warnings import warn
29
30
31 import generic_fns
32 from generic_fns.mol_res_spin import count_molecules, count_residues, count_spins, exists_mol_res_spin_data, generate_spin_id, spin_loop
33 from generic_fns import pipes
34 from generic_fns.result_files import add_result_file
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:
216 if spin.name not in spin_names:
217
218 data[0].append([])
219
220
221 set_labels.append("%s spins. " % spin.name + set_label)
222
223
224 spin_names.append(spin.name)
225
226
227 index = i * len(spin_names) + spin_names.index(spin.name)
228
229
230 else:
231 index = spin_names.index(spin.name)
232
233
234 for j in range(len(x_val)):
235
236 data[0][index].append([])
237 point = data[0][index][-1]
238
239
240 if x_data_type != 'spin':
241 x_val[j] = x_val[j] / x_return_conversion_factor(x_data_type)
242 if x_err[j] and x_data_type != 'spin':
243 x_err[j] = x_err[j] / x_return_conversion_factor(x_data_type)
244 y_val[j] = y_val[j] / y_return_conversion_factor(y_data_type)
245 if y_err[j] and y_data_type != 'spin':
246 y_err[j] = y_err[j] / y_return_conversion_factor(y_data_type)
247
248
249 point.append(x_val[j])
250 point.append(y_val[j])
251 point.append(x_err[j])
252 point.append(y_err[j])
253
254
255 if x_err[j] and not x_err_flag:
256 x_err_flag = True
257 if y_err[j] and not y_err_flag:
258 y_err_flag = True
259
260
261 graph_type = 'xy'
262 if x_err_flag:
263 graph_type = graph_type + 'dx'
264 if y_err_flag:
265 graph_type = graph_type + 'dy'
266
267
268 new_data = []
269 for i in range(len(data)):
270 new_data.append([])
271 for j in range(len(data[i])):
272 new_data[i].append([])
273 for k in range(len(data[i][j])):
274
275 new_data[i][j].append([])
276 new_data[i][j][k].append(data[i][j][k][0])
277 new_data[i][j][k].append(data[i][j][k][1])
278
279
280 if graph_type in ['xydx', 'xydxdy']:
281 new_data[i][j][k].append(data[i][j][k][2])
282
283
284 if graph_type in ['xydy', 'xydxdy']:
285 new_data[i][j][k].append(data[i][j][k][3])
286
287
288 return new_data, set_labels, graph_type
289
290
333
334
335 -def view(file=None, dir=None, grace_exe='xmgrace'):
336 """Execute Grace.
337
338 @keyword file: The name of the file to open in Grace.
339 @type file: str
340 @keyword dir: The optional directory containing the file.
341 @type dir: str
342 @keyword grace_exe: The name of the Grace executable file. This should be located within the
343 system path.
344 @type grace_exe: str
345 """
346
347
348 test_binary(grace_exe)
349
350
351 file_path = get_file_path(file, dir)
352
353
354 system(grace_exe + " " + file_path + " &")
355
356
357 -def write(x_data_type='spin', y_data_type=None, spin_id=None, plot_data='value', file=None, dir=None, force=False, norm=True):
358 """Writing data to a file.
359
360 @keyword x_data_type: The category of the X-axis data.
361 @type x_data_type: str
362 @keyword y_data_type: The category of the Y-axis data.
363 @type y_data_type: str
364 @keyword spin_id: The spin identification string.
365 @type spin_id: str
366 @keyword plot_data: The type of the plotted data, one of 'value', 'error', or 'sim'.
367 @type plot_data: str
368 @keyword file: The name of the Grace file to create.
369 @type file: str
370 @keyword dir: The optional directory to place the file into.
371 @type dir: str
372 @param force: Boolean argument which if True causes the file to be overwritten if it
373 already exists.
374 @type force: bool
375 @keyword norm: The normalisation flag which if set to True will cause all graphs to be
376 normalised to a starting value of 1.
377 @type norm: bool
378 """
379
380
381 pipes.test()
382
383
384 if not exists_mol_res_spin_data():
385 raise RelaxNoSequenceError
386
387
388 if plot_data not in ['value', 'error', 'sim']:
389 raise RelaxError("The plot data argument " + repr(plot_data) + " must be set to either 'value', 'error', 'sim'.")
390
391
392 if plot_data == 'sim' and not hasattr(cdp, 'sim_number'):
393 raise RelaxNoSimError
394
395
396 file_path = get_file_path(file, dir)
397 file = open_write_file(file, dir, force)
398
399
400 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)
401
402
403 if not len(data) or not len(data[0]) or not len(data[0][0]):
404 warn(RelaxWarning("No data could be found, creating an empty file."))
405 file.close()
406 return
407
408
409 seq_type = [None, None]
410 if x_data_type == 'spin':
411 seq_type[0] = 'res'
412 if y_data_type == 'spin':
413 seq_type[1] = 'res'
414
415
416 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)
417
418
419 write_xy_data(data, file=file, graph_type=graph_type, norm=norm)
420
421
422 file.close()
423
424
425 add_result_file(type='grace', label='Grace', file=file_path)
426
427
429 """Write the data into the Grace xy-scatter plot.
430
431 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).
432
433
434 @param data: The 4D structure of numerical data to graph (see docstring).
435 @type data: list of lists of lists of float
436 @keyword file: The file object to write the data to.
437 @type file: file object
438 @keyword graph_type: The graph type which can be one of xy, xydy, xydx, or xydxdy.
439 @type graph_type: str
440 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1.
441 @type norm: bool
442 """
443
444
445 comment_col = 2
446 if graph_type in ['xydx', 'xydy']:
447 comment_col = 3
448 elif graph_type == 'xydxdy':
449 comment_col = 4
450
451
452 for gi in range(len(data)):
453
454 for si in range(len(data[gi])):
455
456 file.write("@target G%s.S%s\n" % (gi, si))
457 file.write("@type %s\n" % graph_type)
458
459
460 norm_fact = 1.0
461 if norm:
462 norm_fact = data[gi][si][0][1]
463
464
465 for point in data[gi][si]:
466
467 if point[0] == None or point[1] == None:
468 continue
469
470
471 file.write("%-30s %-30.15f" % (point[0], point[1]/norm_fact))
472
473
474 if graph_type in ['xydx', 'xydy', 'xydxdy']:
475
476 error = point[2]
477 if error == None:
478 error = 0.0
479
480
481 file.write(" %-30.15f" % (error/norm_fact))
482
483
484 if graph_type == 'xydxdy':
485
486 error = point[3]
487 if error == None:
488 error = 0.0
489
490
491 file.write(" %-30.15f" % (error/norm_fact))
492
493
494 try:
495 file.write("%30s \"# %s\"" % ('', point[comment_col]))
496 except IndexError:
497 pass
498
499
500 file.write("\n")
501
502
503 file.write("&\n")
504
505
507 """Write the grace header for xy-scatter plots.
508
509 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).
510
511
512 @keyword file: The file object to write the data to.
513 @type file: file object
514 @keyword paper_size: The paper size, i.e. 'A4'. If set to None, this will default to letter size.
515 @type paper_size: str
516 @keyword title: The title of the graph.
517 @type title: None or str
518 @keyword subtitle: The sub-title of the graph.
519 @type subtitle: None or str
520 @keyword view: List of 4 coordinates defining the graph view port.
521 @type view: None or list of float
522 @keyword sets: The number of data sets in the graph G0.
523 @type sets: int
524 @keyword set_names: The names associated with each graph data set G0.Sx. For example this can be a list of spin identification strings.
525 @type set_names: None or list of str
526 @keyword set_colours: The colours for each graph data set G0.Sx.
527 @type set_colours: None or list of int
528 @keyword symbols: The symbol style for each graph data set G0.Sx.
529 @type symbols: None or list of int
530 @keyword symbol_sizes: The symbol size for each graph data set G0.Sx.
531 @type symbol_sizes: None or list of int
532 @keyword symbol_fill: The symbol file style for each graph data set G0.Sx.
533 @type symbol_fill: None or list of int
534 @keyword linestyle: The line style for each graph data set G0.Sx.
535 @type linestyle: None or list of int
536 @keyword linetype: The line type for each graph data set G0.Sx.
537 @type linetype: None or list of int
538 @keyword linewidth: The line width for all elements of each graph data set G0.Sx.
539 @type linewidth: None or float
540 @keyword data_type: The axis data category (in the [X, Y] list format).
541 @type data_type: None or list of str
542 @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'.
543 @type seq_type: None or list of str
544 @keyword axis_labels: The labels for the axes (in the [X, Y] list format).
545 @type axis_labels: None or list of str
546 @keyword axis_min: The minimum values for specifying the graph ranges (in the [X, Y] list format).
547 @type axis_min: None or list of str
548 @keyword axis_max: The maximum values for specifying the graph ranges (in the [X, Y] list format).
549 @type axis_max: None or list of str
550 @keyword legend_pos: The position of the legend, e.g. [0.3, 0.8].
551 @type legend_pos: None or list of float
552 @keyword legend: If True, the legend will be visible.
553 @type legend: bool
554 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1.
555 @type norm: bool
556 """
557
558
559 if not data_type:
560 data_type = [None, None]
561 if not seq_type:
562 seq_type = [None, None]
563 if not axis_labels:
564 axis_labels = [None, None]
565 if not axis_min:
566 axis_min = [None, None]
567 if not axis_max:
568 axis_max = [None, None]
569
570
571 file.write("@version 50121\n")
572
573
574 if paper_size == 'A4':
575 file.write("@page size 842, 595\n")
576
577
578 file.write("@with g0\n")
579
580
581 if not view:
582 view = [0.15, 0.15, 1.28, 0.85]
583 file.write("@ view %s, %s, %s, %s\n" % (view[0], view[1], view[2], view[3]))
584
585
586 if title:
587 file.write("@ title \"%s\"\n" % title)
588 if subtitle:
589 file.write("@ subtitle \"%s\"\n" % subtitle)
590
591
592 axes = ['x', 'y']
593 for i in range(2):
594
595 analysis_spec = False
596 if pipes.cdp_name():
597
598 analysis_spec = True
599
600
601 return_units = specific_fns.setup.get_specific_fn('return_units', pipes.get_type())
602 return_grace_string = specific_fns.setup.get_specific_fn('return_grace_string', pipes.get_type())
603
604
605 if data_type[i] and data_type[i] != 'spin' and generic_fns.minimise.return_data_name(data_type[i]):
606 return_units = generic_fns.minimise.return_units
607 return_grace_string = generic_fns.minimise.return_grace_string
608
609
610 if data_type[i] == 'spin':
611
612 if seq_type[i] == 'res':
613
614 if not axis_min[i]:
615 axis_min[i] = repr(cdp.mol[0].res[0].num - 1)
616 if not axis_max[i]:
617 axis_max[i] = repr(cdp.mol[0].res[-1].num + 1)
618
619
620 if not axis_labels[i]:
621 axis_labels[i] = "Residue number"
622
623
624 if seq_type[i] == 'spin':
625
626 if not axis_min[i]:
627 axis_min[i] = repr(cdp.mol[0].res[0].spin[0].num - 1)
628 if not axis_max[i]:
629 axis_max[i] = repr(cdp.mol[0].res[0].spin[-1].num + 1)
630
631
632 if not axis_labels[i]:
633 axis_labels[i] = "Spin number"
634
635
636 if seq_type[i] == 'mixed':
637
638 if not axis_labels[i]:
639 axis_labels[i] = "Spin identification string"
640
641
642 else:
643
644 if analysis_spec and not axis_labels[i]:
645
646 units = return_units(data_type[i])
647
648
649 axis_labels[i] = return_grace_string(data_type[i])
650
651
652 if units:
653 axis_labels[i] = axis_labels[i] + "\\N (" + units + ")"
654
655
656 if norm and axes[i] == 'y':
657 axis_labels[i] = axis_labels[i] + " \\N\\q(normalised)\\Q"
658
659
660 if axis_min[i] != None:
661 file.write("@ world %smin %s\n" % (axes[i], axis_min[i]))
662 if axis_max[i] != None:
663 file.write("@ world %smax %s\n" % (axes[i], axis_max[i]))
664 if axis_labels[i]:
665 file.write("@ %saxis label \"%s\"\n" % (axes[i], axis_labels[i]))
666 file.write("@ %saxis label char size 1.48\n" % axes[i])
667 file.write("@ %saxis tick major size 0.75\n" % axes[i])
668 file.write("@ %saxis tick major linewidth %s\n" % (axes[i], linewidth))
669 file.write("@ %saxis tick minor linewidth %s\n" % (axes[i], linewidth))
670 file.write("@ %saxis tick minor size 0.45\n" % axes[i])
671 file.write("@ %saxis ticklabel char size 1.00\n" % axes[i])
672
673
674 if legend_pos:
675 file.write("@ legend %s, %s\n" % (legend_pos[0], legend_pos[1]))
676 if legend:
677 file.write("@ legend off\n")
678
679
680 file.write("@ frame linewidth %s\n" % linewidth)
681
682
683 for i in range(sets):
684
685 if symbols:
686 file.write("@ s%i symbol %i\n" % (i, symbols[i]))
687 else:
688
689 num = i % 10 + 1
690
691
692 file.write("@ s%i symbol %i\n" % (i, num))
693
694
695 if symbol_sizes:
696 file.write("@ s%i symbol size %s\n" % (i, symbol_sizes[i]))
697 else:
698 file.write("@ s%i symbol size 0.45\n" % i)
699
700
701 if symbol_fill:
702 file.write("@ s%i symbol fill pattern %i\n" % (i, symbol_fill[i]))
703
704
705 file.write("@ s%i symbol linewidth %s\n" % (i, linewidth))
706
707
708 if set_colours:
709 file.write("@ s%i symbol color %s\n" % (i, set_colours[i]))
710
711
712 file.write("@ s%i errorbar size 0.5\n" % i)
713 file.write("@ s%i errorbar linewidth %s\n" % (i, linewidth))
714 file.write("@ s%i errorbar riser linewidth %s\n" % (i, linewidth))
715
716
717 if linestyle:
718 file.write("@ s%i line linestyle %s\n" % (i, linestyle[i]))
719
720
721 if linetype:
722 file.write("@ s%i line type %s\n" % (i, linetype[i]))
723
724
725 if set_colours:
726 file.write("@ s%i line color %s\n" % (i, set_colours[i]))
727
728
729 if set_names and set_names[i]:
730 file.write("@ s%i legend \"%s\"\n" % (i, set_names[i]))
731