Igor Proでグラフを見ていると、「この範囲だけ直線でフィットしたい」という場面がたまによくあります。
たとえば、吸収端の立ち上がり部分、CVの一部の直線領域、時間変化データの初期速度、ベースラインの傾き確認などです。 グラフ全体をフィットするのではなく、見た目で範囲を選んで、その部分だけをさっと直線フィットできるとかなり便利です。

今回は、Igor ProのGraphMarquee機能を使って、グラフ上でドラッグ選択した範囲だけを線形フィットするマクロを紹介します。 マクロ名はスクリプト内では LineFitMarquee です。
できること
- グラフ上でマウスドラッグした範囲だけを線形フィットする
- 複数traceがある場合は、どのtraceをフィットするか選べる
- X wave付きのXYグラフにも、wave scalingだけの通常グラフにも対応する
- フィット結果を青い点線として元のグラフに重ね描きする
- フィットに使ったX/Y wave、フィット結果wave、係数waveを元データと同じdata folderに保存する
要するに、グラフを見ながら「ここからここまで」と囲むだけで、その範囲の直線フィットを作れるマクロです。
使い方
- フィットしたいwaveをグラフに表示します。
- グラフ上で、フィットしたい範囲をマウスでドラッグして囲みます。

- 右クリックしてGraphMarqueeメニューから
Line Fit Marquee Rangeを選びます。
- 複数traceがある場合は、フィットしたいtraceを選びます。

- 選択範囲だけが線形フィットされ、結果がグラフに重ね描きされます。
(aが切片,bが傾き,V_r2がR^2値としてコマンドラインに出力される)
実行後には、IgorのHistoryにフィット対象のtrace名、元のY wave、フィット結果wave、係数waveの保存場所が表示されます。 あとから結果を確認したいときは、この出力を見ると分かりやすいです。
出力されるwave名は、元のY wave名をもとにして自動で作られます。
fitX_元wave名
fitY_元wave名
fit_元wave名
coef_元wave名

