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

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

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

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Matplotlib

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

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

2166閲覧

tkinterを用いて、pyaudioで取り込んだリアルタイムの波形を表示したい

chanpoo

総合スコア3

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Matplotlib

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

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/08/12 17:47

編集2020/08/13 15:18

前提・実現したいこと

tkinterを用いて、pyaudioで取り込んだリアルタイムの波形を表示したい。

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

真っ白なキャンバスが表示されるだけで、波形表示ができない。

該当のソースコード

python

1import tkinter as tk 2import tkinter.ttk as ttk 3import pyaudio 4import matplotlib.pyplot as plt 5import numpy as np 6from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 7from matplotlib.animation import FuncAnimation 8 9def click(): 10 P = pyaudio.PyAudio() 11 stream = P.open(format=pyaudio.paInt16, channels=1, rate=44100, frames_per_buffer=8820, input=True, output=False) 12 ani = FuncAnimation(fig,update) 13 14def update(Z): 15 input = stream.read(8820, exception_on_overflow=False) 16 ndarray = np.frombuffer(input, dtype='int16') 17 ax.cla() 18 ax.plot(ndarray) 19 frame.after(200) 20 21root = tk.Tk() 22root.title("abc") 23root.geometry("800x600") ##### guiの用意 24 25frame = tk.Frame(root) ##### frameの用意 26 27fig = plt.figure() 28ax = fig.add_subplot(1,1,1) 29 30canvas = FigureCanvasTkAgg(fig, master=frame) ##### frameにcanvasを置く 31canvas.draw() ##### canvasを書く? 32 33canvas.get_tk_widget().pack() ##### canvasを配置 34frame.grid(row=0, column=0, columnspan=10, rowspan=5, padx=10, pady=10) ##### frameを配置 35 36button = tk.Button(root, text='Start', command=click) 37 38button.grid(row=6, column=11, columnspan=1, rowspan=1, padx=10, pady=10) 39 40root.mainloop()

試したこと

threadingにて他の関数の場合問題なく起動することを確認

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

python3

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

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

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

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

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

guest

回答3

0

stop ボタンを押せない問題の解消

主な変更点は、after の使い方

問題点: update 関数内でループしていると、
mainloop に処理が戻らず他の操作が効かない状態です。

  • タイマー(after)を使って、tkinter 側から

 オーディオ読み出し処理を(gui処理の合間に)呼んで貰う。

  • stopボタンの変数名と stop 関数が被っていたので、

 ボタンの変数名を変更

  • start/stop をリソースの所得と解放と対になる処理に。

python

1import pyaudio 2import tkinter as tk 3import matplotlib.pyplot as plt 4import numpy as np 5from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 6from matplotlib.animation import FuncAnimation 7import threading 8 9P = None 10stream = None 11 12def start(): 13 global P, stream 14 P = pyaudio.PyAudio() 15 stream = P.open(format=pyaudio.paInt16, channels=1, rate=44100, frames_per_buffer=8820, input=True, output=False) 16 frame.after_idle(update) 17 18def stop(): 19 global P, stream 20 if stream: 21 stream.stop_stream() 22 stream.close() 23 if P: 24 P.terminate() 25 P = stream = None 26 27 28def update(): 29 if stream and stream.is_active(): 30 input = stream.read(8820, exception_on_overflow=False) 31 ndarray = np.frombuffer(input, dtype='int16') 32 ax.cla() 33 ax.plot(ndarray) 34 canvas.draw() 35 frame.after(200, update) 36 37 38root = tk.Tk() 39root.title("abc") 40root.geometry("800x700") ##### guiの用意 41 42frame = tk.Frame(root) ##### frameの用意 43 44fig = plt.figure() 45ax = fig.add_subplot(1,1,1) 46 47canvas = FigureCanvasTkAgg(fig, master=frame) ##### frameにcanvasを置く 48canvas.draw() ##### canvasを書く? 49 50canvas.get_tk_widget().pack() ##### canvasを配置 51frame.grid(row=0, column=0, columnspan=10, rowspan=5, padx=10, pady=10) ##### frameを配置 52 53startButton = tk.Button(root, text='Start', command=start) 54startButton.grid(row=6, column=10, columnspan=1, rowspan=1, padx=10, pady=10) 55 56stopButton = tk.Button(root, text='Stop', command=stop) 57stopButton.grid(row=7, column=10, columnspan=1, rowspan=1, padx=10, pady=10) 58 59root.mainloop() 60stop()

投稿2020/08/13 14:48

teamikl

総合スコア8664

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

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

0

いろいろと問題はあるが、ひとまずグラフの描画までができるプログラムを載せておきます。

python

