import csv
import matplotlib.pyplot as plt
"""
このスクリプトは、異なる手法とパラメータを使用してデータを平滑化します。
:doc:`smoothing_usage`
詳細説明:
指定されたCSVファイルから実験データを読み込み、X軸の範囲でデータをフィルタリングします。
その後、単純移動平均法と多項式近似(Savitzky-Golayフィルターに類似)の2つの異なる平滑化手法を、複数の窓幅で適用します。
平滑化されたデータは個別のCSVファイルに保存され、元のデータと平滑化されたデータがmatplotlibによってグラフとして可視化されます。
"""
#=============================
# parameters
#=============================
csvfile = 'xrd.csv'
outfile_template = 'smoothing-{}-{}.csv'
xmin = 37.0
xmax = 46.0
[ドキュメント]
def SmoothingBySimpleAverage(y, n):
"""
移動平均法を用いてデータを平滑化します。
詳細説明:
指定された窓幅 `n` の前後 `n/2` の範囲にある点の平均値を計算し、各点の新しい値とします。
データ範囲の端では、利用可能な点のみで平均が計算されます。
:param y: list: 平滑化する元のY座標データ(数値のリスト)。
:param n: int: 平滑化に使用する窓幅。内部で `int(n/2)` が使用されるため、奇数、偶数いずれの場合も中央の前後で対称的な窓が形成されます。
:returns: list: 平滑化されたY座標データのリスト。
"""
n2 = int(n / 2);
ndata = len(y);
ys = []
for i in range(0, ndata):
c = 0;
ys.append(0.0);
for k in range(i - n2, i + n2 + 1):
if k < 0 or k >= ndata:
continue
ys[i] += y[k]
c += 1
if c > 0:
ys[i] /= c;
else:
ys[i] = y[i]
return ys;
[ドキュメント]
def SmoothingByPolynomialFit(y, n):
"""
多項式近似(Savitzky-Golayフィルターに類似)を用いてデータを平滑化します。
詳細説明:
指定された窓幅 `n` の範囲にあるデータポイントに重み付き多項式近似を適用してデータを平滑化します。
使用される重み `w23j` は、Savitzky-Golayフィルターの二次多項式、三次フィットに似た係数計算に基づいており、
中央の点ほど大きな重みが与えられます。データ範囲の端では、利用可能な点のみで計算が行われます。
:param y: list: 平滑化する元のY座標データ(数値のリスト)。
:param n: int: 平滑化に使用する窓幅。内部で `int(n/2)` が使用されるため、奇数、偶数いずれの場合も中央の前後で対称的な窓が形成されます。
:returns: list: 平滑化されたY座標データのリスト。
"""
m = int(n / 2);
W23 = (4.0 * m * m - 1.0) * (2.0 * m + 3.0) / 3.0;
w23j = [0.0]*n
for j in range(-m, m+1):
w23j[j + m] = (3.0 * m * (m+1.0) - 1.0 - 5.0 * j * j) / W23
ndata = len(y)
ys = []
for i in range(0, ndata):
c = 0.0;
ys.append(0.0);
for j in range(-m, m+1):
k = i + j
if k < 0 or k >= ndata:
continue
ys[i] += w23j[j+m] * y[k]
c += w23j[j+m]
if c > 0:
ys[i] /= c
else:
ys[i] = y[i]
return ys;
[ドキュメント]
def savecsv(outfile, x, y, ys):
"""
データをCSVファイルに保存します。
詳細説明:
指定されたファイル名でCSVファイルを開き、X軸データ、元のY軸データ、および平滑化されたY軸データを
'x', 'y(raw)', 'y(smooth)' のヘッダーと共に保存します。
ファイルへの書き込み中にエラーが発生した場合は、コンソールにエラーメッセージを出力します。
:param outfile: str: 出力するCSVファイルのパスとファイル名。
:param x: list: X座標データのリスト。
:param y: list: 元のY座標データのリスト。
:param ys: list: 平滑化されたY座標データのリスト。
:returns: None
"""
try:
print("Write to [{}]".format(outfile))
f = open(outfile, 'w')
except:
# except IOError:
print("Error: Can not write to [{}]".format(outfile))
else:
fout = csv.writer(f, lineterminator='\n')
fout.writerow(('x', 'y(raw)', 'y(smooth)'))
# fout.writerows(data)
for i in range(0, len(x)):
fout.writerow((x[i], y[i], ys[i]))
f.close()
[ドキュメント]
def main():
"""
スクリプトのメイン処理を実行します。
詳細説明:
- グローバル変数 `csvfile` で指定されたCSVファイルからデータを読み込みます。
- `xmin` と `xmax` で指定された範囲外のデータは除外します。
- 異なる窓幅で単純移動平均法による平滑化を適用し、結果をCSVファイルに保存し、グラフにプロットします。
- 異なる窓幅で多項式近似法による平滑化を適用し、結果をCSVファイルに保存し、グラフにプロットします。
- 全ての平滑化結果を一つのフィギュア内のサブプロットに表示し、ユーザーの入力があるまで待機します。
:returns: None
"""
global csvfile
global outfile
print("Read data from [{}]".format(csvfile))
x = []
y = []
with open(csvfile) as f:
fin = csv.reader(f)
next(fin)
c = 0
for row in fin:
if c == 0:
label = row
print("{}\t{}".format(label[0], label[1]))
else:
xx = float(row[0])
yy = float(row[1])
if xx < xmin or xmax < xx:
continue
print("{}\t{}".format(row[0], row[1]))
x.append(xx)
y.append(yy)
c += 1
ndata = len(x)
print("")
#=============================
# prepare graph
#=============================
fig, ax = plt.subplots(3, 3, figsize = (8, 8))
ys = []
print("Smoothing by simple moving average")
icase = 0
nsmooth = 3;
method = 'simple'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingBySimpleAverage(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
ax[0, 0].plot(x, ys[0], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[0, 0].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.3)
ax[0, 0].set_title("{}p {}".format(nsmooth, method))
icase = 1
nsmooth = 11;
method = 'simple'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingBySimpleAverage(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[0, 1].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[0, 1].plot(x, ys[1], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[0, 1].set_title("{}p {}".format(nsmooth, method))
icase = 2
nsmooth = 31;
method = 'simple'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingBySimpleAverage(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[0, 2].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[0, 2].plot(x, ys[2], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[0, 2].set_title("{}p {}".format(nsmooth, method))
icase = 3
nsmooth = 51;
method = 'simple'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingBySimpleAverage(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[1, 0].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[1, 0].plot(x, ys[3], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[1, 0].set_title("{}p {}".format(nsmooth, method))
print("Smoothing by polynomial fit")
icase = 4
nsmooth = 11;
method = 'polynomialfit'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingByPolynomialFit(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[1, 1].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[1, 1].plot(x, ys[4], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[1, 1].set_title("{}p {}".format(nsmooth, method))
icase = 5
nsmooth = 31;
method = 'polynomialfit'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingByPolynomialFit(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[1, 2].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[1, 2].plot(x, ys[5], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[1, 2].set_title("{}p {}".format(nsmooth, method))
icase = 6
nsmooth = 51;
method = 'polynomialfit'
print("nsmooth={}".format(nsmooth))
ys.append(SmoothingByPolynomialFit(y, nsmooth))
for i in range(0, ndata):
print("{}\t{}\t{}".format(x[i], y[i], ys[icase][i]))
savecsv(outfile_template.format(method, nsmooth), x, y, ys[icase])
print("")
# ax[2, 0].plot(x, y, linestyle = 'none', marker = 'o', markersize = 0.5)
ax[2, 0].plot(x, ys[6], label = "{}p {}".format(nsmooth, method), linewidth = 0.5)
ax[2, 0].set_title("{}p {}".format(nsmooth, method))
plt.tight_layout()
plt.pause(0.1)
print("Press ENTER to exit>>", end = '')
input()
exit()
if __name__ == '__main__':
main()