すでに同じ名前のwaveがある場合は、Igorの UniqueName によって重複しない名前になります。
注意点
- 選択範囲内に有効な点が2点未満の場合はフィットできません。
- 現在のマクロでは、marqueeのX方向の範囲を使ってデータを選びます。
つまり、縦方向にどれだけ大きく囲むかよりも、横方向にどこからどこまで囲むかが重要です。 グラフ上でX範囲を指定する道具として使うイメージです。
マクロの仕組み
このマクロは、Igor Proの GraphMarquee メニューに項目を追加しています。
Menu "GraphMarquee"
"Line Fit Marquee Range", LineFitMarquee()
End
GraphMarquee は、グラフ上で選択範囲を作ったときに使うメニューです。 ここにマクロを置いておくと、「グラフ上で囲んだ範囲に対して何かする」という操作を自然に追加できます。
1. グラフとmarqueeの有無を確認する
最初に、現在の対象ウィンドウがグラフかどうかを確認します。 さらに、marquee範囲が作られていなければ処理を止めます。
if (WinType(WinName(0, -1)) != 1)
Abort "The target window must be a graph."
endif
GetMarquee left
if (V_Flag == 0)
Abort "Please create a marquee (drag to select) before running this macro."
endif
ここで GetMarquee を使っています。 これが今回のマクロの肝です。 グラフ上で囲んだ範囲の座標をIgor側から取得できます。
2. フィットするtraceを選ぶ
次に、アクティブなグラフに載っているtrace一覧を取得します。 traceが複数ある場合は、ポップアップで対象を選べるようにしています。
String traceList = TraceNameList("", ";", 1)
String traceName = StringFromList(0, traceList)
Prompt traceName, "Trace to fit", popup, traceList
DoPrompt "Quick linear fit", traceName
複数のデータを同じグラフに重ねているとき、どれをフィットするのかを毎回選べるのは大事です。 ここを決め打ちにすると、気づかないうちに別のtraceをフィットしてしまうことがあります。
3. traceからY waveとX waveを取得する
選ばれたtraceから、Y waveとX waveを取得します。
WAVE/Z yWave = TraceNameToWaveRef("", traceName)
WAVE/Z xWave = XWaveRefFromTrace("", traceName)
Variable isXY = WaveExists(xWave)
XYグラフの場合はX waveがあります。 一方、X waveを指定せずに表示した通常のwaveでは、X waveが存在しません。 その場合は pnt2x を使って、wave scalingからX座標を計算します。
if (isXY)
xv = xWave[p]
else
xv = pnt2x(yWave, p)
endif
この処理のおかげで、XYグラフでも普通のwaveグラフでも同じマクロを使えます。
4. marqueeのX範囲を取得する
実際にフィット範囲として使うのは、marqueeのX方向の範囲です。
GetMarquee bottom
Variable xMin = V_left
Variable xMax = V_right
左から右へドラッグしても、右から左へドラッグしても動くように、大小が逆なら入れ替えています。
if (xMin > xMax)
Variable tmpX = xMin
xMin = xMax
xMax = tmpX
endif
5. 範囲内の点だけを抜き出す
元のwaveを先頭から最後まで走査し、X座標が選択範囲内にある点だけを fitX と fitY にコピーします。 このとき、NaN などの無効値は除外しています。
if ((xv >= xMin) && (xv <= xMax) && (numtype(xv) == 0) && (numtype(yv) == 0))
InsertPoints count, 1, fitX, fitY
fitX[count] = xv
fitY[count] = yv
count += 1
endif
この部分で、グラフ上の見た目の範囲と、実際にフィットへ渡すデータ点が対応します。
6. CurveFitで直線フィットする
範囲内の点が2点以上あれば、Igor標準の CurveFit で直線フィットします。
CurveFit/N=1 line, kwCWave=fitCoef, fitY /X=fitX /D=fitResult /I=0
fitCoef にはフィット係数が入ります。 直線フィットなので、基本的には切片と傾きです。 fitResult には、フィット曲線のY値が入ります。
7. 結果をグラフに重ねる
最後に、フィット結果を元のグラフに追加します。 結果は青色の点線で表示されます。
AppendToGraph fitResult vs fitX
ModifyGraph rgb($NameOfWave(fitResult)) = (0,0,65535)
ModifyGraph lstyle($NameOfWave(fitResult)) = 2
元データの上にフィット線が直接重なるので、選択範囲やフィットの妥当性をすぐ確認できます。 この「見ながら選んで、すぐ結果を見る」感じがかなり使いやすいです。
どんな場面で便利か
このマクロは、厳密な自動解析というより、「人間がグラフを見て、ここだと思った範囲をすばやく定量する」ための道具です。
- UV-visの吸収端の傾きを見たいとき
- 時間変化データの初期速度をざっくり確認したいとき
- グラフの一部だけを直線近似したいとき
スクリプト
最後に、記事用にコメントを少し整理した版を載せておきます。
Menu "GraphMarquee"
"Line Fit Marquee Range", LineFitMarquee()
End
Macro LineFitMarquee()
DoQuickFitMarquee()
End
Function DoQuickFitMarquee()
if (WinType(WinName(0, -1)) != 1)
Abort "The target window must be a graph."
endif
GetMarquee left
if (V_Flag == 0)
Abort "Please create a marquee (drag to select) before running this macro."
endif
QuickFitMarquee()
End
Function QuickFitMarquee()
String traceList = TraceNameList("", ";", 1)
if (ItemsInList(traceList) == 0)
Abort "No trace was found in the active graph."
endif
String traceName = StringFromList(0, traceList)
Prompt traceName, "Trace to fit", popup, traceList
DoPrompt "Quick linear fit", traceName
if (V_Flag)
Abort "Canceled."
endif
PauseUpdate; Silent 1
WAVE/Z yWave = TraceNameToWaveRef("", traceName)
if (!WaveExists(yWave))
Abort "Failed to get the Y wave from the selected trace."
endif
WAVE/Z xWave = XWaveRefFromTrace("", traceName)
Variable isXY = WaveExists(xWave)
String oldDF = GetDataFolder(1)
String yFullPath = GetWavesDataFolder(yWave, 2)
String yBareName = NameOfWave(yWave)
String yDF = yFullPath[0, strlen(yFullPath) - strlen(yBareName) - 1]
SetDataFolder $yDF
String outBase = CleanupName(NameOfWave(yWave), 0)
String fitXName = UniqueName("fitX_" + outBase, 1, 0)
String fitYName = UniqueName("fitY_" + outBase, 1, 0)
String fitResultName = UniqueName("fit_" + outBase, 1, 0)
String fitCoefName = UniqueName("coef_" + outBase, 1, 0)
Make/O/N=0 $fitXName, $fitYName
Make/O/N=2 $fitCoefName
WAVE fitX = $fitXName
WAVE fitY = $fitYName
WAVE fitCoef = $fitCoefName
SetDataFolder $oldDF
GetMarquee bottom
Variable xMin = V_left
Variable xMax = V_right
if (xMin > xMax)
Variable tmpX = xMin
xMin = xMax
xMax = tmpX
endif
Variable count = 0
Variable p
Variable xv, yv
Variable n = numpnts(yWave)
for (p = 0; p < n; p += 1)
if (isXY)
xv = xWave[p]
else
xv = pnt2x(yWave, p)
endif
yv = yWave[p]
if ((xv >= xMin) && (xv <= xMax) && (numtype(xv) == 0) && (numtype(yv) == 0))
InsertPoints count, 1, fitX, fitY
fitX[count] = xv
fitY[count] = yv
count += 1
endif
endfor
if (count < 2)
KillWaves/Z fitX, fitY, fitCoef
Abort "Not enough valid points in the selected range to fit."
endif
SetDataFolder $yDF
Make/O/N=(count) $fitResultName
WAVE fitResult = $fitResultName
SetDataFolder $oldDF
CurveFit/N=1 line, kwCWave=fitCoef, fitY /X=fitX /D=fitResult /I=0
AppendToGraph fitResult vs fitX
ModifyGraph rgb($NameOfWave(fitResult)) = (0,0,65535)
ModifyGraph lstyle($NameOfWave(fitResult)) = 2
Print "Fitted trace: ", traceName
Print "Y wave: ", GetWavesDataFolder(yWave, 2)
Print "Fit result wave: ", GetWavesDataFolder(fitResult, 2)
Print "Fit coefficient wave: ", GetWavesDataFolder(fitCoef, 2)
End
まとめ
LineFitMarquee を使うと、Igor Proのグラフ上で選択した範囲だけをすばやく線形フィットできます。 範囲指定をグラフ上のmarquee操作に任せることで、データ点の番号やX範囲を手入力する必要がありません。
特に、グラフを見ながら「このあたりだけ直線で見たい」という作業にはかなり向いています。 GraphMarqueeは地味ですが、うまく使うとIgorの操作感をかなり良くできる機能だと思います。


















