Package lib :: Package software :: Module grace
[hide private]
[frames] | no frames]

Source Code for Module lib.software.grace

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2013 Edward d'Auvergne                                   # 
  4  # Copyright (C) 2013 Troels E. Linnet                                         # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """Module for interfacing with Grace (also known as Xmgrace, Xmgr, and ace).""" 
 25   
 26  # Python module imports. 
 27  from math import ceil, sqrt 
 28   
 29  # relax module imports. 
 30  import pipe_control 
 31  from pipe_control import pipes 
 32  import specific_analyses 
 33   
 34  # This script is used to batch convert the Grace *.agr files into graphics files using the Grace 
 35  # program itself. 
 36   
37 -def script_grace2images(file=None):
38 """Write a python "grace to PNG/EPS/SVG..." conversion script.. 39 40 The makes a conversion script to image types as PNG/EPS/SVG. The conversion is looping over a directory list of *.agr files, and making function calls to xmgrace. Successful conversion of images depends on the compilation of xmgrace. The input is a list of image types which is wanted, f.ex: PNG EPS SVG. PNG is default. 41 42 @keyword file: The file object to write the data to. 43 @type file: file object 44 """ 45 46 # Write to file 47 file.write("#!/usr/bin/env python\n") 48 file.write("#\n") 49 file.write("# This script is used to batch convert the Grace *.agr files into graphics bitmap files using the\n") 50 file.write("# Grace program itself. Therefore you will need to install on your system xmgrace,\n") 51 file.write("# (http://plasma-gate.weizmann.ac.il/Grace/), qtgrace (http://sourceforge.net/projects/qtgrace/)\n") 52 file.write("# or gracegtk (http://sourceforge.net/projects/gracegtk/).\n") 53 file.write("\n") 54 file.write("import glob, os, sys\n") 55 file.write("import shlex, subprocess\n") 56 file.write("import optparse\n") 57 file.write("\n") 58 file.write("# Define a callback function, for a multiple input of PNG, EPS, SVG\n") 59 file.write("def foo_callback(option, opt, value, parser):\n") 60 file.write(" setattr(parser.values, option.dest, value.split(','))\n") 61 file.write("\n") 62 file.write("# Add functioning for argument parsing\n") 63 file.write("parser = optparse.OptionParser(description='Process grace files to images')\n") 64 file.write("# Add argument type. Destination instance is set to types.\n") 65 file.write("parser.add_option('-g', action='store_true', dest='relax_gui', default=False, help='Make it possible to run script through relax GUI. Run by using User-functions -> script')\n") 66 file.write("parser.add_option('-l', action='callback', callback=foo_callback, dest='l', type=\"string\", default=False, help='Make in possible to run scriptif relax has logfile turned on. Run by using User-functions -> script')\n") 67 file.write("parser.add_option('-t', action='callback', callback=foo_callback, dest='types', type=\"string\", default=[], help='List image types for conversion. Execute script with: python %s -t PNG,EPS ...'%(sys.argv[0]))\n") 68 file.write("\n") 69 file.write("# Parse the arguments to a Class instance object\n") 70 file.write("args = parser.parse_args()\n") 71 file.write("\n") 72 file.write("# Lets print help if no arguments are passed\n") 73 file.write("if len(sys.argv) == 1 or len(args[0].types) == 0:\n") 74 file.write(" print('system argument is:', sys.argv)\n") 75 file.write(" parser.print_help()\n") 76 file.write(" print('Performing a default PNG conversion')\n") 77 file.write(" # If no input arguments, we make a default PNG option\n") 78 file.write(" args[0].types = ['PNG']\n") 79 file.write("\n") 80 file.write("# If we run through the GUI we cannot pass input arguments so we make a default PNG option\n") 81 file.write("if args[0].relax_gui:\n") 82 file.write(" args[0].types = ['PNG']\n") 83 file.write("\n") 84 file.write("types = list(args[0].types)\n") 85 file.write("\n") 86 file.write("# A easy search for files with *.agr, is to use glob, which is pathnames matching a specified pattern according to the rules used by the Unix shell, not opening a shell\n") 87 file.write("gracefiles = glob.glob(\"*.agr\")\n") 88 file.write("\n") 89 file.write("# For png conversion, several parameters can be passed to xmgrace. These can be altered later afterwards and the script rerun. \n") 90 file.write("# The option for transparent is good for poster or insertion in color backgrounds. The ability for this still depends on xmgrace compilation\n") 91 file.write("if \"PNG\" in types:\n") 92 file.write(" pngpar = \"png.par\"\n") 93 file.write(" if not os.path.isfile(pngpar):\n") 94 file.write(" wpngpar = open(pngpar, \"w\")\n") 95 file.write(" wpngpar.write(\"DEVICE \\\"PNG\\\" FONT ANTIALIASING on\\n\")\n") 96 file.write(" wpngpar.write(\"DEVICE \\\"PNG\\\" OP \\\"transparent:on\\\"\\n\")\n") 97 file.write(" wpngpar.write(\"DEVICE \\\"PNG\\\" OP \\\"compression:9\\\"\\n\")\n") 98 file.write(" wpngpar.close()\n") 99 file.write("\n") 100 file.write("# Now loop over the grace files\n") 101 file.write("for grace in gracefiles:\n") 102 file.write(" # Get the filename without extension\n") 103 file.write(" fname = grace.split(\".agr\")[0]\n") 104 file.write(" if (\"PNG\" in types or \".PNG\" in types or \"png\" in types or \".png\" in types):\n") 105 file.write(" # Produce the argument string\n") 106 file.write(" im_args = r\"xmgrace -hdevice PNG -hardcopy -param %s -printfile %s.png %s\" % (pngpar, fname, grace)\n") 107 file.write(" # Split the arguments the right way to call xmgrace\n") 108 file.write(" im_args = shlex.split(im_args)\n") 109 file.write(" return_code = subprocess.call(im_args)\n") 110 file.write(" if (\"EPS\" in types or \".EPS\" in types or \"eps\" in types or \".eps\" in types):\n") 111 file.write(" im_args = r\"xmgrace -hdevice EPS -hardcopy -printfile %s.eps %s\" % (fname, grace)\n") 112 file.write(" im_args = shlex.split(im_args)\n") 113 file.write(" return_code = subprocess.call(im_args)\n") 114 file.write(" if (\"JPG\" in types or \".JPG\" in types or \"jpg\" in types or \".jpg\" in types):\n") 115 file.write(" im_args = r\"xmgrace -hdevice JPEG -hardcopy -printfile %s.jpg %s\" % (fname, grace)\n") 116 file.write(" im_args = shlex.split(im_args)\n") 117 file.write(" if (\"JPEG\" in types or \".JPEG\" in types or \"jpeg\" in types or \".jpeg\" in types):\n") 118 file.write(" im_args = r\"xmgrace -hdevice JPEG -hardcopy -printfile %s.jpg %s\" % (fname, grace)\n") 119 file.write(" im_args = shlex.split(im_args)\n") 120 file.write(" return_code = subprocess.call(im_args)\n") 121 file.write(" if (\"SVG\" in types or \".SVG\" in types or \"svg\" in types or \".svg\" in types):\n") 122 file.write(" im_args = r\"xmgrace -hdevice SVG -hardcopy -printfile %s.svg %s\" % (fname, grace)\n") 123 file.write(" im_args = shlex.split(im_args)\n") 124 file.write(" return_code = subprocess.call(im_args)\n")
125 126
127 -def write_xy_data(data, file=None, graph_type=None, norm=None):
128 """Write the data into the Grace xy-scatter plot. 129 130 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). 131 132 133 @param data: The 4D structure of numerical data to graph (see docstring). 134 @type data: list of lists of lists of float 135 @keyword file: The file object to write the data to. 136 @type file: file object 137 @keyword graph_type: The graph type which can be one of xy, xydy, xydx, or xydxdy. 138 @type graph_type: str 139 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1. The first dimension is the graph. 140 @type norm: None or list of bool 141 """ 142 143 # Graph number. 144 graph_num = len(data) 145 146 # Defaults. 147 if not norm: 148 norm = [] 149 for gi in range(graph_num): 150 norm.append(False) 151 152 # Comment columns. 153 comment_col = 2 154 if graph_type in ['xydx', 'xydy']: 155 comment_col = 3 156 elif graph_type == 'xydxdy': 157 comment_col = 4 158 159 # Loop over the graphs. 160 for gi in range(graph_num): 161 # Loop over the data sets of the graph. 162 for si in range(len(data[gi])): 163 # The target and type. 164 file.write("@target G%s.S%s\n" % (gi, si)) 165 file.write("@type %s\n" % graph_type) 166 167 # Normalisation (to the first data point y value!). 168 norm_fact = 1.0 169 if norm[gi]: 170 norm_fact = data[gi][si][0][1] 171 172 # Loop over the data points. 173 for point in data[gi][si]: 174 # Bad data. 175 if point[0] == None or point[1] == None: 176 continue 177 178 # X and Y data. 179 file.write("%-30s %-30.15f" % (point[0], point[1]/norm_fact)) 180 181 # The dx and dy errors. 182 if graph_type in ['xydx', 'xydy', 'xydxdy']: 183 # Catch x or y-axis errors of None. 184 error = point[2] 185 if error == None: 186 error = 0.0 187 188 # Write the error. 189 file.write(" %-30.15f" % (error/norm_fact)) 190 191 # The dy errors of xydxdy. 192 if graph_type == 'xydxdy': 193 # Catch y-axis errors of None. 194 error = point[3] 195 if error == None: 196 error = 0.0 197 198 # Write the error. 199 file.write(" %-30.15f" % (error/norm_fact)) 200 201 # The comment if given. 202 try: 203 file.write("%30s \"# %s\"" % ('', point[comment_col])) 204 except IndexError: 205 pass 206 207 # End the point. 208 file.write("\n") 209 210 # End of the data set i. 211 file.write("&\n") 212 213 # Autoscaling of all graphs to avoid user confusion. 214 for i in range(graph_num): 215 file.write("@with g%i\n" % i) 216 file.write("@autoscale\n") 217 218 # Auto-arrange the graphs if multiple are present. 219 if len(data) > 1: 220 row_num = int(round(sqrt(len(data)))) 221 col_num = int(ceil(sqrt(len(data)))) 222 file.write("@arrange(%i, %i, .1, .1, .1, OFF, OFF, OFF)\n" % (row_num, col_num))
223 224
225 -def write_xy_header(file=None, paper_size='A4', title=None, subtitle=None, view=None, graph_num=1, sets=None, set_names=None, set_colours=None, x_axis_type_zero=None, y_axis_type_zero=None, symbols=None, symbol_sizes=None, symbol_fill=None, linestyle=None, linetype=None, linewidth=None, data_type=None, seq_type=None, axis_labels=None, legend=None, legend_pos=None, legend_box_fill_pattern=None, legend_char_size=None, norm=None):
226 """Write the grace header for xy-scatter plots. 227 228 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). 229 230 231 @keyword file: The file object to write the data to. 232 @type file: file object 233 @keyword paper_size: The paper size, i.e. 'A4'. If set to None, this will default to letter size. 234 @type paper_size: str 235 @keyword title: The title of the graph. 236 @type title: None or str 237 @keyword subtitle: The sub-title of the graph. 238 @type subtitle: None or str 239 @keyword view: List of 4 coordinates defining the graph view port. 240 @type view: None or list of float 241 @keyword graph_num: The total number of graphs. 242 @type graph_num: int 243 @keyword sets: The number of data sets in each graph. 244 @type sets: list of int 245 @keyword set_names: The names associated with each graph data set Gx.Sy. For example this can be a list of spin identification strings. The first dimension is the graph, the second is the set. 246 @type set_names: None or list of list of str 247 @keyword set_colours: The colours for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 248 @type set_colours: None or list of list of int 249 @keyword x_axis_type_zero: The flags specifying if the X-axis should be placed at zero. 250 @type x_axis_type_zero: None or list of lists of bool 251 @keyword y_axis_type_zero: The flags specifying if the Y-axis should be placed at zero. 252 @type y_axis_type_zero: None or list of lists of bool 253 @keyword symbols: The symbol style for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 254 @type symbols: None or list of list of int 255 @keyword symbol_sizes: The symbol size for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 256 @type symbol_sizes: None or list of list of int 257 @keyword symbol_fill: The symbol file style for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 258 @type symbol_fill: None or list of list of int 259 @keyword linestyle: The line style for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 260 @type linestyle: None or list of list of int 261 @keyword linetype: The line type for each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 262 @type linetype: None or list of list of int 263 @keyword linewidth: The line width for all elements of each graph data set Gx.Sy. The first dimension is the graph, the second is the set. 264 @type linewidth: None or list of float 265 @keyword data_type: The axis data category (in the [X, Y] list format). 266 @type data_type: None or list of list of str 267 @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'. 268 @type seq_type: None or list of list of str 269 @keyword axis_labels: The labels for the axes (in the [X, Y] list format). The first dimension is the graph. 270 @type axis_labels: None or list of list of str 271 @keyword legend: If True, the legend will be visible. The first dimension is the graph. 272 @type legend: list of bool 273 @keyword legend_pos: The position of the legend, e.g. [0.3, 0.8]. The first dimension is the graph. 274 @type legend_pos: None or list of list of float 275 @keyword legend_box_fill_pattern: The legend box fill. If set to 0, it will become transparent. 276 @type legend_box_fill_pattern: int 277 @keyword legend_char_size: The size of the legend box text. 278 @type legend_char_size: float 279 @keyword norm: The normalisation flag which if set to True will cause all graphs to be normalised to 1. The first dimension is the graph. 280 @type norm: list of bool 281 """ 282 283 # Defaults. 284 if sets == None: 285 sets = [] 286 for gi in range(graph_num): 287 sets.append(1) 288 if x_axis_type_zero == None: 289 x_axis_type_zero = [] 290 for gi in range(graph_num): 291 x_axis_type_zero.append(False) 292 if y_axis_type_zero == None: 293 y_axis_type_zero = [] 294 for gi in range(graph_num): 295 y_axis_type_zero.append(False) 296 if linewidth == None: 297 linewidth = [] 298 for gi in range(graph_num): 299 linewidth.append(0.5) 300 if norm == None: 301 norm = [] 302 for gi in range(graph_num): 303 norm.append(False) 304 if not legend_box_fill_pattern: 305 legend_box_fill_pattern = [] 306 for gi in range(graph_num): 307 legend_box_fill_pattern.append(1) 308 if not legend_char_size: 309 legend_char_size = [] 310 for gi in range(graph_num): 311 legend_char_size.append(1.0) 312 313 # Set the None args to lists as needed. 314 if not data_type: 315 data_type = [None, None] 316 if not seq_type: 317 seq_type = [None, None] 318 if not axis_labels: 319 axis_labels = [] 320 for gi in range(graph_num): 321 axis_labels.append([None, None]) 322 323 # Set the Grace version number of the header's formatting for compatibility. 324 file.write("@version 50121\n") 325 326 # The paper size. 327 if paper_size == 'A4': 328 file.write("@page size 842, 595\n") 329 330 # Loop over each graph. 331 for gi in range(graph_num): 332 # Graph Gi. 333 file.write("@with g%i\n" % gi) 334 335 # The view port. 336 if not view: 337 view = [0.15, 0.15, 1.28, 0.85] 338 file.write("@ view %s, %s, %s, %s\n" % (view[0], view[1], view[2], view[3])) 339 340 # The title and subtitle. 341 if title: 342 file.write("@ title \"%s\"\n" % title) 343 if subtitle: 344 file.write("@ subtitle \"%s\"\n" % subtitle) 345 346 # Axis at zero. 347 if x_axis_type_zero[gi]: 348 file.write("@ xaxis type zero true\n") 349 if y_axis_type_zero[gi]: 350 file.write("@ yaxis type zero true\n") 351 352 # Axis specific settings. 353 axes = ['x', 'y'] 354 for i in range(2): 355 # Analysis specific methods for making labels. 356 analysis_spec = False 357 if pipes.cdp_name(): 358 # Flag for making labels. 359 analysis_spec = True 360 361 # Specific value and error, conversion factor, and units returning functions. 362 return_units = specific_analyses.setup.get_specific_fn('return_units', pipes.get_type()) 363 return_grace_string = specific_analyses.setup.get_specific_fn('return_grace_string', pipes.get_type()) 364 365 # Test if the axis data type is a minimisation statistic. 366 if data_type[i] and data_type[i] != 'spin' and pipe_control.minimise.return_data_name(data_type[i]): 367 return_units = pipe_control.minimise.return_units 368 return_grace_string = pipe_control.minimise.return_grace_string 369 370 # Some axis default values for spin data. 371 if data_type[i] == 'spin': 372 # Residue only data. 373 if seq_type[i] == 'res': 374 # X-axis label. 375 if not axis_labels[gi][i]: 376 axis_labels[gi][i] = "Residue number" 377 378 # Spin only data. 379 if seq_type[i] == 'spin': 380 # X-axis label. 381 if not axis_labels[gi][i]: 382 axis_labels[gi][i] = "Spin number" 383 384 # Mixed data. 385 if seq_type[i] == 'mixed': 386 # X-axis label. 387 if not axis_labels[gi][i]: 388 axis_labels[gi][i] = "Spin identification string" 389 390 # Some axis default values for other data types. 391 else: 392 # Label. 393 if analysis_spec and (not axis_labels or not axis_labels[gi][i]): 394 # Get the units. 395 units = return_units(data_type[i]) 396 397 # Set the label. 398 axis_labels[gi][i] = return_grace_string(data_type[i]) 399 400 # Add units. 401 if units: 402 axis_labels[gi][i] = axis_labels[gi][i] + "\\N (" + units + ")" 403 404 # Normalised data. 405 if norm and norm[gi] and axes[i] == 'y': 406 axis_labels[gi][i] = axis_labels[gi][i] + " \\N\\q(normalised)\\Q" 407 408 # Write out the data. 409 if axis_labels[gi][i]: 410 file.write("@ %saxis label \"%s\"\n" % (axes[i], axis_labels[gi][i])) 411 file.write("@ %saxis label char size 1.00\n" % axes[i]) 412 file.write("@ %saxis tick major size 0.50\n" % axes[i]) 413 file.write("@ %saxis tick major linewidth %s\n" % (axes[i], linewidth[gi])) 414 file.write("@ %saxis tick minor linewidth %s\n" % (axes[i], linewidth[gi])) 415 file.write("@ %saxis tick minor size 0.25\n" % axes[i]) 416 file.write("@ %saxis ticklabel char size 0.70\n" % axes[i]) 417 418 # Legend box. 419 if legend != None and legend[gi]: 420 file.write("@ legend on\n") 421 else: 422 file.write("@ legend off\n") 423 if legend_pos != None: 424 file.write("@ legend %s, %s\n" % (legend_pos[gi][0], legend_pos[gi][1])) 425 file.write("@ legend box fill pattern %s\n" % legend_box_fill_pattern[gi]) 426 file.write("@ legend char size %s\n" % legend_char_size[gi]) 427 428 # Frame. 429 file.write("@ frame linewidth %s\n" % linewidth[gi]) 430 431 # Loop over each graph set. 432 for i in range(sets[gi]): 433 # Symbol style (default to all different symbols). 434 if symbols: 435 file.write("@ s%i symbol %i\n" % (i, symbols[gi][i])) 436 else: 437 # The symbol number (cycle between 1 and 10). 438 num = i % 10 + 1 439 440 # Write out. 441 file.write("@ s%i symbol %i\n" % (i, num)) 442 443 # Symbol sizes (default to a small size). 444 if symbol_sizes: 445 file.write("@ s%i symbol size %s\n" % (i, symbol_sizes[gi][i])) 446 else: 447 file.write("@ s%i symbol size 0.45\n" % i) 448 449 # The symbol fill. 450 if symbol_fill: 451 file.write("@ s%i symbol fill pattern %i\n" % (i, symbol_fill[gi][i])) 452 453 # The symbol line width. 454 file.write("@ s%i symbol linewidth %s\n" % (i, linewidth[gi])) 455 456 # Symbol colour (default to nothing). 457 if set_colours: 458 file.write("@ s%i symbol color %s\n" % (i, set_colours[gi][i])) 459 file.write("@ s%i symbol fill color %s\n" % (i, set_colours[gi][i])) 460 461 # Error bars. 462 file.write("@ s%i errorbar size 0.5\n" % i) 463 file.write("@ s%i errorbar linewidth %s\n" % (i, linewidth[gi])) 464 file.write("@ s%i errorbar riser linewidth %s\n" % (i, linewidth[gi])) 465 466 # Line linestyle (default to nothing). 467 if linestyle: 468 file.write("@ s%i line linestyle %s\n" % (i, linestyle[gi][i])) 469 470 # Line linetype (default to nothing). 471 if linetype: 472 file.write("@ s%i line type %s\n" % (i, linetype[gi][i])) 473 474 # Line and all other colours (default to nothing). 475 if set_colours: 476 file.write("@ s%i line color %s\n" % (i, set_colours[gi][i])) 477 file.write("@ s%i fill color %s\n" % (i, set_colours[gi][i])) 478 file.write("@ s%i avalue color %s\n" % (i, set_colours[gi][i])) 479 file.write("@ s%i errorbar color %s\n" % (i, set_colours[gi][i])) 480 481 # Legend. 482 if set_names and len(set_names) and len(set_names[gi]) and set_names[gi][i]: 483 file.write("@ s%i legend \"%s\"\n" % (i, set_names[gi][i]))
484