1import pyaudio 2import tkinter as tk 3import matplotlib.pyplot as plt 4import numpy as np 5from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 6from matplotlib.animation import FuncAnimation 7import threading 8 9def start(): 10 while stream.is_active(): 11 input = stream.read(8820, exception_on_overflow=False) 12 ndarray = np.frombuffer(input, dtype='int16') 13 ax.cla() 14 ax.plot(ndarray) 15 canvas.draw() 16 frame.after(200) 17 18def stop(): 19 stream.stop_stream() 20 stream.close() 21 P.terminate() 22 23root = tk.Tk() 24root.title("abc") 25root.geometry("800x700") ##### guiの用意 26 27frame = tk.Frame(root) ##### frameの用意 28 29fig = plt.figure() 30ax = fig.add_subplot(1,1,1) 31 32canvas = FigureCanvasTkAgg(fig, master=frame) ##### frameにcanvasを置く 33canvas.draw() ##### canvasを書く? 34 35canvas.get_tk_widget().pack() ##### canvasを配置 36frame.grid(row=0, column=0, columnspan=10, rowspan=5, padx=10, pady=10) ##### frameを配置 37 38start = tk.Button(root, text='Start', command=start) 39start.grid(row=6, column=10, columnspan=1, rowspan=1, padx=10, pady=10) 40 41stop = tk.Button(root, text='Stop', command=stop) 42stop.grid(row=7, column=10, columnspan=1, rowspan=1, padx=10, pady=10) 43 44P = pyaudio.PyAudio() 45stream = P.open(format=pyaudio.paInt16, channels=1, rate=44100, frames_per_buffer=8820, input=True, output=False) 46 47root.mainloop() 48

投稿2020/08/13 14:03

chanpoo

総合スコア3

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

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

teamikl

2020/08/13 14:35

こちらをベースにした方が良さそうですね。 time.sleep については、恐らくノンブロッキングモードでの オーディオデータの読み出しを参考にされたのだと思います、 今回は取り合えずブロッキングモードなので sleep 相当の事は不要です。 https://people.csail.mit.edu/hubert/pyaudio/docs/ while stream.is_active()~sleep は、 オーディオを読み出している間、 プログラムが終了しないように待機してるだけです。 gui のプログラムでは guiのイベントループがこれを担当します。 通常、ウィンドウが閉じられるまではプログラムは終了しません。
chanpoo

2020/08/13 14:44

こちらをベースに書き換えてみます。 frame.after(200)ですが、canvas.draw()だけだと、canvasが白いままで グラフの表示がされないため、plt.pause()と同様な意味で使用しているのですが、 なにか他にcanvasを表示する方法がありますでしょうか。
teamikl

2020/08/13 14:58

ソースコードを投稿したので別の回答になりましたが、 after の使い方について書いたので、参考にして下さい。 キャンバスの表示については、 描画はデータを設定した時ではなくて、 関数が終わって mainloopへ処理が戻った時に描画の更新が行われます。 この場合、start関数はループを持っていて終了しない為、描画は行われません。 一応、キャンバスのupdate()を呼び出す事でも、この場合 canvas.get_tk_widget().update() で描画を更新できますが、 ループは使わず、タイマーを使う方法が推奨です。
chanpoo

2020/08/13 15:14

ありがとうございます。 frame.after_idle(update) でmainloopに戻り、updateを呼び出し、 frame.after(200, update) で200msごとにupdateを呼び出しているので、 roopができているという認識で大丈夫でしょうか。 updateは処理している際でも、startやstopが操作可能になるということは、 updateは並列処理のようになっているのでしょうか。 何度もすみません。お時間ございましたらよろしくお願いします。
teamikl

2020/08/13 15:35

最初の認識は、合ってます。その通り。 after_idle や after はコードの実行を止めずに、 mainloop 側から呼び出してもらうように予約します。 「並列処理」については、 恐らく言いたいことのニュアンスは解るのですが、 ここは違います。 一連の処理は 単一のスレッド上で動作します mainloop内のループから -> start() -> mainloopに戻る -> 他のイベント と「順番に」実行されます。タイマーへ登録した処理は見かけ上、 バックグラウンドで動作してるみたいに感じられるのだと思いますが、 これらの処理は直列です。 なので、start() 内で ループがあったり time.sleep() したりすと 処理が mainloop に戻らなくなり、結果他の gui のイベントが処理されず ウィンドウが固まります(stopボタンを押せない状態がこれに該当)
chanpoo

2020/08/13 15:43

直列処理だったんですね・・・。ようやく理解できました。 updateの処理中は、すでに、mainloopに戻っているので、 stopを受け付けることができるという感じなのですね。 いろいろと勉強になりました。
guest

0

ベストアンサー

ソースコードはマークダウンを使って整形をお願いします。
今回は推測可能な範囲ではありますが、インデント情報が失われてしまいます。


問題点: 幾つかあります

  • tkinterのレイアウト問題

Frame は生成されたものの、表示されれない状態なので、
配置用のメソッド(pack/grid/placeの何れか)を呼んでみてください。

