質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Raspbian

Raspbianは、DebianベースのRaspberry Pi用ディストリビューション。ハードウェア浮動小数点演算を有効にすることが可能で、Webブラウズなどの速度を向上できます。

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

1回答

4061閲覧

matplotlibでのグラフデータをtkinterのcanvasへ画像データとして受け渡す方法が知りたいです。

TomoWa

総合スコア5

Raspbian

Raspbianは、DebianベースのRaspberry Pi用ディストリビューション。ハードウェア浮動小数点演算を有効にすることが可能で、Webブラウズなどの速度を向上できます。

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

2クリップ

投稿2020/04/23 07:28

前提・実現したいこと

ラズパイ4B,pyhton3で計測プログラムを作成しています。
各種ICからのデータを読み込んで画面に表示することはできたのですが
10秒毎にデータグラフを書きたくてtkinterからFigureCanvasTkAggを使用して
最初の1枚を出すことはできたのですが、いろいろなアプローチを行ったんですが
2回目の書換がうまく行かずに
(エラーがでてプログラムが止まる)
苦肉の策でエラーが出ずに動いた

fig.savefig("test_figure2.png") img = Image.open('test_figure2.png') img = ImageTk.PhotoImage(img) canvas.itemconfig(img2,image=img)

というファイルを経由しての書き換えを行っています。
このファイル経由をなにか変数経由で行いたいのですが
いい方法がありますでしょうか

イメージ的には

変数A(イメージ) <= 新グラフデータ
canvas.itemconfig(img2,image=変数A(イメージ))

という感じです。
ソースファイル添付しますが計測部は省いています。

Python歴は1ヶ月です。
稚拙なソースファイルでもう訳ありませんがよろしくおねがいします。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

