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