#!/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()