Source code for stosim.analysis.plotter

#!/usr/bin/python

'''
plotter
=======
'''

import sys
import os
import os.path as osp
from subprocess import Popen
from shutil import rmtree

from stosim.analysis import compressor
from stosim.analysis import harvester


with_names = False # if to have title in PDF
show_pdfs = False  # if to show PDF right after creation
pdf_viewer = 'evince'
tmp_dir = 'tmp_plotter'


[docs]def plot(filepath='', delim=',', outfile_name='', name='My simulation',\ xcol=1, x_label='iteration', y_label='value', x_range=None, y_range='[0:10]',\ use_y_errorbars=False, errorbar_every=1, infobox_pos='top left', use_colors=True,\ use_tex=False, line_width=6, font_size=22, custom_script='', plots=[]): ''' Make plots for specific portions of data in one figure. For each graph, this function ... - selects folders with data files depending on parameter values you provide - collects all log files contained in them in a temporary folder - averages over the contents or just selects values from them - makes a (gnu)plot out of that, with yerrorbars if you want The output is one PDF file. Creating PDF for this yields far nicer linetypes. Also, this makes different linetypes (e.g. dashes/dots) possible, bcs papers are often printed b/w. In addition to gnuplot, you need epstopdf installed. :param string filepath: path to data :param string delim: delimiter used between columns :param string outfile_name: name of the PDF file you want to make :param string name: Title of the simulation :param int xcol: column >= 1 :param string x_label: label on x axis :param string y_label: label on y axis :param string x_range: the range of values for x axis, in the form of "[a:b]", defaults to None, meaning that gnuplot should take to the actual value range of x values :param string y_range: the range of values for y axis, defaults to '[0:10]' :param boolean use_y_errorbars: True if errorbars should be shown, default is False :param int errorbar_every: show an errorbar every x steps, defaults to 1 :param string infobox_pos: where the infobox should go, e.g. 'bottom left', defaults to 'top left' when given empty :param boolean use_colors: whether to use colors or be b+w, defaults True :param boolean use_tex: whether to use enhanced mode, which interpretes tex-like encoding (e.g. subscript, math, greek symbols), defaults to False :param int line_width: line width in pixels, defaults to 6 :param int font_size: font size (a number), defaults to 22 :param list plots: list of plot descriptions, defaults to empty list ''' # make sure tmp dir exists if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) # ---- collect relevant data for each requested plot ---- # get relevant files searches = {} for p in plots: # make sure no old data is around plot_dir = '%s/%s' % (tmp_dir, p['_name']) if os.path.exists(plot_dir): if len(os.listdir(plot_dir)) > 0: Popen('rm -r %s/*' % plot_dir, shell=True).wait() searches[p['_name']] = [(k, p[k]) for k in list(p.keys()) if not k.startswith('_')] failed = harvester.collect_files(searches, filepath, tmp_dir) # handle errors init_plots_num = len(plots) if len(failed) > 0: print("[StoSim] WARNING: Selectors %s didn't match any folders!" % ','.join(failed)) for fail in failed: for p in plots: if p['_name'] == fail: plots.remove(p) if len(failed) == init_plots_num: print("[StoSim] In fact, no selectors of this figure matched anything. Aborting ...") print("") return # ---- prepare data ---- for p in plots: if p['_type'] == 'line': compressor.avg_stats(xcol, int(p['_ycol']), None, filePrefix='log', fileSuffix='.dat', filePath='%s/%s' % (tmp_dir, p['_name']), delim=delim, outName='%s/%s/all.dat' % (tmp_dir, p['_name'])) else: # scatter if '_select' not in p: p['_select'] = 'all' harvester.collect_values('%s/%s' % (tmp_dir, p['_name']), delim, '%s/%s/all.dat' \ % (tmp_dir, p['_name']), cols=[xcol, int(p['_ycol'])], selector=p['_select'] ) # ---- plot the results ---- if custom_script != "": if not osp.exists(custom_script): print("[StoSim] Cannot find custom script at [%s]. Aborting ..." % (custom_script)) print("") return print('[StoSim] Using custom script at %s' % custom_script) Popen('cp %s %s/plot.gnu' % (custom_script, tmp_dir), shell=True).wait() else: e = '' if use_tex: e = 'enhanced' c = 'monochrome' if use_colors: c = 'color' # write gnuplot code gnu = "set terminal postscript %s eps %s dashed lw %d rounded %d;\n" % (e, c, int(line_width), int(font_size)) gnu += "set output '%s.eps';\n" % name if x_range: gnu += "set xrange %s;\n" % x_range gnu += "set yrange %s;\n" % y_range if with_names: gnu += "set title '%s';" % name gnu += "set xlabel '%s';\n" % x_label gnu += "set ylabel '%s';\n" % y_label gnu += "set key %s spacing 1;\n" % infobox_pos gnu += "plot " # first the actual plots num = 1 for p in plots: smu = '' if p['_type'] == 'line': smu = 'smooth unique' gnu += "'%s/all.dat' %s " % (p['_name'], smu) gnu += " title '%s' lt %d" % (p['_name'], num) if num < len(plots): gnu += ',' num += 1 # then the errorbars (this way, they don't reserve the linestyles) if use_y_errorbars: offset = 1 offset_step = max(1, int(errorbar_every) / 5) gnu += "," for num, p in enumerate(plots): offtxt = '' if int(errorbar_every) > 1: offtxt = 'every %d::%d' % (int(errorbar_every), offset) gnu += "'%s/all.dat' %s with yerrorbars title '' lt %d" \ % (p['_name'], offtxt, num + 1) if num + 1 < len(plots): gnu += ',' #TODO: this isn't nice for everyone... can maybe be derived from xrange somehow ... ? offset += offset_step # execute gunplot code gnuf = open('%s/%s.gnu' % (tmp_dir, name), 'w') gnuf.write(gnu) gnuf.close() # generate PDF and maybe show it print('[StoSim] Plotting %s' % outfile_name) Popen('cd %s; gnuplot %s.gnu; epstopdf %s.eps; cd ..' % (tmp_dir, name, name), shell=True).wait() Popen('cp %s/%s.pdf %s' % (tmp_dir, name, outfile_name), shell=True).wait() if osp.exists(tmp_dir) and not '-k' in sys.argv: rmtree(tmp_dir) if show_pdfs: Popen('%s %s' % (pdf_viewer, outfile_name), shell=True).wait()