00001 import os, sys, types
00002
00003 from Util import Kali
00004
00005 def EnQuote(s):
00006 return s.join(("'", "'"))
00007
00008 def EnDQuote(s):
00009 return s.join(('"', '"'))
00010
00011 try:
00012 from wxGUI.Plotter import Plotter as wxPlotter
00013 except:
00014 wxPlotter = Kali.Kali
00015
00016
00017
00018 class Data:
00019 """ base class to hold data sent to a plotter """
00020
00021 def __init__(self, data, options={}):
00022 """ pre: data is list of equal length lists of ints or floats """
00023
00024 self.Options = dict(options)
00025 self.ValidOptions = {}
00026 self.UpdateData(data)
00027
00028 def UpdateData(self, data):
00029 self.data = data
00030
00031
00032 def CheckOption(self, key, val=None):
00033
00034 rv = len(self.ValidOptions) ==0
00035 if self.ValidOptions.has_key(key):
00036 if val in self.ValidOptions[key] or val == None:
00037 rv =True
00038 else:
00039 print "Invalid value", str(val), "for option", key
00040 else:
00041 print "no such option -", key
00042
00043 return rv
00044
00045
00046 def SetOption(self, key, val):
00047
00048
00049 self.Options[key] = val
00050
00051
00052 def GetOptions(self):
00053 pass
00054
00055 def GetData(self):
00056 pass
00057
00058
00059 class PlotterBase(dict):
00060
00061 pass
00062
00063
00064
00065 class wxData:
00066
00067 DefaultOpts = {
00068 "Style":"line",
00069 "Substyle":"SOLID",
00070 "colour" : "BLACK",
00071 "width" :2,
00072 "marker" :"circle",
00073 "Title" : ""
00074 }
00075
00076
00077 def __init__(self, data):
00078
00079 if len(data)==1:
00080 self.y = data[0]
00081 self.x = range(len(self.y))
00082 else:
00083 self.x = data[0]
00084 self.y = data[1]
00085
00086 self.Options = wxData.DefaultOpts
00087
00088
00089
00090 def GetData(self):
00091 return self.x, self.y
00092
00093
00094 def GetOptions(self):
00095 return self.Options
00096
00097
00098
00099 class wxPlotter(wxPlotter):
00100
00101 def AddData(self, name, data):
00102
00103 opts = dict(data.Options)
00104 style = opts["Style"]
00105 opts["style"] = opts["Substyle"]
00106 opts["Name"] = opts["Title"]
00107 del opts["Substyle"], opts["Style"], opts["Title"]
00108 if opts["Name"] == "":
00109 opts["Name"] = name
00110
00111 if style == "line":
00112 if opts.has_key("marker"):
00113 del opts["marker"]
00114 self.AddLinePlotItem(data.x, data.y, **opts)
00115 else:
00116 self.AddMarkerPlotItem(data.x, data.y, **opts)
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 def ValidNum(x):
00132 try:
00133 return str(float(x)) != "nan"
00134 except:
00135 return False
00136
00137
00138
00139
00140
00141 class GPData(Data):
00142 """ data for gnuplot """
00143
00144 DefaultOpts ={
00145 "Style": 'linesp',
00146 "PType": '',
00147 "Colour": '',
00148 "Title": ''
00149 }
00150
00151 def Sanitise(self, data):
00152
00153 xdat, ydat = data[0], data[1]
00154
00155 checkx = map(ValidNum, xdat)
00156 while False in checkx:
00157 idx = checkx.index(False)
00158 for l in checkx, xdat, ydat:
00159 del l[idx]
00160
00161 checky = map(ValidNum, ydat)
00162 while False in checky:
00163 idx = checky.index(False)
00164 for l in checky, xdat, ydat:
00165 del l[idx]
00166
00167 def UpdateData(self,data):
00168 self.Sanitise(data)
00169 self.data = data
00170
00171
00172
00173
00174
00175 def __init__(self, data):
00176 self.Sanitise(data)
00177 Data.__init__(self, data)
00178 self.ValidOptions = dict(self.DefaultOpts)
00179 self.Options.update(self.DefaultOpts)
00180
00181
00182 def GetData(self):
00183
00184 lend = len(self.data[0])
00185 lines = []
00186 for n in range(lend):
00187 lines.append(" ".join(map(str,map(lambda l:l[n], self.data))))
00188
00189 return "\n".join(lines)+"\ne\n"
00190
00191
00192 def GetOptions(self):
00193 return " ".join((
00194 "'-'",
00195 "t"+EnDQuote(self.Options["Title"]),
00196 "with ", self.Options["Style"],
00197 str(self.Options["Colour"]),
00198 str(self.Options["PType"])
00199 ))
00200
00201
00202
00203
00204
00205
00206 class GPPlotter(PlotterBase):
00207
00208 gp_cmd = os.popen("which gnuplot").read()
00209 default_term = "wxt"
00210 plot_cmd = "plot "
00211
00212 Options = {
00213 "Logx": "unset log x",
00214 "Logy": "unset log y",
00215 "xrange": "set xra [:]",
00216 "yrange" : "set yra [:]",
00217 "term": "set term " + default_term,
00218 "out" : "set out "
00219 }
00220
00221 def __init__(self):
00222 if self.gp_cmd == "":
00223 print >>sys.stderr, "!! Can't locate gnuplot binary\n!! Plotting not available\n"
00224 self._gp2 = self._gp = Kali.Kali()
00225 else:
00226 self._gp2 = self._gp = os.popen(self.gp_cmd,"w")
00227 self.PlotNames = []
00228
00229
00230 def ToGP(self, string):
00231 self._gp.write(string+"\n")
00232 self._gp.flush()
00233
00234
00235 def GetOptions(self):
00236
00237 return "\n".join(["set auto"]+self.Options.values())+"\n"
00238
00239
00240 def SetMissing(self, MissStr = '"nan"'):
00241
00242 self.ToGP('set datafile missing '+ MissStr)
00243
00244
00245 def AddData(self, name, data, style="linespoints"):
00246
00247 if not self.has_key(name):
00248 self[name] = GPData(data)
00249 self.PlotNames.append(name)
00250
00251 self[name].Options["Title"] = name
00252 self[name].Options["Style"] = style
00253
00254
00255 def RemoveData(self, name):
00256
00257 if self.has_key(name):
00258 del self[name]
00259 self.PlotNames.remove(name)
00260
00261
00262
00263 def AutoName(self):
00264
00265 for k in self.keys():
00266 self[k].Options["Title"] =k
00267
00268
00269
00270 def PlotStr(self, Names=[]):
00271
00272 if len(Names)==0:
00273 Names = self.PlotNames
00274
00275 preamble = self.GetOptions()+self.plot_cmd+",".join(map(lambda n: self[n].GetOptions(), Names))
00276 data = "\n".join(map(lambda n:self[n].GetData(), Names))
00277
00278 self.ToGP(preamble+"\n"+data)
00279 return preamble+"\n"+data
00280
00281
00282 def Plot(self,Names=""):
00283
00284 self.ToGP(self.PlotStr(Names))
00285
00286
00287 def Replot(self):
00288 self.Plot(self.PlotNames)
00289
00290 def SavePlot(self,filename):
00291 """ save the current plot in gp format to filename """
00292
00293 print >>open(filename,"w"), self.PlotStr()
00294
00295
00296
00297 def SetRange(self, Axis="x", lo="", hi=""):
00298 """default args are auto scale (lo,hi)"""
00299
00300 optk = Axis.lower()+"range"
00301 lo= str(lo)
00302 hi = str(hi)
00303 self.Options[optk] = "".join(("set ", optk, "[", lo, ":", hi, "]"))
00304
00305
00306 def SetLog(self, Axis="x", On=True):
00307
00308 Axis = Axis.lower()
00309 optk = "Log" + Axis
00310 if On:
00311 cmd = "set"
00312 else:
00313 cmd = "unset"
00314
00315 self.Options[optk] = " ".join((cmd, "log", Axis ))
00316
00317
00318 def SaveData(self, FName, Names=""):
00319
00320 open(FName,"w").write(self.PlotStr(Names))
00321
00322
00323 def SaveGraphic(self, file, format, opts):
00324
00325 term = self.Options["term"]
00326 out = self.Options["out"]
00327 self.Options["term"] = " ".join(("set term", format, opts))
00328 self.Options["out"] = "set out "+EnQuote(file)
00329 self.Replot()
00330 self.Options["term"] = term
00331 self.Options["out"] = out
00332
00333
00334 def SavePS(self, file, opts = "enhanced eps colour solid linewidth 2"):
00335
00336 self.SaveGraphic(file, "post", opts)
00337
00338
00339 def SaveSVG(self, file, opts = "enhanced linewidth 2"):
00340
00341 self.SaveGraphic(file, "svg", opts)
00342
00343
00344 Plotter = GPPlotter
00345 Plotdata = GPData