グラフの値の読み取り
改訂:2026.03.03
データとその分析結果はグラフで表示されることが多い。分析は、何らかの視点から行われるが、分析者の視点とは異なる観点からの分析を行いたいときもある。他の観点から分析を行うためには、グラフから必要なデータ値を読み取ることになる。PyGameを利用してグラフから値を読み取ることを試みた。
まず、グラフに傾きがない場合を扱い、次に傾きがある場合を扱う。グラフの画像は、大きすぎたり小さすぎることもあるので、適度の大きさに調整することも試みた。
図A.1の画像ファイルから折れ線のデータ点の値を読み取ることを試みる。

図A.1 画像ファイルSampleData.png
図A.1のファイルから折れ線のデータ点を読み取るスクリプトをリストA.1のように作成した。Python 3.13.12を利用した(2026.02.22)。ファイルは、files1.zipにまとめた。
リストA.1 グラフの点の読み取り(read_graph.py)
import pygame as pg
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pygame import font
infl_nm = input('Input Image File = ')
outxl_nm = input('Output Excel File
Name(*.xlsx) = ')
pg.init()
font.init()
screen =
pg.display.set_mode(size=(1200, 700)) # 画面の大きさ
screen.fill((0,0,0))
# 黒で塗りつぶす
img_expln =
pg.image.load(infl_nm)
# 画像ファイルのロード
rect_expln = img_expln.get_rect() # 画像の大きさ
img_tmp =
pg.Surface.copy(img_expln) # 画像ファイルのコピー
img_x0 =
(1200-rect_expln.width)//2
# 提示画像の左上の角のX座標
img_y0 =
(700-rect_expln.height)//2
# 提示画像の左上の角のY座標(下方が正)
(x,y) = (0,0) # ポインター位置変数の初期値
data = [] # クリック位置のリスト
n = 0
# クリックデータの数
ck = True
while ck:
# スクリーンを黒で塗りつぶす
screen.fill((0,0,0))
img_tmp =
pg.Surface.copy(img_expln)
(x,y) =
pg.mouse.get_pos()
# ポインターの位置に緑の小円を描く
pg.draw.circle(img_tmp,(0,255,0), (x-img_x0,y-img_y0), 10, 2)
screen.blit(img_tmp,
((1200-rect_expln.width)//2,(700-rect_expln.height)//2))
# スクリーンの表示
pg.display.flip()
for e in pg.event.get():
if
e.type == pg.QUIT:
ck = False
break
if
e.type == pg.KEYDOWN:
if e.key == pg.K_q: # キーGが押されたかのチェック
ck = False
break
if
e.type == pg.MOUSEBUTTONDOWN:
# クリックされた位置に赤の小円をimg_explnに描き、dataに記録する。
pg.draw.circle(img_expln,(255, 0, 0), (x-img_x0,y-img_y0), 8, 2)
data.append([n, x-img_x0,y-img_y0])
n += 1
font.quit()
pg.quit()
print(data)
# dataを辞書型に変換
dict_data = {'data_id':[], 'x':[],
'y':[]}
for v in data:
dict_data['data_id'].append(v[0])
dict_data['x'].append(v[1])
dict_data['y'].append(v[2])
# 辞書型データをExcelファイルに保存
print(dict_data)
dframe = pd.DataFrame(dict_data)
dframe.to_excel(outxl_nm, index=False)
リストA.1のスクリプトを実行すると、入力データファイル名と読み込んだ値を出力するExcelファイル名の設定が求められる。
= RESTART: ****\files1\read_graph.py
pygame 2.6.1 (SDL 2.28.4, Python
3.13.12)
Hello from the pygame community.
https://www.pygame.org/contribute.html
Input Image File = SampleData.png
Output Excel File Name(*.xlsx) =
Sample.xlsx
出力ファイル名は、適当なExcelファイル名を設定する。
ファイル名を設定すると、画像ファイルが読み込まれ、図A.2のような画面が表示される。他のWindowに隠れて見えないときがあるが、Windows画面の下端のタスクバー上のPythonのアイコン上にマウスのポインターを置くと、Python関係の実行中のWindowが表示されるので、図A.2のWindowを選んでクリックすればよい。

図A.2
画像の上にマウスのポインターを置くと、その位置に緑の小円が表示される。

図A.3
マウスのボタンをクリックすると、緑の小円の内側に赤の小円が表示される(図A.4)。

図A.4
このとき、次のスクリプトにより、クリック位置がリストdataに追加される。
if e.type
== pg.MOUSEBUTTONDOWN:
# クリックされた位置に赤の小円をimg_explnに描き、dataに記録する。
pg.draw.circle(img_expln,(255, 0, 0), (x-img_x0,y-img_y0), 8, 2)
data.append([n, x-img_x0,y-img_y0])
n += 1
マウスの移動は、速さを遅く設定しておくと位置決めが容易になる。マウスの移動速度は、「システム|Bluetoothとデバイス|マウス」の「マウスポインターの速度」で選ぶことができる。
キーQを押すと、画面が閉じられて、グラフ値の読み込みが終了する。
読み込まれたグラフ値のリストdataは、以下のスクリプトでPandasのDataFrame型に変換され、Exelファイルとして保存される。
# dataを辞書型に変換
dict_data = {'data_id':[], 'x':[],
'y':[]}
for v in data:
dict_data['data_id'].append(v[0])
dict_data['x'].append(v[1])
dict_data['y'].append(v[2])
# 辞書型データをExcelファイルに保存
print(dict_data)
dframe = pd.DataFrame(dict_data)
dframe.to_excel(outxl_nm, index=False)
スクリプトの実行終了後、保存されたExcelファイルを開くと、図A.5のようになっている。意図せずにクリックされて記録された行は、削除すればよい。

図A.5
保存されたExcelファイルのチェック
グラフ値を読み込み、作成されたExcelファイルのチェックを行うスクリプトを、リストB.1のように用意した。
リストB.1 読み込みデータのチェック(check_values.py)
import pygame as pg
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pygame import font
infl_nm = input('Image File Name = ')
xlfl_nm = input('Excel file name = ')
pg.init()
font.init()
screen =
pg.display.set_mode(size=(1200, 700)) # 画面の大きさ
screen.fill((0,0,0))
# 黒で塗りつぶす
my_font = pg.font.SysFont(None,
20)
# フォントの大きさ
img_expln =
pg.image.load(infl_nm)
rect_expln = img_expln.get_rect()
img_x0 = (1200-rect_expln.width)//2
img_y0 = (700-rect_expln.height)//2
values = pd.read_excel(xlfl_nm).values
print(values)
for v in values:
# 読み込み値の表示
pg.draw.circle(img_expln,(255,
0, 0), (v[1],v[2]), 7, 1)
screen.blit(img_expln,
((1200-rect_expln.width)//2,(700-rect_expln.height)//2))
for v in values:
# 読み込み値のIDの表示
img_str =
my_font.render(f'{v[0]}',
True, (255,0, 0), None)
rect_str =
img_str.get_rect()
screen.blit(img_str,
(3+v[1]+img_x0, 3+v[2]+img_y0)) # (x-img_x0,y-img_y0))
ck = True
while ck:
pg.display.flip()
for e in pg.event.get():
if
e.type == pg.QUIT:
ck = False
break
if
e.type == pg.KEYDOWN:
if e.key == pg.K_q: # キーGが押されたかのチェック
ck = False
break
font.quit()
pg.quit()
リストB.1のスクリプトを実行すると、グラフ値の読み込みを行った画像ファイル名と読み取りの結果を格納したExcelファイル名の入力が求められる。
= RESTART: ****\files1\check_values.py
pygame 2.6.1 (SDL 2.28.4, Python
3.13.12)
Hello from the pygame community.
https://www.pygame.org/contribute.html
Image File Name = SampleData.png
Excel file name = Sample.xlsx
ファイル名を設定すると、図B.1の画面が表示される。

図B.1
画像データの上に、クリックした位置が赤の小円で、その右下にデータ識別子(図A.5のExcelファイルの第1欄の文字列)が表示されている。不適切なデータがあれば、Excelで開いて該当行を削除すればよい。
問題が無ければ、次に進み、読み込んだグラフ値の描画を行う。
読み込みグラフ値の表示
グラフから読み込んだ値は座標がピクセル値であるが、これをグラフで用いられている尺度値に変換して表示する。リストC.1にスクリプトを示す。
リストC.1 読み込み値の表示(ReConstrctn.py)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
xlfl_nm = input('Excel file name = ')
values = pd.read_excel(xlfl_nm).values
print(values)
# X座標の基準点
x_1 = values[0][1]
x_9 = values[1][1]
# Y座標の基準点
y_0 = values[2][2]
y_20 = values[3][2]
def x_transf(v):
"""
読み込み値をX座標に変換
"""
return 1.0 + (9 - 1) * (v -
x_1) / (x_9 - x_1)
def y_transf(v):
"""
読み込み値をY座標に変換
"""
return 0.0 + (20 - 0) * (v -
y_0) / (y_20 - y_0)
x = []
y = []
for i in range(4, 13):
x.append(x_transf(values[i][1]))
y.append(y_transf(values[i][2]))
plt.plot(x, y, 'o-')
plt.title('Read Out Values',
fontsize=16)
plt.show()
上のスクリプトを実行すると、グラフ値を読み込んだExcelファイル名の設定が求められる。
= RESTART: ****\files1\ReConstrctn.py
Excel file name = Sample.xlsx
ファイル名を設定すると、図C.1のグラフが表示される。

図C.1
Excelファイルは、座標がピクセル値であるが、これを図B.1に合わせて、入力グラフの尺度値に以下のように変換している。
X軸、Y軸への座標値の変換は、図B.1における0番の点、1番の点、および2番の点、3番の点のデータから次の関数でピクセル値から元の座標値への変換を行っている。
# X座標の基準点
x_1 = values[0][1]
x_9 = values[1][1]
# Y座標の基準点
y_0 = values[2][2]
y_20 = values[3][2]
def x_transf(v):
"""
読み込み値をX座標に変換
"""
return 1.0 + (9 - 1) * (v -
x_1) / (x_9 - x_1)
def y_transf(v):
"""
読み込み値をY座標に変換
"""
return 0.0 + (20 - 0) * (v -
y_0) / (y_20 - y_0)
この変換関数により、図B.1の点4から点12までのピクセル値を次のスクリプトで元の尺度値に変換した座標をリストxおよびyに格納している。
x = []
y = []
for i in range(4, 13):
x.append(x_transf(values[i][1]))
y.append(y_transf(values[i][2]))
変換された座標による描画を、次のスクリプトで行っている。
plt.plot(x, y, 'o-')
plt.title('Read Out Values',
fontsize=16)
plt.show()
グラフが、図D.1のように傾いている場合を考える。なお、傾いている場合用のスクリプトは、グラフが傾いていない場合にも使用できる。ファイルは、files2.zipにまとめた。

図D.1 SampleDataRot.png
図D.1の画像ファイルからグラフの値を読み込むスクリプトは、リストA.1のスクリプトで行う。
リストA.1のスクリプトを実行すると、読み取る画像ファイル名と読み込んだ結果を出力するExcelファイル名の設定が求められる。
= RESTART: ****\files2\read_graph.py
pygame 2.6.1 (SDL 2.28.4, Python
3.13.12)
Hello from the pygame community.
https://www.pygame.org/contribute.html
Input Image File = SampleDataRot.png
Output Excel File Name(*.xlsx) =
SampleRot.xlsx
ファイル名を設定すると、図D.1のWindowが表示される。図A.2の場合と同様に読み込み点をクリックしていく。

図D.2
点の読み込みが終わったら、キーQを押して終了する。
読み込んだ値のチェックは、リストB.1のスクリプトで行える。上のデータの場合、図D.3のようになる。

図D.3
出力Excelファイルは、図D.4のようである。

図D.4
不適当なデータがあれば、Excelファイルにおいて削除すればよい。
点の読み込みで作成されたExcelファイルからグラフの尺度値に変換するスクリプトは、リストD.1のように用意した。
リストD.1 画像グラフの傾きを考量したグラフの尺度値の構成スクリプト(ReConstrctnRot.py)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
xlfl_nm = input('Input Excel file name
= ')
xlfout_nm = input('Output Excel file
name = ')
values = pd.read_excel(xlfl_nm).values
print(values)
class TransF():
def __init__(self, x0,
x1, # X軸の左と右の基準点
v0, v1,
# X軸の基準点の値
y0, y1,
# Y軸の下と上の基準点
w0, w1):
# Y軸の基準点の値
# X座標の単位ベクトル
e_x
= np.array(x1) - np.array(x0)
self.e_x = e_x / (np.sum(e_x**2)**0.5)
self.x0 = np.dot(np.array(x0), self.e_x)
self.x1 = np.dot(np.array(x1), self.e_x)
self.v0 = v0
self.v1 = v1
# Y座標の単位ベクトル
e_y
= np.array(y1) - np.array(y0)
self.e_y = e_y / (np.sum(e_y**2)**0.5)
self.y0 = np.dot(np.array(y0), self.e_y)
self.y1 = np.dot(np.array(y1), self.e_y)
self.w0 = w0
self.w1 = w1
def t_func(self, p): # 点pのピクセル値の座標をX軸Y軸の座標に変換
p =
np.array(p)
p_x
= np.dot(p, self.e_x)
x =
self.v0 + (self.v1 - self.v0) * \
(p_x - self.x0) / (self.x1 - self.x0)
p_y
= np.dot(p, self.e_y)
y =
self.w0 + (self.w1 - self.w0) * \
(p_y - self.y0) / (self.y1 - self.y0)
return x, y
tf = TransF([values[0][1],
values[0][2]], [values[1][1], values[1][2]],
1, 9,
[values[2][1], values[2][2]], [values[3][1], values[3][2]],
0, 20)
x = []
y = []
for i in range(4, 13):
vx, vy =
tf.t_func([values[i][1], values[i][2]])
x.append(vx)
y.append(vy)
plt.plot(x, y, 'o-')
plt.title('Read Out Values',
fontsize=16)
plt.show()
dict_out = {'X':x, 'Y':y}
dframe = pd.DataFrame(dict_out)
dframe.to_excel(xlfout_nm,
index=False)
print(xlfout_nm, 'was saved.')
リストD.1のファイルを実行する。
= RESTART:
****\files2\ReConstrctnRot.py
Input Excel file name = SampleRot.xlsx
Output Excel file name =
SampleExcel.xlsx
グラフ値を読み取ったExcelファイルと、変換した尺度値を出力するExcelファイルの名前を設定すると、グラフの尺度値が算出されて図D.5のように表示される。

図D.5
ピクセル値座標からグラフの元の尺度値への変換は、次のクラスTransFによって行っている。
class TransF():
def __init__(self, x0,
x1, # X軸の左と右の基準点
v0, v1,
# X軸の基準点の値
y0, y1,
# Y軸の下と上の基準点
w0, w1):
# Y軸の基準点の値
グラフの傾きを戻すために、X軸方向のベクトルとY軸方向のベクトルを、図D.6に示すようにとっている。


図D.6
すなわち、
tf = TransF([values[0][1],
values[0][2]], [values[1][1], values[1][2]],
1, 9,
[values[2][1], values[2][2]], [values[3][1], values[3][2]],
0, 20)
である。
点0から点1までのベクトルをとり、点0でのX座標を1,点1でのX座標を9としている。
点2から点3までのベクトルをとり、点2でのY座標を0,点3でのY座標を20としている。
図D.5に表示されているグラフの値は、出力用Excelファイルに図D.7のように格納されている。

図D.7
グラフから読み取った値は、Excelファイルに格納されているので、いろいろな分析を適用することができる。
画像が、図A.2の枠に対して大き過ぎる、あるいは小さ過ぎるときに、画像ファイルの大きさを調整するスクリプトとしてリストE.1のスクリプトを作成してみた。ファイルは、files3.zipにまとめた。
リストE.1 画像ファイルのリサイズ(rescale_img.py)
import cv2
# pip install opencv-python
import pygame as pg
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
inflnm = input('Input Image File = ')
img0 = cv2.imread(inflnm)
outflnm = input('Output Image File =
')
pg.init()
screen =
pg.display.set_mode(size=(1200, 700)) # 画面の大きさ
screen.fill((0,0,0))
# 黒で塗りつぶす
v_scl = 100 # rescaling fatorの初期値 100%
(h0, w0, _rgb0) = np.shape(img0)
while True:
pg.init()
screen =
pg.display.set_mode(size=(1200, 700)) # 画面の大きさ
screen.fill((0,0,0))
#
#
Rescaling
#
sw = int(w0*v_scl/100)
sh = int(h0*v_scl/100)
img1 = np.empty((sh, sw, 3),
dtype = 'uint8')
cv2.resize(img0, dsize=(sw,
sh), dst=img1)
cv2.imwrite(outflnm,
img1)
# リサイズした画像の一時保存
pg.display.set_caption(f'{v_scl}%')
img_rescl =
pg.image.load(outflnm)
# リサイズ画像の読み込み
rect_rescl = img_rescl.get_rect() # 画像の大きさ
img_x0 =
(1200-rect_rescl.width)//2
# 提示画像の左上の角のX座標
img_y0 =
(700-rect_rescl.height)//2
# 提示画像の左上の角のY座標(下方が正)
ck = True
while ck:
# スクリーンを黒で塗りつぶす
screen.fill((0,0,0))
# リサイズ画像の貼り付け
screen.blit(img_rescl,
((1200-rect_rescl.width)//2,(700-rect_rescl.height)//2))
# スクリーンの表示
pg.display.flip()
for
e in pg.event.get():
if e.type == pg.QUIT:
ck = False
break
if e.type == pg.KEYDOWN:
if e.key == pg.K_q: # キーGが押されたかのチェック
ck = False
break
pg.quit()
v = input('Is the resizing
OK? Y(es) or N(o) = ')
if v in {'Y', 'y'}:
break
v_scl =
float(input('Resizing factor(%) = '))
print(outflnm, 'was daved.')
リストE.1のスクリプトを実行すると、大きさを調整したい画像ファイルの名前と、調整後の画像ファイルを格納する出力ファイル名の設定が求められる。
= RESTART: ****\files3\rescale_img.py
pygame 2.6.1 (SDL 2.28.4, Python
3.13.12)
Hello from the pygame community.
https://www.pygame.org/contribute.html
Input Image File = sampleRGB.png
Output Image File = FResize.png
上の例では、入力画像ファイル名としてsampleRGB.png、出力ファイル名としてFResize.pngが設定されている。
ファイル名を設定すると、入力画像ファイルが表示される。黒の枠画面は、図A.2の画面と同じ大きさである。

図E.1
図E.1のWindowがフォーカスされているとき(図E.1のWindow内をクリックすればよい)にキーQを押す、あるいは図E.1のWindowの右上角のX印をクリックするとWindowは閉じられて、端末上に次のメッセージが表示される。図E.1に表示されている画像サイズを変えるときは、Nを入力する。
Nを入力すると、画像の拡大/縮小率の設定が求められる。
Is the resizing OK? Y(es) or N(o) = N
Resizing factor(%) = 170
拡大/縮小率を設定(上の例では170%)すると、指定した拡大/縮小率による画像ファイルが表示される(図E.2)。

図E.2
図E.2のWindowをクリックしてフォーカスしてからキーQを押す、あるいは図E.2のWindowの右上角のX印をクリックすると、Windowは閉じられて、拡大/縮小した画像のサイズでよいか端末上で聞いてくる。
Is the resizing OK? Y(es) or N(o) = Y
FResize.png was daved.
Yと入力すれば、スクリプトは終了して、拡大/縮小した画像ファイルの出力ファイル名が表示される。