Style File と Data File を分離した QDP-like な ROOT での作図
単なる遊びです。Style file にデータの表示形式を書き、データ辞退は Data file に書いて ROOT で図を作る簡易スクリプト。
#!/usr/bin/env python # Teruaki Enoto 2012-02-03 from optparse import OptionParser import array import shlex import ROOT stylefile_def = "/Users/enoto/work/program/root/example/PlotXY/stylefile.txt" class PlotXY(): def __init__(self, data_array, stylefile, outputpdf): self.data_array = data_array self.stylefile = stylefile self.outputpdf = outputpdf def show(self): print "data_array = ", self.data_array print "stylefile = ", self.stylefile def init_par(self): ### initialize parameters self.pars = {"Title" : "str", "Xmin" : "float", "Xmax" : "float", "Xtitle" : "str", "Xlog" : "bool", "Ymin" : "float", "Ymax" : "float", "Ytitle" : "str", "Ylog" : "bool", "Format" : "list", "Style" : " list", "Can_X0" : "int", "Can_Y0" : "int", "Can_Xwid" : "int", "Can_Ywid" : "int", "TitleBorderSize" : "int", "TitleAlign" : "int", "TextFont" : "int", "FrameLineWidth" : "int", "EndErrorSize" : "float" } for par in self.pars: exec("self.%s = %s('%s')" % (par, self.pars[par], '0')) def set_style(self): ### open file try: f = open(self.stylefile) except IOError, err: print 'Error: cannot read stylefile (%s):' % (self.stylefile,), err quit() ### get file content lex = shlex.shlex(f,posix=True) lex.whitespace += "=" lex.whitespace_split = True ### read and set parameters while True: s = lex.get_token() if s!=lex.eof: val = lex.get_token() print s, val if s == "Style" or s == "Format": cmd = "self.%s = %s(%s)" % (s, self.pars[s], val) elif s == "Xlog" or s == "Ylog": if val == "True": cmd = "self.%s = %s(%s)" % (s, self.pars[s], True) elif val == "False": cmd = "self.%s = %s(%s)" % (s, self.pars[s], False) else: print "Error:: Xlog/Ylog must be bool (True or False)" else: cmd = "self.%s = %s('%s')" % (s, self.pars[s], val) exec(cmd) elif s==lex.eof: break else: print "Error: unexpected error in reading the parfile." f.close() def read_all(self): self.graph = [] id = 0 for file in self.data_array: if self.Format[id] == 0: x, y = self.read(file) self.graph.append(ROOT.TGraph(len(x), x, y)) elif self.Format[id] == 1: x, y, xe, ye = self.read_err(file) self.graph.append(ROOT.TGraphErrors(len(x), x, y, xe, ye)) elif self.Format[id] == 2: x, y, xeh, xel, yeh, yel = self.read_asymerr(file) self.graph.append(ROOT.TGraphAsymmErrors(len(x), x, y, xeh, xel, yeh, yel)) else: print "Error:: Format error in style file" quit() id += 1 def read(self, file): print "...reading file %s..." % file x = array.array('f') y = array.array('f') for line in open(file): col = line.split() x.append(float(col[0])) y.append(float(col[1])) return x, y def read_err(self, file): print "...reading file %s..." % file x = array.array('f') y = array.array('f') xe = array.array('f') ye = array.array('f') for line in open(file): col = line.split() x.append(float(col[0])) y.append(float(col[1])) xe.append(float(col[2])) ye.append(float(col[3])) return x, y, xe, ye def read_asymerr(self, file): print "...reading file %s..." % file x = array.array('f') y = array.array('f') xeh = array.array('f') xel = array.array('f') yeh = array.array('f') yel = array.array('f') for line in open(file): col = line.split() x.append(float(col[0])) y.append(float(col[1])) xeh.append(float(col[2])) xel.append(float(col[3])) yeh.append(float(col[4])) yel.append(float(col[5])) return x, y, xeh, xel, yeh, yel def plot(self): can = ROOT.TCanvas("c1","A Simple Graph with error bars", self.Can_X0, self.Can_Y0, self.Can_Xwid, self.Can_Ywid) print self.Xlog, self.Ylog can.SetLogx(self.Xlog) can.SetLogy(self.Ylog) # --- Optional Gstyles --- ROOT.gStyle.SetTitleBorderSize(self.TitleBorderSize) ROOT.gStyle.SetTitleAlign(self.TitleAlign) ROOT.gStyle.SetTextFont(self.TextFont) ROOT.gStyle.SetFrameLineWidth(self.FrameLineWidth) ROOT.gStyle.SetEndErrorSize(self.EndErrorSize) id = 0 for graph in self.graph: if id == 0: graph.Draw("AP") else: graph.Draw("P") graph.SetMarkerColor(self.Style[id][0]) graph.SetLineColor(self.Style[id][0]) graph.SetMarkerStyle(self.Style[id][1]) graph.SetMarkerSize(self.Style[id][2]) id += 1 # --- Range & Title Set --- self.graph[0].SetTitle(self.Title) self.graph[0].GetXaxis().SetLimits(self.Xmin, self.Xmax) self.graph[0].GetXaxis().SetTitle(self.Xtitle) self.graph[0].SetMinimum(self.Ymin) self.graph[0].SetMaximum(self.Ymax) self.graph[0].GetYaxis().SetTitle(self.Ytitle) can.Print(self.outputpdf) def run(self): self.show() self.init_par() self.set_style() self.read_all() self.plot() ############################# if __name__=="__main__": ############################# # --- Interface to command line parser = OptionParser() parser.add_option("-s", "--stylefile", dest="stylefile", default=stylefile_def, type="string", action="store", help="style file name") parser.add_option("-o", "--outputpdf", dest="outputpdf", default="out.pdf", type="string", action="store", help="output pdf file name") (opt, arg) = parser.parse_args() # --- run main --- if len(arg) == 0: print "Error:: No input data_array." quit() else: plot = PlotXY(arg, stylefile=opt.stylefile, outputpdf=opt.outputpdf) plot.run() quit()
ほんで、Style file
Title = "Title" Xmin = 0.8 Xmax = 10.0 Xtitle = "Xtitle" Xlog = True Ymin = 0.1 Ymax = 4.0 Ytitle = "Ytitle" Ylog = True #-------- Format file --------- # Format # 0 : xy # 1 : xy with x, y errors # 2 : xy with x, y asimerr # Style [color, marker, size] Format = [2,1] Style = [[2,20,1.1],[3,22,1.1]] #--------- Other Format ---------- Can_X0 = 200 Can_Y0 = 10 Can_Xwid = 580 Can_Ywid = 450 TitleBorderSize = 0 TitleAlign = 13 TextFont = 132 FrameLineWidth = 1 EndErrorSize = 0.8
Data file は
3.0 2.0 0.2 0.4 0.2 0.1 5.0 2.0 0.1 0.8 0.1 0.2 3.4 2.5 0.1 0.7 0.2 0.1 5.6 0.3 0.1 0.8 0.3 0.2
で、図
パラメータファイルを読み込ませるスクリプトの定型
次のようなパラメータファイルを読むスクリプトの定型をメモしておきます。
par1 = 3 par2 = 0.4
from optparse import OptionParser import shlex class MainClass(): def __init__(self, parfile, verbose=0, logfile="logfile.txt"): self.parfile = parfile self.verbose = verbose self.logfile = logfile def show_input(self): print "parfile = %s" % self.parfile print "verbose = %d" % self.verbose print "logfile = %s" % self.logfile def init_par(self): ### initialize parameters self.pars = {"par1" : "int", "par2" : "float" } for par in self.pars: exec("self.%s = %s('%s')" % (par, self.pars[par], '0')) def read_par(self): if not hasattr(self, "pars"): print 'Error: init_par should be defined.' quit() ### open file try: f = open(self.parfile) except IOError, err: print 'Error: cannot read parfile (%s):' % (self.parfile,), err quit() ### get file content lex = shlex.shlex(f,posix=True) lex.whitespace += "=" lex.whitespace_split = True ### read and set parameters while True: s = lex.get_token() if s!=lex.eof and self.pars.has_key(s): val = lex.get_token() cmd = "self.%s = %s('%s')" % (s, self.pars[s], val) if self.verbose > 0: print cmd exec(cmd) elif s==lex.eof: break else: print "Error: unexpected error in reading the parfile." f.close() def run(self): print "---run---" self.show_input() self.init_par() self.read_par() print "---done---" ############################# if __name__=="__main__": ############################# # --- Interface to command line parser = OptionParser() parser.add_option("-p", "--parfile", dest="parfile", default="par.txt", type="string", action="store", help="parameter file name") parser.add_option("-v", "--verbose", dest="verbose", default=0, type="int", action="store", help="verbose level: int") parser.add_option("-o", "--logfile", dest="logfile", default="logfile.txt", type="string", action="store", help="logfile name") (opt, arg) = parser.parse_args() # --- run main --- obj = MainClass(opt.parfile, verbose=opt.verbose, logfile=opt.logfile) obj.run() quit()
カイ二乗分布を描く。
特に何ということもないんだけれど、自由度 k=4のカイ二乗分布を ROOT と python で描いてみた。自由度 k=4 のカイ二乗分布は、平均値 k = 4、分散 2k = 8、最頻値 k - 2 = 2、中央値 k-2/3+4/27k -8/729k^2=3.4 で分布する。周期性を探す Zn-test (Raileigh Test) でよくお世話になる。
#!/usr/bin/env python import ROOT import pylab from matplotlib import rc def drange(start, stop, step): r = start while r < stop: yield r r += step x = [] y_pdf = [] y_cdf = [] for i in drange(0,15,0.1): x.append(i) y_pdf.append(ROOT.Math.chisquared_pdf(i, 4)) y_cdf.append(ROOT.Math.chisquared_cdf(i, 4)) rc('text', usetex=True) rc('font',**{'family':'sans-serif','sans-serif':['Helvetica'], 'size':'14'}) fig = pylab.figure(figsize=(7,7)) ax = fig.add_subplot(111) ax.set_xlabel('Chi-square value') ax.set_ylabel('Probability') ax.set_title('Chi-square Distribution (Degree of Freedom = 4)') ax.plot(x, y_pdf, 'r-', x, y_cdf, 'b--') ax.legend(('Probability Distribution', 'Cumulative Distribution'), 'center right', shadow=False) fig.savefig("chi2_dof4.pdf")
Arduino と SHT71 センサーで実験室の温湿度ログを Mac から取得する。
実験室で温度・湿度を記録する、あるいは長時間でのログを取りたいがあります。この目的に合うStrawberry Linux 社の温度・湿度計モジュール USBRH が市販されていますが、Windows の driver しか公開されおらず、有志の開発したソフトで Linux でまでなら対応しているようです(先輩の例)。ただ、Mac User なので、できれば直接 Mac から制御したいところです。
そこで、Arduino とSENSIRION 社製のデジタル温湿度センサー SHT71 を使って、直接 Mac でデータ収集してみました。SHT シリーズは比較的高性能で、上記のモジュールにも使われています。今回は、PIN の足がついている SHT71 を用います。日本国内だと Strawberry Linux からも SHT71 や SHT11 を購入できます。自分は、アメリカで Newark 経由で購入して $33 でした。
SHT71 は、公称値で、 25℃ において湿度の精度が±3.0%、温度の精度が±0.4℃となっています。 詳しくは、SHT71 dataheet (pdf) をご覧ください。この SHT71 はデジタル値で出力してくれるので、PIN の足は順番に
- SCL : Serial Clock, input only (同期用)
- VDD : Source Voltage
- GND : Ground
- DATA : Serial Data, bidirectional (シリアルデータ通信)
となっています。
Arduino との配線は、10 kOhm のプルアップ抵抗をつけて、以下のようにしました。
肝心のスケッチですが、ライブラリを利用できます。SHT1X や SHT7X のライブラリが、サイトから sht1x.tgz としてダウンロードできます。あるいは、GitHub にもあるようです(ref)。ライブラリは以下に収容します。
~enoto/Documents/Arduino/libraries/sht1x
なお、Arduino Uno を使っており、sht1x_hw.h の中身で
# define SHT1X_CLOCK_LINE PD2 # define SHT1X_DATA_LINE PD3
という箇所を
# define SHT1X_CLOCK_LINE PORTD2 # define SHT1X_DATA_LINE PORTD3
のように修正しないとコンパイルが通りません。
その上で、スケッチは以下の通り。データシートにある補正式のままです。
#include <sht1x.h> #include <sht1x_hw.h> unsigned int h; unsigned int t; double temp; double hlin; double htrue; void setup() { Serial.begin(9600); delay(15); sht1x_init(); Serial.println("Start"); if (sht1x_read_humidity() < 0) { Serial.println("Reset"); sht1x_reset(); } } void loop() { h = sht1x_read_humidity(); t = sht1x_read_temp(); while (millis() % 1000); temp = -39.66 + 0.01 * t; // 14 bit hlin = -2.0468 + 0.0367 * h - 1.5955e-6 * h * h; // 12 bit htrue = (temp - 25.0) * (0.01 + 8e-5 * h) + hlin; // 12 bit Serial.print(temp, 3); Serial.print("C "); Serial.print(htrue, 3); Serial.println("% "); }
大体、仕様の誤差範囲で、正しい温度のようですが、較正はまた確認してみようと思います。
参考サイト