Package generic_fns :: Module grace
[hide private]
[frames] | no frames]

Source Code for Module generic_fns.grace

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 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 numpy import array, ndarray 
 28  from os import system 
 29  from warnings import warn 
 30   
 31  # relax module imports. 
 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   
42 -def determine_seq_type(spin_id=None):
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 # Count the molecules, residues, and spins. 54 num_mol = count_molecules(spin_id) 55 num_res = count_residues(spin_id) 56 num_spin = count_spins(spin_id) 57 58 # Only residues. 59 if num_mol == 1 and num_spin == 1: 60 return 'res' 61 62 # Only spins. 63 if num_mol == 1 and num_res == 1: 64 return 'spin' 65 66 # Mixed. 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 # Initialise the 4D data structure (Gx, Sx, data point, data point info), and graph set labels. 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 # Specific x and y value returning functions. 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 # Test if the X-axis data type is a minimisation statistic. 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 # Test if the Y-axis data type is a minimisation statistic. 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 # Number of graph sets. 108 if plot_data == 'sim': 109 sets = cdp.sim_number 110 else: 111 sets = 1 112 113 # Loop over the data points. 114 for i in range(sets): 115 # The graph label. 116 set_label = '' 117 if plot_data == 'sim': 118 set_label = "Sim: %i" % i 119 120 # The sim number. 121 sim = None 122 if plot_data == 'sim': 123 sim = i 124 125 # Spin names list (for creating new graph sets). 126 spin_names = [] 127 128 # Loop over the spins. 129 for spin, mol_name, res_num, res_name, id in spin_loop(full_info=True, selection=spin_id, return_id=True): 130 # Skip deselected spins. 131 if not spin.select: 132 continue 133 134 # The X data (plotted as residue numbers). 135 if x_data_type == 'spin': 136 x_val = res_num 137 x_err = None 138 139 # The X data (plotted as values). 140 else: 141 # Append the x-axis values and errors. 142 x_val, x_err = x_return_value(spin, x_data_type, sim=sim) 143 144 # The Y data (plotted as residue numbers). 145 if y_data_type == 'spin': 146 y_val = res_num 147 y_err = None 148 149 # The Y data (plotted as values). 150 else: 151 # Append the y-axis values and errors. 152 y_val, y_err = y_return_value(spin, y_data_type, sim=sim) 153 154 # Go to the next spin if there is missing xy data. 155 if x_val == None or y_val == None: 156 continue 157 158 # One set per spin (list data has been returned). 159 if data_list or isinstance(x_val, list): 160 # Append a new set structure and set the name to the spin ID. 161 data[0].append([]) 162 set_labels.append("Spin %s" % id) 163 164 # The set index. 165 index = len(data[0]) - 1 166 167 # No errors. 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 # Data list flag. 174 data_list = True 175 176 # One set per spin (dictionary data has been returned). 177 if data_dict or isinstance(x_val, dict): 178 # Append a new set structure and set the name to the spin ID. 179 data[0].append([]) 180 set_labels.append("Spin %s" % id) 181 182 # The set index. 183 index = len(data[0]) - 1 184 185 # Convert to lists. 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 # Overwrite the data structures. 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 # No errors. 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 # Data list flag. 205 data_dict = True 206 207 # Convert the data to lists for packing into 1 point. 208 else: 209 x_val = [x_val] 210 y_val = [y_val] 211 x_err = [x_err] 212 y_err = [y_err] 213 214 # A new spin type (one data set per spin type). 215 if not data_list and not data_dict and spin.name not in spin_names: 216 # Append a new set structure. 217 data[0].append([]) 218 219 # Append the label. 220 set_labels.append("%s spins. " % spin.name + set_label) 221 222 # Add the spin name to the list. 223 spin_names.append(spin.name) 224 225 # The set index. 226 index = i * len(spin_names) + spin_names.index(spin.name) 227 228 # Loop over the points. 229 for j in range(len(x_val)): 230 # Initialise and alias point structure. 231 data[0][index].append([]) 232 point = data[0][index][-1] 233 234 # Conversion factors. 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 # Append the data. 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 # Error flags. 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 # The graph type. 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 # Remodel the data. 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 # The xy data. 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 # First error set. 275 if graph_type in ['xydx', 'xydxdy']: 276 new_data[i][j][k].append(data[i][j][k][2]) 277 278 # Second error set. 279 if graph_type in ['xydy', 'xydxdy']: 280 new_data[i][j][k].append(data[i][j][k][3]) 281 282 # Return the data. 283 return new_data, set_labels, graph_type
284 285
286 -def get_data_types():
287 """Get all of the data types to plot for the current data pipe. 288 289 @return: A list of lists of all the allowable data type descriptions and their values. 290 @rtype: list of list of str 291 """ 292 293 # Get the specific functions (return an empty list if a RelaxError occurs). 294 try: 295 data_names = specific_fns.setup.get_specific_fn('data_names', cdp.pipe_type, raise_error=False) 296 return_data_desc = specific_fns.setup.get_specific_fn('return_data_desc', cdp.pipe_type, raise_error=False) 297 except: 298 return [] 299 300 # The data names, if they exist. 301 names = data_names(set='params') 302 303 # Initialise the list and then add the sequence data. 304 data = [] 305 data.append(["Spin sequence", 'spin']) 306 307 # Loop over the parameters. 308 for name in (data_names(set='params') + data_names(set='generic')): 309 # Get the description. 310 try: 311 desc = return_data_desc(name) 312 except: 313 return [] 314 315 # No description. 316 if not desc: 317 text = name 318 319 # The text. 320 else: 321 text = "'%s': %s" % (name, desc) 322 323 # Append the description. 324 data.append([text, name]) 325 326 # Return the data. 327 return data
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 # Test the binary file string corresponds to a valid executable. 343 test_binary(grace_exe) 344 345 # File path. 346 file_path = get_file_path(file, dir) 347 348 # Run Grace. 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 # Test if the current pipe exists. 376 pipes.test() 377 378 # Test if the sequence data is loaded. 379 if not exists_mol_res_spin_data(): 380 raise RelaxNoSequenceError 381 382 # Test if the plot_data argument is one of 'value', 'error', or 'sim'. 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 # Test if the simulations exist. 387 if plot_data == 'sim' and not hasattr(cdp, 'sim_number'): 388 raise RelaxNoSimError 389 390 # Open the file for writing. 391 file_path = get_file_path(file, dir) 392 file = open_write_file(file, dir, force) 393 394 # Get the data. 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 # No data, so close the empty file and exit. 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 # Determine the sequence data type. 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 # Write the header. 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 # Write the data. 414 write_xy_data(data, file=file, graph_type=graph_type, norm=norm) 415 416 # Close the file. 417 file.close() 418 419 # Add the file to the results file list. 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
427 -def write_xy_data(data, file=None, graph_type=None, norm=False):
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 # Comment columns. 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 # Loop over the graphs. 451 for gi in range(len(data)): 452 # Loop over the data sets of the graph. 453 for si in range(len(data[gi])): 454 # The target and type. 455 file.write("@target G%s.S%s\n" % (gi, si)) 456 file.write("@type %s\n" % graph_type) 457 458 # Normalisation (to the first data point y value!). 459 norm_fact = 1.0 460 if norm: 461 norm_fact = data[gi][si][0][1] 462 463 # Loop over the data points. 464 for point in data[gi][si]: 465 # Bad data. 466 if point[0] == None or point[1] == None: 467 continue 468 469 # X and Y data. 470 file.write("%-30s %-30s" % (point[0], point[1]/norm_fact)) 471 472 # The dx and dy errors. 473 if graph_type in ['xydx', 'xydy', 'xydxdy']: 474 # Catch x or y-axis errors of None. 475 error = point[2] 476 if error == None: 477 error = 0.0 478 479 # Write the error. 480 file.write(" %-30s" % (error/norm_fact)) 481 482 # The dy errors of xydxdy. 483 if graph_type == 'xydxdy': 484 # Catch y-axis errors of None. 485 error = point[3] 486 if error == None: 487 error = 0.0 488 489 # Write the error. 490 file.write(" %-30s" % (error/norm_fact)) 491 492 # The comment if given. 493 try: 494 file.write("%30s \"# %s\"" % ('', point[comment_col])) 495 except IndexError: 496 pass 497 498 # End the point. 499 file.write("\n") 500 501 # End of the data set i. 502 file.write("&\n")
503 504
505 -def write_xy_header(file=None, paper_size='A4', title=None, subtitle=None, view=None, sets=1, set_names=None, set_colours=None, symbols=None, symbol_sizes=None, symbol_fill=None, linestyle=None, linetype=None, linewidth=0.5, data_type=None, seq_type=None, axis_labels=None, axis_min=None, axis_max=None, legend_pos=None, legend=False, norm=False):
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 # Set the None args to lists as needed. 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 # Set the Grace version number of the header's formatting for compatibility. 570 file.write("@version 50121\n") 571 572 # The paper size. 573 if paper_size == 'A4': 574 file.write("@page size 842, 595\n") 575 576 # Graph G0. 577 file.write("@with g0\n") 578 579 # The view port. 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 # The title and subtitle. 585 if title: 586 file.write("@ title \"%s\"\n" % title) 587 if subtitle: 588 file.write("@ subtitle \"%s\"\n" % subtitle) 589 590 # Axis specific settings. 591 axes = ['x', 'y'] 592 for i in range(2): 593 # Analysis specific methods for making labels. 594 analysis_spec = False 595 if pipes.cdp_name(): 596 # Flag for making labels. 597 analysis_spec = True 598 599 # Specific value and error, conversion factor, and units returning functions. 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 # Test if the axis data type is a minimisation statistic. 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 # Some axis default values for spin data. 609 if data_type[i] == 'spin': 610 # Residue only data. 611 if seq_type[i] == 'res': 612 # Axis limits. 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 # X-axis label. 619 if not axis_labels[i]: 620 axis_labels[i] = "Residue number" 621 622 # Spin only data. 623 if seq_type[i] == 'spin': 624 # Axis limits. 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 # X-axis label. 631 if not axis_labels[i]: 632 axis_labels[i] = "Spin number" 633 634 # Mixed data. 635 if seq_type[i] == 'mixed': 636 # X-axis label. 637 if not axis_labels[i]: 638 axis_labels[i] = "Spin identification string" 639 640 # Some axis default values for other data types. 641 else: 642 # Label. 643 if analysis_spec and not axis_labels[i]: 644 # Get the units. 645 units = return_units(data_type[i]) 646 647 # Set the label. 648 axis_labels[i] = return_grace_string(data_type[i]) 649 650 # Add units. 651 if units: 652 axis_labels[i] = axis_labels[i] + "\\N (" + units + ")" 653 654 # Normalised data. 655 if norm and axes[i] == 'y': 656 axis_labels[i] = axis_labels[i] + " \\N\\q(normalised)\\Q" 657 658 # Write out the data. 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 # Legend box. 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 # Frame. 679 file.write("@ frame linewidth %s\n" % linewidth) 680 681 # Loop over each graph set. 682 for i in range(sets): 683 # Symbol style (default to all different symbols). 684 if symbols: 685 file.write("@ s%i symbol %i\n" % (i, symbols[i])) 686 else: 687 # The symbol number (between 1 and 10). 688 num = (i+1) - (i+1) / 11 * 10 689 690 # Write out. 691 file.write("@ s%i symbol %i\n" % (i, num)) 692 693 # Symbol sizes (default to a small size). 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 # The symbol fill. 700 if symbol_fill: 701 file.write("@ s%i symbol fill pattern %i\n" % (i, symbol_fill[i])) 702 703 # The symbol line width. 704 file.write("@ s%i symbol linewidth %s\n" % (i, linewidth)) 705 706 # Symbol colour (default to nothing). 707 if set_colours: 708 file.write("@ s%i symbol color %s\n" % (i, set_colours[i])) 709 710 # Error bars. 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 # Line linestyle (default to nothing). 716 if linestyle: 717 file.write("@ s%i line linestyle %s\n" % (i, linestyle[i])) 718 719 # Line linetype (default to nothing). 720 if linetype: 721 file.write("@ s%i line type %s\n" % (i, linetype[i])) 722 723 # Line colours (default to nothing). 724 if set_colours: 725 file.write("@ s%i line color %s\n" % (i, set_colours[i])) 726 727 # Legend. 728 if set_names and set_names[i]: 729 file.write("@ s%i legend \"%s\"\n" % (i, set_names[i]))
730