ソフトウェア/Igor/グラフ関連
グラフに表示されたウェーブの一覧を取得する†
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
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 まで引っかかってしまいます。
グラフ上の選択領域を得る†
グラフ上をマウスで斜めにドラッグすると矩形領域を選べますが、 この範囲を 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
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 ®ion 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 でも、 内部か外部かを正しく判別できるようにしてあります。
グラフ上の選択範囲を設定する†
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 について†
DrawLine, DrawArc, DrawRect など、一連の DrawXXX 関数によってグラフ上に様々な図形を描画できます。
しかし、注釈を付ける際の TextBox 等と違って DrawXXX で書いた図形には名前が付かないため、 一旦描いた DrawXXX 図形をスクリプトから変更する方法が分かりづらいです。
例えば、一旦書いた DrawXXX 図形を後から消去したいような場合には、
- SetDrawEnv gstart, gname = the_group_name で一連の描画を入れる名前付きグループを作成する
- DrawXXX を使って描画する
- SetDrawEnv gstop で名前付きグループを閉じる
- あとから、DrawAction getgroup=the_group_name, delete のようにグループを消去する
という手順を取ります。
コード例:(コマンドラインに貼り付けられます)
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
棒グラフや都市景観グラフの罠†
Igor で棒グラフや都市景観グラフを書くと、
“対応する x 座標値の「右側」にグラフが書かれます”
これ、注意しないと結果を見間違います。
次のコードをコマンドラインに貼り付けてみて下さい。
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
ここまでは問題ないですが、上のグラフのデータを棒グラフにすると、
LANG:Igor *ModifyGraph mode=5
このように、見事にずれてしまいます。
上のグラフでは x=2 が頂点だったのに、 このグラフでは x=2.5 が頂点に見えてしまいます。
都市景観でも同様です。
LANG:Igor *ModifyGraph mode=6
棒を本来の値の真上に持ってくるには、 グラフに柱の半分だけオフセットを履かせる必要があります。
LANG:Igor *ModifyGraph offset={ - DeltaX(wave0) / 2, 0 }
ようやく合いました。
Histogram との組み合わせ†
上記と似たような話で Histogram も注意です。
新しく Igor を立ち上げて、コマンドウィンドに以下のコマンドを貼り付けてみて下さい。
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)
ただこの結果、ご覧の通りなぜか期待値がゼロになりません。
この理由は、ヒストグラムを棒グラフ表示してみると分かります。
LANG:Igor *ModifyGraph mode(wave0_Hist)=5 *ModifyGraph hbFill(wave0_Hist)=5
上で述べた「棒グラフの罠」のおかげで、棒グラフの方はちゃんと中央がゼロになりました。
ヒストグラムの結果はこのように棒グラフ表示することを前提としたもので、
恐らく棒グラフ表示の方もこのようにヒストグラムと組み合わせて使うことを前提としているのだと思います。
が、、、これは完全に初見殺しの罠になってしまってます。
ヒストグラムの結果を正しくフィッティングするには、 ヒストグラム作成時に /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
こんどはちゃんと期待値がほぼゼロになってくれました。
が、ヒストグラムの棒グラフ表示がずれてしまっていますので、
結局オフセットを使って姑息に合わせなければなりません。
LANG:Igor *ModifyGraph offset(wave0_Hist)={ - DeltaX(wave0_Hist)/2, 0 }
ようやく期待する結果が得られました。
添付ファイル:







