ソフトウェア/Igor/グラフ関連 の変更点

更新


[[ソフトウェア/Igor]]

#contents

* グラフに表示されたウェーブの一覧を取得する [#n02b667a]

TraceNameList という関数で読み取った値をリスト関数で処理します。

 LANG:Igor(linenumber)
 function TestTraceNameList(graph_name)
    string graph_name
    string traces = TraceNameList(graph_name, ";", 1)
    variable i
    for(i = 0; i < ItemsInList(traces); i+=1)
        print StringFromList(i, traces)
    endfor
 end

[[コマンドラインから>http://dora.bk.tsukuba.ac.jp/~takeuchi/index.php?cmd=read&page=%A5%BD%A5%D5%A5%C8%A5%A6%A5%A7%A5%A2%2FIgor%2F%A5%B7%A5%B9%A5%C6%A5%E0%A4%CE%B4%F0%CB%DC#content_1_0]]

 LANG:Igor
 make wave1, wave2, wave3, wave4
 display wave1, wave2, wave3, wave4
 TestTraceNameList("Graph0")
 // wave1
 // wave2
 // wave3
 // wave4

Igor には他にも XxxxNameList という名前の関数がたくさんあって、
同じパターンを使い回せます。

例えば、画像の一覧なら、TraceNameList ではなく ImageNameList 
を呼べばいいわけです。

 LANG:Igor(linenumber)
 string graph_name = "Graph1"
 string images = ImageNameList(graph_name, ";", 1)
 variable i
 for(i = 0; i < ItemsInList(images); i+=1)
     print StringFromList(i, images)
 endfor

当然、名前が手に入れば何でもできますね。

例えばあるグラフから名前が "wave1?" の形のトレース、~
例えば "wave10", "wave11", ... をすべて消去するには、

 LANG:Igor(linenumber)
 function test()
     string graph_name = "Graph0"
     string traces = TraceNameList(graph_name, ";", 1)
     variable i
     for(i = ItemsInList(traces) - 1; i>=0; i-=1)
         string trace_name = StringFromList(i, traces)
         if(GrepString(trace_name, "^wave1.(#\d*)?$"))
             RemoveFromGraph $trace_name
         endif
     endfor
 end
 
 // コマンドラインから
 
 // いくつもウェーブを表示した中から
 make wave0, wave1, wave10, wave11
 display wave0, wave1, wave10, wave11, wave1, wave11
 // wave10, wave11 だけを取り除く
 test()

などとします。

for を逆順に回しているのは、トレースを Remove すると
残されたトレースの名前が変化することがあるためです。

例えば、wave10 が2回 AppendToGraph されていると、wave10 と wave10#1
という2つのトレースができます。ここで、先に wave10 を消してしまうと
wave10#1 の名前が wave10 になってしまい、後から wave10#1 を消そうと
したときに見付からずエラーになります。

逆順に回すとこの問題を回避できます。

"wave1?" という形のウェーブを探すのに GrepString を使いました。
正規表現で検索できるので、strsearch に比べると凝ったことが簡単にできますね。

この部分を strsearch(trace_name, "wave1", 0) >= 0 としてしまうと、
wave10 などだけでなく、wave1 まで引っかかってしまいます。


* グラフ上の選択領域を得る [#d6fd38cf]

グラフ上をマウスで斜めにドラッグすると矩形領域を選べますが、
この範囲を Igor では Marquee と呼んでいます。

使用例

 LANG:Igor(linenumber)
 // 与えられた座標がグラフの選択領域に含まれているかどうか返す
 function IsPointInSelectedRegion(x, y)
 variable x, y
 
     string graph_name = "Graph0"
 
     struct Rectangle selected_region
     GetMarqueeRegion(graph_name, selected_region)
 
     return IsPointInRect(x, y, selected_region)
 end

[[コマンドラインから>http://dora.bk.tsukuba.ac.jp/~takeuchi/index.php?cmd=read&page=%A5%BD%A5%D5%A5%C8%A5%A6%A5%A7%A5%A2%2FIgor%2F%A5%B7%A5%B9%A5%C6%A5%E0%A4%CE%B4%F0%CB%DC#content_1_0]]

 LANG:Igor
 make/N=100 wave0 = x
 display wave0
 
 // 適当な領域をマウスで選択してから
 print IsPointInSelectedRegion(20,20)

コード

 LANG:Igor(linenumber)
 // 矩形領域を格納するための構造体
 Structure Rectangle
     double left
     double right
     double top
     double bottom
 EndStructure
 
 // 指定された名前のグラフから選択範囲を得る
 // 選択されていなければ全範囲 (left, bottom 軸で) を返す
 function GetMarqueeRegion(graph_name, region)
 string graph_name
 Struct Rectangle &region
 
     GetMarquee/W=$graph_name left, bottom
     if(!V_Flag)
         GetAxis/q/W=$graph_name bottom
         V_Left   = V_min
         V_Right  = V_max
         GetAxis/q/W=$graph_name left
         V_Top    = V_min
         V_Bottom = V_max
     endif
 
     region.left = V_Left
     region.right = V_Right
     region.top = V_Top
     region.bottom = V_Bottom
 end
 
 // x, y で指定された点が rect 領域に入っているかどうかを返す 
 function IsPointInRect(x, y, rect)
 variable x, y
 Struct Rectangle &rect
     variable result
     result = (x-rect.left)*(x-rect.right) <= 0
     result = (y-rect.top)*(y-rect.bottom) <= 0 && result
     return result
 end

IsPointInRect は、left < right, top < bottom を期待せず、
right < left や bottom < top でも、
内部か外部かを正しく判別できるようにしてあります。

* グラフ上の選択範囲を設定する [#dcd89a94]

SetMarquee を使えばいいのですが、単位をポイントに直さなければならないので、
PixelFromAxisVal と ScreenResolution を呼んで変換します。

また、普通にやると上下逆さまに指定することになって正しく選択されないため、
数値の大小で指定を並べ替えています。

コード

 LANG:Igor
 // 下軸、左軸の値を指定してグラフの選択範囲を設定する
 function SetMarqueeByAxisVal(graph_name, x1, y1, x2, y2)
 string graph_name
 variable x1, y1, x2, y2
     x1 = PixelFromAxisVal(graph_name, "bottom", x1) / ScreenResolution * 72
     x2 = PixelFromAxisVal(graph_name, "bottom", x2) / ScreenResolution * 72
     y1 = PixelFromAxisVal(graph_name, "left",   y1) / ScreenResolution * 72
     y2 = PixelFromAxisVal(graph_name, "left",   y2) / ScreenResolution * 72
     variable t
     if (x2<x1)
     	t=x2; x2=x1; x1=t;
     endif
     if (y2<y1)
     	t=y2; y2=y1; y1=t;
     endif
     SetMarquee/w=$graph_name x1, y1, x2, y2
 end

* グラフ上への DrawAction について [#b8aac765]

DrawLine, DrawArc, DrawRect など、一連の DrawXXX 関数によってグラフ上に様々な図形を描画できます。

しかし、注釈を付ける際の TextBox 等と違って DrawXXX で書いた図形には名前が付かないため、
一旦描いた DrawXXX 図形をスクリプトから変更する方法が分かりづらいです。

例えば、一旦書いた DrawXXX 図形を後から消去したいような場合には、

+ SetDrawEnv gstart, gname = the_group_name で一連の描画を入れる名前付きグループを作成する
+ DrawXXX を使って描画する
+ SetDrawEnv gstop で名前付きグループを閉じる
+ あとから、DrawAction getgroup=the_group_name, delete のようにグループを消去する

という手順を取ります。

コード例:[[(コマンドラインに貼り付けられます)>http://dora.bk.tsukuba.ac.jp/~takeuchi/index.php?cmd=read&page=%A5%BD%A5%D5%A5%C8%A5%A6%A5%A7%A5%A2%2FIgor%2F%A5%B7%A5%B9%A5%C6%A5%E0%A4%CE%B4%F0%CB%DC#content_1_0]]

 LANG:Igor
 // 適当なグラフを作成
 Make wave0 = {0, 1}
 Display wave0
 // グループを指定して四角形を描画
 SetDrawEnv gstart, gname=my_group_name
 SetDrawEnv xcoord=bottom, ycoord=left
 SetDrawEnv linefgc= (0,65280,0), fillpat=0, dash=1
 DrawRect 0.1, 0.1, 0.3, 0.4
 SetDrawEnv gstop
 // グループを指定せずに描画 (色指定などは持ち越されない)
 DrawRect 0.4, 0.5, 0.6, 0.7
 DoAlert 0, "1つ目に書いた図形を消去します"
 DrawAction getgroup=my_group_name, delete
 DoAlert 0, "残っている2つ目に書いた図形も含めて全部消去します"
 DrawAction delete

* 棒グラフや都市景観グラフの罠 [#n0be756b]

Igor で棒グラフや都市景観グラフを書くと、

''“対応する x 座標値の「右側」にグラフが書かれます”''

これ、注意しないと結果を見間違います。~
次のコードを[[コマンドラインに貼り付けて>http://dora.bk.tsukuba.ac.jp/~takeuchi/index.php?cmd=read&page=%A5%BD%A5%D5%A5%C8%A5%A6%A5%A7%A5%A2%2FIgor%2F%A5%B7%A5%B9%A5%C6%A5%E0%A4%CE%B4%F0%CB%DC#content_1_0]]みて下さい。

 LANG:Igor
 make wave0 = {0,1,2,1,0}
 display wave0
 ModifyGraph mode=3,marker=19
 DoAlert 0, "x=2 をピークとするグラフになっていることを確認して下さい"
 DoAlert 0, "このデータを棒グラフで表示します"
 ModifyGraph mode=5
 DoAlert 0, "ピークが x=2.5 にずれてしまいました"
 DoAlert 0, "このデータを都市景観グラフで表示します"
 ModifyGraph mode=6
 DoAlert 0, "やはり同じです"
 DoAlert 0, "オフセットを付けて無理矢理合わせます"
 ModifyGraph offset={ - DeltaX(wave0) / 2, 0 }

以下説明です。

 LANG:Igor
 *make wave0 = {0,1,2,1,0}
 *display wave0
 *ModifyGraph mode=3,marker=19

&attachref(mode3.png);

ここまでは問題ないですが、上のグラフのデータを棒グラフにすると、

 LANG:Igor
 *ModifyGraph mode=5

&attachref(mode5.png);

このように、見事にずれてしまいます。

上のグラフでは x=2 が頂点だったのに、
このグラフでは x=2.5 が頂点に見えてしまいます。

都市景観でも同様です。

 LANG:Igor
 *ModifyGraph mode=6

&attachref(mode6.png);

棒を本来の値の真上に持ってくるには、
グラフに柱の半分だけオフセットを履かせる必要があります。

 LANG:Igor
 *ModifyGraph offset={ - DeltaX(wave0) / 2, 0 }

&attachref(mode6offset.png);

ようやく合いました。

** Histogram との組み合わせ [#e600b145]

上記と似たような話で Histogram も注意です。

新しく Igor を立ち上げて、[[コマンドウィンドに以下のコマンドを貼り付けてみて下さい>http://dora.bk.tsukuba.ac.jp/~takeuchi/index.php?cmd=read&page=%A5%BD%A5%D5%A5%C8%A5%A6%A5%A7%A5%A2%2FIgor%2F%A5%B7%A5%B9%A5%C6%A5%E0%A4%CE%B4%F0%CB%DC#content_1_0]]。

 LANG:Igor
 Make/N=1000 wave0=gnoise(1)
 Make/N=10 wave0_Hist
 Histogram/B={-5,1,10} wave0, wave0_Hist
 Display wave0_Hist
 ModifyGraph grid=1
 CurveFit/NTHR=0/W=0 gauss wave0_Hist /D 
 ModifyGraph rgb(fit_wave0_Hist)=(0,0,0)
 DoAlert 0, "次へ進みます"
 ModifyGraph mode(wave0_Hist)=5
 ModifyGraph hbFill(wave0_Hist)=5
 DoAlert 0, "次へ進みます"
 Histogram/B={-5,1,10}/C wave0, wave0_Hist
 CurveFit/NTHR=0/W=0 gauss wave0_Hist /D 
 DoAlert 0, "次へ進みます"
 ModifyGraph offset(wave0_Hist)={ - DeltaX(wave0_Hist)/2, 0 }

以下、説明です。

始めに、期待値 0、標準偏差 1 のガウス分布のランダム値 1000 個を生成し、
そのヒストグラムを作成して、結果をガウシアンでフィッティングしています。

 LANG:Igor
 *Make/N=1000 wave0=gnoise(1)
 *Make/N=10 wave0_Hist
 *Histogram/B={-5,1,10} wave0, wave0_Hist
 *Display wave0_Hist
 *ModifyGraph grid=1
 *CurveFit/NTHR=0/W=0 gauss wave0_Hist /D 
  適切に収束しました
  fit_wave0_Hist= W_coef[0]+W_coef[1]*exp(-((x-W_coef[2])/W_coef[3])^2)
  W_coef={2.6318,390.96,-0.50822,1.4051}
  V_chisq= 76.6007;V_npnts= 10;V_numNaNs= 0;V_numINFs= 0;
  V_startRow= 0;V_endRow= 9;
  W_sigma={1.65,3.5,0.00967,0.0162}
  係数値 ±標準偏差
  	y0   	=2.6318 ± 1.65
  	A    	=390.96 ± 3.5
  	x0   	=-0.50822 ± 0.00967
  	width	=1.4051 ± 0.0162
 *ModifyGraph rgb(fit_wave0_Hist)=(0,0,0)

&attachref(HistogramTrap1.png);

ただこの結果、ご覧の通りなぜか期待値がゼロになりません。

この理由は、ヒストグラムを棒グラフ表示してみると分かります。

 LANG:Igor
 *ModifyGraph mode(wave0_Hist)=5
 *ModifyGraph hbFill(wave0_Hist)=5

&attachref(HistogramTrap2.png);

上で述べた「棒グラフの罠」のおかげで、棒グラフの方はちゃんと中央がゼロになりました。~
ヒストグラムの結果はこのように棒グラフ表示することを前提としたもので、
恐らく棒グラフ表示の方もこのようにヒストグラムと組み合わせて使うことを前提としているのだと思います。

が、、、これは完全に初見殺しの罠になってしまってます。

ヒストグラムの結果を正しくフィッティングするには、
ヒストグラム作成時に /C を付ける必要があります。

 LANG:Igor
 *Histogram/B={-5,1,10}/C wave0, wave0_Hist
 *CurveFit/NTHR=0/W=0 gauss wave0_Hist /D 
  適切に収束しました
  fit_wave0_Hist= W_coef[0]+W_coef[1]*exp(-((x-W_coef[2])/W_coef[3])^2)
  W_coef={2.6318,390.96,-0.0082209,1.4051}
  V_chisq= 76.6007;V_npnts= 10;V_numNaNs= 0;V_numINFs= 0;
  V_startRow= 0;V_endRow= 9;
  W_sigma={1.65,3.5,0.00967,0.0162}
  係数値 ±標準偏差
  	y0   	=2.6318 ア 1.65
  	A    	=390.96 ア 3.5
  	x0   	=-0.0082209 ア 0.00967
  	width	=1.4051 ア 0.0162

&attachref(HistogramTrap3.png);

こんどはちゃんと期待値がほぼゼロになってくれました。~
が、ヒストグラムの棒グラフ表示がずれてしまっていますので、
結局オフセットを使って姑息に合わせなければなりません。

 LANG:Igor
 *ModifyGraph offset(wave0_Hist)={ - DeltaX(wave0_Hist)/2, 0 }

&attachref(HistogramTrap4.png);

ようやく求めていた結果が得られました。
ようやく期待する結果が得られました。

Counter: 13841 (from 2010/06/03), today: 3, yesterday: 0