PYTHON ソースコード import time import datetime import tkinter as tk import tkinter.font as font import threading import RPi.GPIO as GPIO import spidev import matplotlib.pyplot as plt import numpy as np from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk from matplotlib.figure import Figure import csv import pprint import sys import os from PIL import Image, ImageTk fontsize1 = 40 #path_w = 'data/src/test_w.txt' #for csv test class Application(tk.Frame): def __init__(self, master=None): super().__init__(master) self.stop_fg=True # self.stop_fg=True self.locate=" 0.000" # self.laptime=" 0.000000000" # Process time measure self.laptime2=" 0.000000000" # Process time measure self.laptime3=" 0.000000000" # Process time measure self.testcount01=0 # temp counter01 self.testcount02=0 # temp counter02 self.temperature01A=" 0.00" # temperature01 self.temperature01B=" 0.00" # temperature02 self.temperature02A=" 0.00" # temperature01 self.temperature02B=" 0.00" # temperature02 self.adconv01=" 0.000" # ADconverterA01 self.adconv02=" 0.000" # ADconverterA02 self.strain01=" 0.000" # Starin converter01 self.strain02=" 0.000" # Strain converter02 self.hosei_fg = False self.GUI() self.on_start() def GUI(self): self.Text001=tk.Label(text=self.locate,font=("",fontsize1), anchor='w') self.Text001.grid(column=0,row=0) # Text001=tk.Label(text=" mm (位置",font=("",fontsize1)) Text001.grid(column=1,row=0) self.Text002=tk.Label(text=self.temperature01A,font=("",fontsize1),fg ='green', anchor='w') self.Text002.grid(column=0,row=1) Text002=tk.Label(text="℃ (1",font=("",fontsize1),fg ='green') Text002.grid(column=1,row=1) self.Text004=tk.Label(text=self.temperature02A,font=("",fontsize1),fg ='darkorange', anchor='w') self.Text004.grid(column=0,row=2) Text004=tk.Label(text="℃ (2",font=("",fontsize1),fg ='darkorange') Text004.grid(column=1,row=2) self.Text006=tk.Label(text=self.adconv01,font=("",fontsize1), anchor='w') self.Text006.grid(column=10,row=0) Text006=tk.Label(text=" Volt (1 ",font=("",fontsize1)) Text006.grid(column=11,row=0) self.Text007=tk.Label(text=self.adconv02,font=("",fontsize1),fg ='green', anchor='w') self.Text007.grid(column=10,row=1) Text007=tk.Label(text=" Volt (2",font=("",fontsize1),fg ='green') Text007.grid(column=11,row=1) self.Text008=tk.Label(text=self.strain01,font=("",fontsize1),fg ='darkorange', anchor='w') self.Text008.grid(column=10,row=2) Text008=tk.Label(text=" e (G1 ",font=("",fontsize1),fg ='darkorange') Text008.grid(column=11,row=2) self.Text009=tk.Label(text=self.strain02,font=("",fontsize1), anchor='w') self.Text009.grid(column=10,row=3) Text009=tk.Label(text=" e (G2 ",font=("",fontsize1)) Text009.grid(column=11,row=3) #グラフ描画テスト global x1,y1,y2,fig,ax1,canvas,h,img,img2 x1 = np.linspace(0.0, 5.0) y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) y2 = np.sin(2 * np.pi * x1) * np.exp(-x1) fig = plt.figure(figsize=(14, 5)) ax1 = fig.add_subplot(111) # ax1.plot(x1,y1,'green') h,=ax1.plot(x1,y1,'green') fig.savefig("test_figure.png") img = Image.open('test_figure.png') img = ImageTk.PhotoImage(img) canvas = tk.Canvas(bg = "black", width=1400, height=490) canvas.place(x=100, y=300) # 左上の座標を指定 # キャンバスに画像を表示する。第一引数と第二引数は、x, yの座標 img2 = canvas.create_image(0, 0, image=img, anchor=tk.NW) # canvas = FigureCanvasTkAgg(fig, master=root) # Generate canvas instance, Embedding fig in root # canvas.draw() # canvas.get_tk_widget().place(x=50,y=300) #laptime 表示 self.Text108=tk.Label(text=self.laptime,font=("",20), anchor='w') self.Text108.grid(column=0,row=3) self.Text109=tk.Label(text=self.testcount01,font=("",20), anchor='w') self.Text109.grid(column=0,row=4) self.Text110=tk.Label(text=self.testcount02,font=("",20), anchor='w') self.Text110.grid(column=0,row=5) #ボタン Button001=tk.Button(text="Start",font=("",20),command=self.on_start) # Button001.grid(column=0,row=10) Button001.place(x=50,y=800) Button002=tk.Button(text="Stop",font=("",20),command=self.on_stop) # Button002.grid(column=1,row=10) Button002.place(x=150,y=800) Button003=tk.Button(text="Reset",font=("",20),command=self.on_reset) # Button002.grid(column=2,row=10) Button003.place(x=250,y=800) Button004=tk.Button(text="Quit",font=("",20),command=self.on_quit) # Button003.grid(column=3,row=10) Button004.place(x=350,y=800) def run(self): global h self.stop_fg=False elapsed_time = 0 elapsed_timemax = 0 elapsed_timeave = 0 sectimer01 = 0 avg1_list=[] avg1_cnt=0 avg1 = 0 logtime1 = 1000.0 # msec while self.stop_fg!=True: start = time.time() time.sleep(0.15) #150msec wait #ここに計測処理が入ります。 #処理時間の計測 elapsed_time = (time.time() - start) * 1000 if elapsed_time > elapsed_timemax : elapsed_timemax = elapsed_time avg1_list.append(elapsed_time) avg1_cnt = avg1_cnt + 1 if avg1_cnt > 50 : avg1_cnt = 0 avg1 = sum(avg1_list) / len(avg1_list) avg1_list = [] sectimer01 = sectimer01 + elapsed_time #10秒毎の処理 if sectimer01 > logtime1 : ax1.cla() h,=ax1.plot(x1,y2,'red') fig.savefig("test_figure2.png") img = Image.open('test_figure2.png') img = ImageTk.PhotoImage(img) canvas.itemconfig(img2,image=img) # canvas.show() sectimer01 = 0 now = datetime.datetime.now() recordtime = '{0:%Y%m%d}'.format(now) recordtime = recordtime + "," + '{0:%H%M%S}'.format(now) #コンソールに測定値を表示 # print("recordtime = %s" % recordtime) data = 123456 data = recordtime + "," + str(data) # data = data.split(',') print("%s" % data) # print(type(data)) #日付のファイル名のCSVに書き込み f = open('{0:%Y%m%d}'.format(now) + ".csv" , 'a') f.write(data+"\n") f.close() self.laptime= '   処理時間(単独) ' + "{:6.2f}".format(elapsed_time)+'ミリ秒' self.Text108["text"]= self.laptime self.laptime2= '   処理時間(最大) ' + "{:6.2f}".format(elapsed_timemax)+'ミリ秒' self.Text109["text"]= self.laptime2 self.laptime3= '処理時間(50回平均) ' + "{:6.2f}".format(avg1)+'ミリ秒' self.Text110["text"]= self.laptime3 def on_start(self): if self.stop_fg!=True: return else: threading.Thread(target=self.run).start() def on_stop(self): self.stop_fg=True def on_reset(self): self.on_stop() self.testcount01=0 def on_quit(self): #終了処理 raise SystemExit root=tk.Tk() root.title("Measurement Value") root.geometry("1600x900+50+50") app=Application(master=root) app.mainloop()

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