frame.pack(fill=tk.BOTH, expand=True)

  • 試してないので気になる点ですが、PyAudio の stream

PyAudio の stream を mainloop 前に閉じてますが、
継続して描画するなら、streamを維持する必要はないのでしょうか?(未テスト)

  • FuncAnimation の 使い方

figure オブジェクトは plot メソッドを持ってません。

投稿2020/08/13 00:19

teamikl

総合スコア8664

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

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

chanpoo

2020/08/13 02:21

ご回答ありがとうございます。 ソースコード、整形いたしました。 ご教授いただいたように修正したのですが、あまりうまくいっておりません。 やりたいこととしては、上のgifをしたのcanvasに描画したいです。 figを更新する際は、frame、canvas共にunpackする必要があるのでしょうか。 よろしくお願いします。
teamikl

2020/08/13 04:02 編集

余分なコードが増えてませんか? tkinter に表示したい場合は、 plt.show() 等は tkinter のイベントループと競合する為使えません。 FigureCanvasTkAgg を使うサンプルを参考にして下さい。
chanpoo

2020/08/13 04:30

試行錯誤しているうちに混在しておりました。 ありがとうございます。 少し背伸びしているようなので、guiはまたの機会にしてみます。
teamikl

2020/08/13 13:25 編集

gif ファイルがもし動画gifだとすると、(訂正 git -> gif) tkinter ではアニメーション処理もタイマーを用いて自分で行う必要があります。 (teratail 内で以前回答した事があるので、サンプルコードは見つかると思います) 今提示されているコードは複数の問題が混在してるので、 まずは最初のコードをベースにして、 tkinter 上でのアニメーションを伴わないプロットから試してみましょう。 大元の問題は「Frameウィジェットが配置されていない」ですが、 update() も恐らく期待通りの処理になっていないので、 プロットを反映させるには修正が必要です。 pyaudio の後始末は、mainloop の後に書くと、 windowを閉じた後に処理されます。WM_DELETE_WINDOW も調べて見て下さい。
chanpoo

2020/08/13 12:36

サンプルコードは見つけることができなかったですが、time.sllepを使うという認識で間違いないでしょうか。 アニメーションがない場合は、plotを書き換えるという感じでしょうか。 frame.grid(row=0, column=0, columnspan=10, rowspan=5, padx=10, pady=10) でFrameウィジェットが配置をしているという認識なのですが、間違っていますでしょうか。 stopボタンを押した際に後始末をする予定で、放置しておりました。ご教授ありがとうございます。
teamikl

2020/08/13 13:16

time.sleep は他の処理を停止してしまうので、 tkinter で使うと、sleep してる間 gui が固まってしまいます。 どのように使われるのか把握してませんが、多分違います。 オーディオの読込も同様に、ブロッキングモードで読み込む場合は gui をフリーズさせてしまう可能性があるので、guiと一緒に使う場合は スレッドを使ったり、ノンブロッキングモードで読み込んだりします。 この辺はまだ先になると思いますが。 tkinetr と使う場合、キャンバスの設置は今のコードでok 後は plt.show() の代わりが tkinter の mainloop() になるだけで、 プロット自体は同じです。 ただし、今掲載されてるコードは、 編集された際に他の部分もおかしくなってるので 最初のコードから、機能は一つづつ動作確認しながら追加していった方が良いです。 「ボタンを押したときに開始」したいのだと思いますが、 今の click 関数は期待通りに動いてくれません。恐らく動作確認も出来てないはずです。
teamikl

2020/08/13 13:17

>~でFrameウィジェットが配置をしているという認識なのですが、間違っていますでしょうか grid でも大丈夫です。
chanpoo

2020/08/13 13:39

ご指導いただいたように、アニメーションを伴わないプロットでしたら問題なく動作できました。 しかし、startボタンを押してしまうと、stopを押せなくなってしまいます。 それを回避するために、threadingをいれたのですが、segmentation faultが出てしまいます。 よろしければこちらについてもご教授いただけないでしょうか。codeを貼りなおしております。 アニメーションについては現在修正中です。
teamikl

2020/08/13 13:59 編集

色々とまずい部分が増えていってるので、 (おそらく動作確認せずに書かれたコード、after等、使い方が間違ってます) 取り合えず、追加の機能は別トピックにして、 最初のコードに戻した方が良いです。 スレッドの導入などは、それなりにボリュームのあるトピックなので、 今の時点では気に留めておくくらいにして(TODOに書いておきましょう) >アニメーションを伴わないプロットでしたら問題なく動作できました。 確認ですが、これは plt.show() ではなく tkinter で、ですか?
chanpoo

2020/08/13 14:02

別トピックにさせていただきます。 threadingをいれていない起動するコードは解決策に置いておくほうがよろしいでしょうか。 コードは戻しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問