diff --git a/python/BlackDynamite/graphhelper.py b/python/BlackDynamite/graphhelper.py index 858b64f..4bb0845 100755 --- a/python/BlackDynamite/graphhelper.py +++ b/python/BlackDynamite/graphhelper.py @@ -1,384 +1,385 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -*- py-which-shell: "python"; -*- __all__ = [ "GraphHelper", "GraphParser" ] import base import run import job import runselector import jobselector import bdparser ############################################## ##Temp workaround for broken debian package ## ############################################## #import matplotlib############################# #matplotlib.use('Agg')######################### ############################################## #import matplotlib.pyplot as plt import re import sys import numpy as np class GraphHelper(object): """ """ def getMeasures(self,run_list): myresults = [] add_req = [] if (self.frequency): add_req += ["step %% {0} = 0".format(self.frequency)] if (self.start): add_req += ["step > {0}".format(self.start) ] if (self.end): add_req += ["step < {0}".format(self.end) ] for r,j in run_list: print ("retrieve data from run " + r["run_name"]) res = r.getScalarQuantities(self.quantities,add_req) for key , value in res: if (value == None): del res[key] myresults.append([r,j,res]) return myresults def selectGraphs(self): print 'AAAAAAAAA ' + self.binary_operator run_list = self.runSelector.selectRuns(self.run_constraints,self.job_constraints, self.sort_by,binary_operator=self.binary_operator) results = self.getMeasures(run_list) return results def makeGraphs(self,fig=None,**kwargs): + import matplotlib.pyplot as plt results = self.selectGraphs() if fig is None: fig = plt.figure(figsize=self.figsize) for r,j,data in results: if data: self.makeCurve(data,fig=fig,myrun=r,myjob=j,**kwargs) return fig def replaceRunAndJobsParameters(self,name,myrun,myjob): res = name # print (res) codes = [["%r."+key,myrun[key]] for key in myrun.entries.keys()] codes += [["%j."+key,myjob[key]] for key in myjob.entries.keys()] for code,val in codes: res = res.replace(code,str(val)) return res def generateLabels(self,results,myrun,myjob): labels = [] names = [r[0] for r in results] for i in range(0,len(results)): name = results[i][0] if (not self.legend or i >= len(self.legend) or not self.legend[i]): labels.append(self.replaceRunAndJobsParameters(name,myrun,myjob)) continue # print (self.legend[i]) head_legend = self.legend[i].replace("{","{{") head_legend = head_legend.replace("}","}}") head_legend = re.sub(r"(%)([0-9]+)",r'{\2}',head_legend).format(*names) # print (head_legend) head_legend = self.replaceRunAndJobsParameters(head_legend,myrun,myjob) # print (head_legend) # if (not head_legend.find("%") == -1): # print("unknown variable name. Possible variables are:") # print "\n".join([c[0] for c in codes]) # sys.exit(-1) # print (head_legend) labels.append(head_legend) return labels def makeComposedQuantity(self,results,myrun,myjob): vecs = [r[1] for r in results] names = [r[0] for r in results] # print (vecs[0].shape) new_results = [] for comp in self.using: exprs = comp.split(":") tmp_res = [] for i in [0,1]: e = re.sub(r"(%)([0-9]+)\.(x)",r"vecs[\2][:,0]",exprs[i]) e = re.sub(r"(%)([0-9]+)\.(y)",r"vecs[\2][:,1]",e) e = self.replaceRunAndJobsParameters(e,myrun,myjob) try: tmp_res.append(eval(e)) except: print (names) print ("invalid expression: '" + exprs[i] + "'") print ("invalid expression: '" + e + "'") sys.exit(-1) name = re.sub(r"(%)([0-9]+)\.([x|y])",r'(" + str(names[\2]) + ")',exprs[1]) res = np.zeros((tmp_res[0].shape[0],2)) res[:,0] = tmp_res[0] res[:,1] = tmp_res[1] # print (res.shape) expr = re.sub(r"(%)([0-9]+)",r"vecs[\2]",comp) # res[0] = eval(expr) # print (name) name = "\"" + name + "\"" # print (name) name = eval(name) # print (name) new_results.append([name,res]) return new_results def decorateGraph(self, fig, myrun, myjob, results): if not results: return if fig is None: fig = plt.figure() axe=fig.add_subplot(1,1,1) if self.xrange: axe.set_xlim(self.xrange) if self.yrange: axe.set_ylim(self.yrange) if (self.xlabel): axe.set_xlabel(self.xlabel) if (self.ylabel): axe.set_ylabel(self.ylabel) if (self.title): t = self.replaceRunAndJobsParameters(self.title,myrun,myjob) axe.set_title(t) axe.grid(True,linewidth=0.1) if (self.using): results = self.makeComposedQuantity(results,myrun,myjob) labels = self.generateLabels(results,myrun,myjob) # print (labels) return fig, axe, results, labels def makeCurve(self,results,myrun=None,myjob=None,fig=None,**kwargs): fig, axe, results, labels = self.decorateGraph(fig, myrun, myjob, results) for count, result in enumerate(results): name = result[0] vec = result[1] label = labels[count] # print (self.quantities) # print (name) style=dict() if (self.marker is not None): style["marker"] = self.marker if self.blackwhite: width_index = self.cycle_index/len(self.linestyle_cycle) style_index = self.cycle_index%len(self.linestyle_cycle) self.cycle_index += 1 style["linewidth"] = self.linewidth_cycle[width_index] style["linestyle"] = self.linestyle_cycle[style_index] style["color"] = 'k' axe.plot(vec[:,0]/self.xscale, vec[:,1]/self.yscale, label=label, **style) axe.legend(loc='best') if (self.fileout): fig.savefig(self.fileout) return fig def setJobConstraint(self,**params): self.job_constraints = [] if ("job_constraints" in params): self.job_constraints = params["job_constraints"] def setRunConstraint(self,**params): self.run_constraints = [] if ("run_constraints" in params): self.run_constraints = params["run_constraints"] def setBinaryOperator(self,**params): self.binary_operator = 'and' if ("binary_operator" in params): self.binary_operator = params["binary_operator"] def setQuantity(self,**params): if ("quantity" in params): self.quantities = params["quantity"] else: print ("quantity should be provided using option --quantity") self.quantities = "__BLACKDYNAMITE_ERROR__" def __init__ (self,base,**params): self.setJobConstraint(**params) self.setRunConstraint(**params) self.setBinaryOperator(**params) self.setQuantity(**params) self.base = base self.runSelector = runselector.RunSelector(self.base) self.fig = None self.xrange = None self.yrange = None self.xlabel = None self.ylabel = None self.xscale = None self.yscale = None self.fileout = None self.title = None self.using = None self.frequency = None self.start = None self.end = None self.figsize = None self.blackwhite = None self.legend = None self.sort_by = None self.marker = None ### set the members if keys are present in params members = set(self.__dict__.keys()) p = set(params.keys()) for key in members & p: setattr(self,key,params[key]) if(params["list_quantities"] == True): myrun = run.Run(base) print ("list of possible quantities:\n") print("\n".join(myrun.listQuantities())) sys.exit(0) if(params["list_parameters"] == True): myjob = job.Job(base) myjob.prepare() print ("****************************************************************") print ("Job parameters:") print ("****************************************************************") params = [str(j[0]) + ": " + str(j[1]) for j in myjob.types.iteritems() ] print("\n".join(params)) myrun = run.Run(base) myrun.prepare() print ("****************************************************************") print ("Run parameters:") print ("****************************************************************") params = [str(j[0]) + ": " + str(j[1]) for j in myrun.types.iteritems() ] print("\n".join(params)) sys.exit(0) self.linewidth_cycle = [1, 2, 4] self.linestyle_cycle = ['-', '--', '-.'] self.cycle_index = 0 ################################################################ class GraphParser(bdparser.BDParser): """ """ def __init__ (self): bdparser.BDParser.__init__(self) self.admissible_params["quantity"] = [str] self.help["quantity"] = "Specify the quantity to be outputed" self.admissible_params["xrange"] = [float] self.help["xrange"] = "Specify range of values in the X direction" self.admissible_params["yrange"] = [float] self.help["yrange"] = "Specify range of values in the Y direction" self.admissible_params["sort_by"] = [str] self.help["sort_by"] = "Specify a study parameter to be used in sorting the curves" self.admissible_params["xlabel"] = str self.help["xlabel"] = "Specify the label for the X axis" self.admissible_params["ylabel"] = str self.help["ylabel"] = "Specify the label for the Y axis" self.admissible_params["xscale"] = float self.default_params["xscale"] = 1. self.help["xscale"] = "Specify a scale factor for the X axis" self.admissible_params["yscale"] = float self.default_params["yscale"] = 1. self.help["yscale"] = "Specify a scale factor for the Y axis" self.admissible_params["title"] = str self.help["title"] = "Specify title for the graph" self.admissible_params["legend"] = [str] self.help["legend"] = "Specify a legend for the curves. The syntax can use %%j.param or %%r.param to use get job and run values" self.default_params["legend"] = None self.admissible_params["using"] = [str] self.help["using"] = "Allow to combine several quantities. The syntax uses python syntax where %%quantity1.column1:%%quantity2.column2 is the python numpy vector provided by quantity number (provided using the --quantities option) and column number (x or y). The sytax is comparable to the GNUPlot one in using the ':' to separate X from Y axis" self.admissible_params["list_quantities"] = bool self.help["list_quantities"] = "Request to list the possible quantities to be plotted" self.admissible_params["list_parameters"] = bool self.help["list_parameters"] = "Request to list the possible job/run parameters" self.admissible_params["frequency"] = int self.default_params["frequency"] = 1 self.help["frequency"] = "Set a frequency at which the quantity values should be retreived (helpful when the amount of data is very large)" self.admissible_params["start"] = float self.help["start"] = "Set the start X value for the graph" self.admissible_params["end"] = int self.help["end"] = "Set the end X value for the graph" self.admissible_params["figsize"] = [float] self.admissible_params["blackwhite"] = bool self.default_params["blackwhite"] = False self.help["blackwhite"] = "Request a black and white graph generation" self.default_params["blackwhite"] = False self.help["blackwhite"] = "Request to plot a black and white graph" self.admissible_params["marker"] = str self.help["marker"] = "Request a specific marker (matplotlib option)" self.admissible_params["fileout"] = str self.help["fileout"] = "Request to write a PDF file (given its name) containing the graph" self.group_params["GraphHelper"] = [ "quantity", "xrange", "yrange", "sort_by", "xlabel", "ylabel", "xscale", "yscale", "title", "legend", "using", "list_quantities", "list_parameters", "frequency", "start", "end", "figsize", "blackwhite", "marker", "fileout"] ################################################################