いい方法がありますでしょうか

FigureCanvasTkAggを使うです。

・・・が、これだけだと何の解決にもならないと思うので

解決へ向けて、エラーの内容と、
問題が再現できる最小のコードを作成できますか。

省略部分のデータ所得の部分などは乱数に置き換えても良いので
エラーが再現出来るものが望ましいです。

また、未使用の外部ライブラリも動作に影響がなければコメントアウトで。
コードを実行してみるにあたり、環境を整えやすい方が良いです。


2回目の書換がうまく行かずに

FigureCanvasTkAggを用いて (解説は下)

イメージ説明

python

1import time 2import datetime 3import tkinter as tk 4import tkinter.font as font 5import threading 6#import RPi.GPIO as GPIO 7#import spidev 8import matplotlib.pyplot as plt 9import numpy as np 10from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk 11from matplotlib.figure import Figure 12import csv 13import pprint 14import sys 15import os 16from PIL import Image, ImageTk 17 18fontsize1 = 40 19 20class Application(tk.Frame): 21 def __init__(self, master=None): 22 super().__init__(master) 23 self.stop_fg=True 24# self.stop_fg=True 25 self.locate=" 0.000" # 26 self.laptime=" 0.000000000" # Process time measure 27 self.laptime2=" 0.000000000" # Process time measure 28 self.laptime3=" 0.000000000" # Process time measure 29 self.testcount01=0 # temp counter01 30 self.testcount02=0 # temp counter02 31 self.temperature01A=" 0.00" # temperature01 32 self.temperature01B=" 0.00" # temperature02 33 self.temperature02A=" 0.00" # temperature01 34 self.temperature02B=" 0.00" # temperature02 35 self.adconv01=" 0.000" # ADconverterA01 36 self.adconv02=" 0.000" # ADconverterA02 37 self.strain01=" 0.000" # Starin converter01 38 self.strain02=" 0.000" # Strain converter02 39 self.hosei_fg = False 40 self.GUI() 41 42 # 動画キャプチャの為 43 # self.on_start() 44 45 def GUI(self): 46 self.Text001=tk.Label(text=self.locate,font=("",fontsize1), anchor='w') 47 self.Text001.grid(column=0,row=0) 48# 49 Text001=tk.Label(text=" mm (位置",font=("",fontsize1)) 50 Text001.grid(column=1,row=0) 51 52 self.Text002=tk.Label(text=self.temperature01A,font=("",fontsize1),fg ='green', anchor='w') 53 self.Text002.grid(column=0,row=1) 54 55 Text002=tk.Label(text="℃ (1",font=("",fontsize1),fg ='green') 56 Text002.grid(column=1,row=1) 57 58 self.Text004=tk.Label(text=self.temperature02A,font=("",fontsize1),fg ='darkorange', anchor='w') 59 self.Text004.grid(column=0,row=2) 60 61 Text004=tk.Label(text="℃ (2",font=("",fontsize1),fg ='darkorange') 62 Text004.grid(column=1,row=2) 63 64 self.Text006=tk.Label(text=self.adconv01,font=("",fontsize1), anchor='w') 65 self.Text006.grid(column=10,row=0) 66 67 Text006=tk.Label(text=" Volt (1 ",font=("",fontsize1)) 68 Text006.grid(column=11,row=0) 69 70 self.Text007=tk.Label(text=self.adconv02,font=("",fontsize1),fg ='green', anchor='w') 71 self.Text007.grid(column=10,row=1) 72 73 Text007=tk.Label(text=" Volt (2",font=("",fontsize1),fg ='green') 74 Text007.grid(column=11,row=1) 75 76 self.Text008=tk.Label(text=self.strain01,font=("",fontsize1),fg ='darkorange', anchor='w') 77 self.Text008.grid(column=10,row=2) 78 79 Text008=tk.Label(text=" e (G1 ",font=("",fontsize1),fg ='darkorange') 80 Text008.grid(column=11,row=2) 81 82 self.Text009=tk.Label(text=self.strain02,font=("",fontsize1), anchor='w') 83 self.Text009.grid(column=10,row=3) 84 85 Text009=tk.Label(text=" e (G2 ",font=("",fontsize1)) 86 Text009.grid(column=11,row=3) 87 88#グラフ描画テスト 89 global x1,y1,y2,fig,ax1,canvas,h,img,img2 90 91 x1 = np.linspace(0.0, 5.0) 92 y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) 93 y2 = np.sin(2 * np.pi * x1) * np.exp(-x1) 94 95 fig = plt.figure(figsize=(14, 5)) 96 ax1 = fig.add_subplot(111) 97# ax1.plot(x1,y1,'green') 98 h,=ax1.plot(x1,y1,'green') 99 100 canvas = FigureCanvasTkAgg(fig, master=root) # Generate canvas instance, Embedding fig in root 101 canvas.draw() 102 canvas.get_tk_widget().place(x=50,y=300) 103 104#laptime 表示 105 self.Text108=tk.Label(text=self.laptime,font=("",20), anchor='w') 106 self.Text108.grid(column=0,row=3) 107 108 self.Text109=tk.Label(text=self.testcount01,font=("",20), anchor='w') 109 self.Text109.grid(column=0,row=4) 110 111 self.Text110=tk.Label(text=self.testcount02,font=("",20), anchor='w') 112 self.Text110.grid(column=0,row=5) 113 114#ボタン 115 Button001=tk.Button(text="Start",font=("",20),command=self.on_start) 116# Button001.grid(column=0,row=10) 117 Button001.place(x=50,y=800) 118 Button002=tk.Button(text="Stop",font=("",20),command=self.on_stop) 119# Button002.grid(column=1,row=10) 120 Button002.place(x=150,y=800) 121 Button003=tk.Button(text="Reset",font=("",20),command=self.on_reset) 122# Button002.grid(column=2,row=10) 123 Button003.place(x=250,y=800) 124 Button004=tk.Button(text="Quit",font=("",20),command=self.on_quit) 125# Button003.grid(column=3,row=10) 126 Button004.place(x=350,y=800) 127 128 def run(self): 129 global h 130 self.stop_fg=False 131 elapsed_time = 0 132 elapsed_timemax = 0 133 elapsed_timeave = 0 134 sectimer01 = 0 135 avg1_list=[] 136 avg1_cnt=0 137 avg1 = 0 138 logtime1 = 1000.0 # msec 139 140 while self.stop_fg!=True: 141 142 start = time.time() 143 time.sleep(0.15) #150msec wait 144 145 #ここに計測処理が入ります。 146 147#処理時間の計測 148 elapsed_time = (time.time() - start) * 1000 149 if elapsed_time > elapsed_timemax : 150 elapsed_timemax = elapsed_time 151 avg1_list.append(elapsed_time) 152 avg1_cnt = avg1_cnt + 1 153 if avg1_cnt > 50 : 154 avg1_cnt = 0 155 avg1 = sum(avg1_list) / len(avg1_list) 156 avg1_list = [] 157 158 sectimer01 = sectimer01 + elapsed_time 159 160#10秒毎の処理 161 if sectimer01 > logtime1 : 162 ax1.cla() 163 h,=ax1.plot(x1,y2,'red') 164 165 ## メインスレッド側で呼ぶ 166 root.after(10, canvas.draw) 167 168 sectimer01 = 0 169 now = datetime.datetime.now() 170 recordtime = '{0:%Y%m%d}'.format(now) 171 recordtime = recordtime + "," + '{0:%H%M%S}'.format(now) 172#コンソールに測定値を表示 173# print("recordtime = %s" % recordtime) 174 data = 123456 175 data = recordtime + "," + str(data) 176 print("%s" % data) 177 178 self.laptime= '   処理時間(単独) ' + "{:6.2f}".format(elapsed_time)+'ミリ秒' 179 self.Text108["text"]= self.laptime 180 self.laptime2= '   処理時間(最大) ' + "{:6.2f}".format(elapsed_timemax)+'ミリ秒' 181 self.Text109["text"]= self.laptime2 182 self.laptime3= '処理時間(50回平均) ' + "{:6.2f}".format(avg1)+'ミリ秒' 183 self.Text110["text"]= self.laptime3 184 185 def on_start(self): 186 if self.stop_fg!=True: 187 return 188 else: 189 threading.Thread(target=self.run, daemon=True).start() 190 191 def on_stop(self): 192 self.stop_fg=True 193 194 def on_reset(self): 195 self.on_stop() 196 self.testcount01=0 197 198 def on_quit(self): 199#終了処理 200 raise SystemExit 201 202root=tk.Tk() 203root.title("Measurement Value") 204root.geometry("1600x900+50+50") 205app=Application(master=root) 206 207app.mainloop()

