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