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

Source Code for Module lib.software.grace

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