要点は一か所のみ

## メインスレッド側で呼ぶ root.after(10, canvas.draw)

tkinerに限らず、mainloopを実行してる以外のスレッドから
データ更新以外のGUI操作をするとうまくいきません。
(スレッドセーフな操作ではない為)

スレッドを使ったタイマー処理は tkinter では
after()で呼び出す方法がよく用いられますが、
今回は最小限の変更で済むように、canvas.drawのみを
mainloop側(メインスレッド)で呼んでもらうように修正。

エラー内容がないので確定ではありませんが、
元コードは canvas.show() でコメントアウトしていた箇所、
恐らくここで詰まってたのではないかなと予想です。


他の変更点: (問題には影響なし、コードを掲載するにあたり変更した箇所)

  • 起動時の on_start() 録画の為にコメントアウト。
  • threading.Thread(target=self.run, daemon=True).start()

daemon=メインスレッド終了時にスレッドも終了。不要であれば削ってください。

  • 注意: csv出力や画像ファイル出力など、

デバッグで何度も実行する時に不要だった部分はざっくり削ってあります。

投稿2020/04/24 19:00

編集2020/04/24 19:44
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TomoWa

2020/04/25 00:31

ご指摘の通り、canvas.draw()で詰まっていました。エラー表示が ↓ここから Backend terminated or disconnected.Fatal Python error: Segmentation fault Current thread 0xb229d460 (most recent call first): File "/usr/lib/python3/dist-packages/matplotlib/backends/_backend_tk.py", line 91 in blit File "/usr/lib/python3/dist-packages/matplotlib/backends/backend_tkagg.py", line 10 in draw File "/home/pi/Documents/wada_python01/testgraph02T.py", line 174 in run File "/usr/lib/python3.7/threading.py", line 865 in run File "/usr/lib/python3.7/threading.py", line 917 in _bootstrap_inner File "/usr/lib/python3.7/threading.py", line 885 in _bootstrap Thread 0xb6f91ad0 (most recent call first): File "/usr/lib/python3.7/tkinter/__init__.py", line 1283 in mainloop File "/home/pi/Documents/wada_python01/testgraph02T.py", line 224 in <module> File "/usr/lib/python3/dist-packages/thonny/backend.py", line 1272 in _execute_prepared_user_code File "/usr/lib/python3/dist-packages/thonny/backend.py", line 1200 in wrapper File "/usr/lib/python3/dist-packages/thonny/backend.py", line 1213 in wrapper File "/usr/lib/python3/dist-packages/thonny/backend.py", line 1259 in execute_source File "/usr/lib/python3/dist-packages/thonny/backend.py", line 815 in _execute_source File "/usr/lib/python3/dist-packages/thonny/backend.py", line 801 in _execute_file File "/usr/lib/python3/dist-packages/thonny/backend.py", line 403 in _cmd_Run File "/usr/lib/python3/dist-packages/thonny/backend.py", line 204 in handle_command File "/usr/lib/python3/dist-packages/thonny/backend.py", line 146 in mainloop File "/usr/lib/python3/dist-packages/thonny/backend_launcher.py", line 87 in <module> Use 'Stop/Restart' to restart. ↑ここまで といった感じでWEBで調べても具体例がなく解決方法がわかりませんでした。 FigureCanvasTkAggを使ってグラフの更新ができるようになりました。 本当にありがとうございました、感謝です。 まだまだ学習が足りていないですね、もっと勉強したいと思います。
teamikl

2020/04/25 02:38

確かにこのエラー表示は原因の特定が難しいですね。 これはマルチスレッド + GUI ライブラリでの共通する問題なので、 他にもメイン以外のスレッドから直接GUIの操作をする場合は、 同様のエラーになる可能性があるので注意です。 一点だけ訂正。待ち時間は特に指定する必要がないので、root.after_idle(canvas.draw) の方が適切でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問