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

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

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

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

Tkinter

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

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

Python

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

Q&A

2回答

2058閲覧

YOUTUBEの配信の視聴中の人数をリアルタイムでグラフにして表示したい

Winter_1214

総合スコア11

Matplotlib

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

Tkinter

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

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

Python

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

0グッド

0クリップ

投稿2021/06/06 08:00

編集2022/01/12 10:55

実現したいこと

YOUTUBEの配信の視聴中の人数をグラフにして表示したいが、更新されずに同じグラフしか表示されない。
5秒おきに視聴中の人数を取得して、折れ線グラフをリアルタイムでTkinterに表示させたい。
グラフの表示とデーの取得はできたが、Tkinterへの出力がうまいことできない。

発生している問題

エラーは出ないが、グラフが更新されない。

ソースコード

python

1# -*- coding: utf-8 -*- 2import time 3import datetime 4import requests 5import json 6import matplotlib.pyplot as plt 7import numpy as np 8from apiclient.discovery import build 9 10import tkinter as tk 11import matplotlib.pyplot as plt 12from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk) 13 14 15YT_API_KEY = 'your youtube api key' 16youtube = build('youtube', 'v3', developerKey=YT_API_KEY) 17 18root = tk.Tk() 19root.title("graph????") 20root.geometry("1400x800") 21 22dt_now = datetime.datetime.now() 23now = str(dt_now.hour) + ":" + str(dt_now.minute) + ":" + str(dt_now.second) 24nowma = str(dt_now.hour) + ":" + str(dt_now.minute) + ":" + str(dt_now.second - 10) 25nowmae = str(dt_now.hour) + ":" + str(dt_now.minute) + ":" + str(dt_now.second - 5) 26 27 28def get_video_id(yt_url): 29 video_id = yt_url.replace('https://www.youtube.com/watch?v=', '') 30 print('video_id : ', video_id) 31 32 return video_id 33 34videos = [] 35yt_url = input('Input YouTube URL > ') 36Liveurl.append(yt_url) 37video_id = get_video_id(yt_url) 38video_response = youtube.videos().list( 39 part = 'snippet,liveStreamingDetails', 40 id = video_id 41).execute() 42 43for video_result in video_response.get("items", []): 44 if video_result["kind"] == "youtube#video": 45 videos.append([video_result["snippet"]["title"],video_result["liveStreamingDetails"]["concurrentViewers"]]) 46 47dataX = [nowma,nowmae] 48dataY = ['0','2'] 49def update(): 50 global dataY 51 for channel in videos: 52 print(channel) 53 print(dataX) 54 print(dataY) 55 fig = plt.figure() 56 plt.cla() 57 dataX.append(now) 58 dataY.append(str(channel[1])) 59 dataY = sorted(dataY) 60 plt.plot(dataX, dataY); 61 fig.savefig("img.png") 62 canvas = FigureCanvasTkAgg(fig, master=root) 63 canvas.draw() 64 root.after(5000, update) 65 66fig = plt.figure() 67plt.title("グラフ",fontname="MS Gothic") 68plt.xlabel("時間", fontname="MS Gothic") 69plt.ylabel("視聴中数", fontname="MS Gothic") 70dataY = sorted(dataY) 71plt.tight_layout() 72 73plt.plot(dataX, dataY); 74fig.savefig("img.png") 75 76canvas = FigureCanvasTkAgg(fig, master=root) 77canvas.draw() 78canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) 79 80toolbar = NavigationToolbar2Tk(canvas, root) 81toolbar.update() 82canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) 83 84root.after(5000, update) 85root.mainloop()

使用サイト

matplotlibまとめ
tkinterのウインド上にグラフを表示する
youtubeapi

###追加ソース

python

1dataX = [nowma,nowmae,nowmae] 2dataY = ['0','2','2'] 3def main(): 4 global dataY 5 fig = plt.figure() 6 plt.title("グラフ",fontname="MS Gothic") 7 plt.xlabel("時間", fontname="MS Gothic") 8 plt.ylabel("視聴中数", fontname="MS Gothic") 9 dataY = sorted(dataY) 10 plt.tight_layout() 11 12 plt.plot(dataX, dataY); 13 fig.savefig("img.png") 14 canvas = FigureCanvasTkAgg(fig, master=root) 15 16 canvas = FigureCanvasTkAgg(fig, master=root) 17 canvas.draw() 18 toolbar = NavigationToolbar2Tk(canvas, root) 19 toolbar.update() 20 canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) 21 22 canvas.flush_events() 23 root.after_idle(5000, get_data) 24 25def get_data(): 26 time.sleep(5) 27 for channel in videos: 28 print(channel) 29 dataX.append(now) 30 dataY.append(str(channel[1])) 31 root.after_idle(5000, get_data) 32 33 34main() 35root.mainloop()

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

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

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

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

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

guest

回答2

0

python

1 2def update(): 3 for channel in videos: 4 ... 5 6 canvas = FigureCanvasTkAgg(fig, master=root) 7 ... 8 9 root.after(5000, update)

問題点:

  • タイマーで update が呼ばれますが、videos は更新されてません。
  • タイマー内での FigureCanvasTkAgg 生成

 新規生成はせずに、既存のキャンバスに対して、データのみ変更し、再描画するようにします。

  • root.after のインデント 「forループ内」で呼び出されてるので、videos の回数だけ重複します。

 まずは、update() が正常に5秒毎に呼ばれているかどうかを確認しましょう。

解決策:

  • youtube 空のデータ所得 (HTTPリクエスト) は、

 メインスレッドで処理すると、GUIの反応を一時的に止める事になるので、
別スレッドで 5 秒間隔で行うようにします。

  • 別スレッド → メインスレッドへは queue や root.after_idle で

 プロットに必要なデータを送ります

  • メインスレッド側で、プロットに描画するデータを更新・再描画します。

注意点1: tkinter ではライブラリ内部でもtcl/tk とスレッド間通信をしてる為、
pythonの別スレッド側でプロットするデータ更新をしても、エラー無く通りますが、
問題が起きた時のデバッグが困難になる為、(タイミング次第で起こる問題だと、問題の再現が難しい)
データの所得と更新を明示的に分離した、スレッドセーフな設計にする事をお勧めします。

注意点2: matplotlib のアニメーションでは FuncAnimation を使う例がありますが、
tkinter 等に組み込む際、イベントループが異なる場合は、機能しません。
FuncAnimationのタイマーを稼働させるためには、backend の設定が必要になります。

投稿2021/06/06 09:26

teamikl

総合スコア8664

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

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

Winter_1214

2021/06/06 13:44

```py dataX = [nowma,nowmae,nowmae] dataY = ['0','2','2'] def main(): global dataY fig = plt.figure() plt.title("グラフ",fontname="MS Gothic") plt.xlabel("時間", fontname="MS Gothic") plt.ylabel("視聴中数", fontname="MS Gothic") dataY = sorted(dataY) plt.tight_layout() plt.plot(dataX, dataY); fig.savefig("img.png") canvas = FigureCanvasTkAgg(fig, master=root) canvas = FigureCanvasTkAgg(fig, master=root) canvas.draw() toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) canvas.flush_events() root.after_idle(5000, get_data) def get_data(): time.sleep(5) for channel in videos: print(channel) dataX.append(now) dataY.append(str(channel[1])) root.after_idle(5000, get_data) return dataX,dataY main() root.mainloop() ``` ###エラー 'int' object has no attribute '__name__' ###解決策 teamikiさんに言われた通りであっているのかわからないのですが、 私側がわかってないのが悪いんですが..... ここをこうっていうのがあれば教えていただけると嬉しいです。
teamikl

2021/06/06 13:55

インデントが解らないので、質問のコード変更でお願いします。 - FigureCanvasTkAgg が複数ある → 初期化時一回のみにする。 - time.sleep は イベントループ内ではつかわないように。→ GUIが5秒間フリーズします  使うとすれば、別スレッドで。 - flush_events() は、matplotlib.plot のイベントループを呼び出します  バックエンド次第なので、出来れば使わないで実装した方が良いです。  (FuncAnimation を動かしたい場合は使うかもしれませんが、現状は使ってないようなので) 段階を踏んで実装していった方が良さそうですね。 - アニメーションの実装 (タイマー root.after を使います ) - データのリアルタイム所得(別スレッドで定期的にHTTPリクエスト)  こちらは、time.sleep(5) でも大丈夫。
Winter_1214

2021/06/06 18:55

段階を踏んで一個ずつ一回してきます。 わからなければ再度よろしくお願いいたします。
teamikl

2021/06/09 03:21 編集

もう一点気になった部分は、 「tkinter への埋め込みの場合」と、「matplotlib 単体で使う場合」のコードが 混在しているように見受けられます。 - time.sleep と root.after の混在 - flush_events 混在させること自体は可能なのですが、 内部の仕組みが競合しないように、使い方に配慮しなければなりません。 サンプルコード等を参考にする際に注意です。 前のコメントの補足で、「段階を踏んで~」というのは、明確な理由があって、 アニメーションの例は、tkinter 組み込みの場合には、 直接参考に出来ないものがあるからです。→ flush_events() - tkinter 内に組み込みである必要があるか  matplotlib 単独でもいいなら tkinter は一旦切り離して考える - matplotlib の FuncAnimation を使うかどうか  → matplotlib アニメーションのサンプルコードの多くで使われてます  tkinter 内組み込みで使う場合は、backend 次第で工夫が必要になるので  ここも tkinter は切り離して考えた方が、  参考に出来るサンプルコードの幅が広がります。 - 「tkinterに組み込みで(※ イベントループの使い方)」 - 「リアルタイムデータを所得し(スレッドの使い方)」 - 「イベントループに送り(キューを用いたスレッド間通信)」 - 「グラフをアニメーション描画する(タイマーの使い方)」 それぞれが、ある程度分量のある話題なので、ここで説明するのは難しいのですが、 自分も同じ様なプログラムを作ることになったので、もう少し情報・サンプル等共有できます。 ---- 追加分のget_data問題点ですが、 一部を修正して解消するような問題ではないので、ここも 小さなプログラムを作ってみて挙動を確認するのをオススメします。 - time.sleep(5) ... イベントループ内でスリープしてはいけない (GUIがフリーズします) - for channel in videos: ... videos は更新されていない - データ更新がグラフに反映されていない  プロットに対してデータ更新の通知が必要になるはずです。⇛set_data 確認方法 - print 等で、まずはその関数が呼ばれているかを確認する - 変数の中身が期待通りであることを表示して確認する - 期待どおりでない場合: 呼び出し元を辿り、原因を探す ---- metplotlib のアニメーションのサンプルコードの紹介 https://matplotlib.org/stable/gallery/animation/strip_chart.html#sphx-glr-gallery-animation-strip-chart-py tkinter 組み込み「ではない」例ですが、 emitterが乱数を返すジェネレーターとして実装してます。 追記: こちらの方がサンプルとしてはより単純そうでした。 描画するデータをジェネレータとして実装してる点は同じです https://matplotlib.org/stable/gallery/animation/animate_decay.html#sphx-glr-gallery-animation-animate-decay-py STEP 1: これを応用して、emitter 内で視聴者数を所得し、 interval を 5000ms (5秒) とすると、 目的のリアルタイムプロットが得られます。 STEP 2: tkinter 組み込みにする場合、 キャンバスへの組み込み等は出来ているようなので FuncAnimation が動くかを確認 (backend 設定が影響します) 動かない場合、tkinter のタイマーで 5000ms 間隔で実行する。 STEP 3: youtube data api からデータを所得する間、 恐らく通常の運用では 一瞬ですがGUI が応答しなくなります。 ネットワークに障害がでた場合は、長時間GUIが応答なしになります。 この問題を解決したい場合に、スレッドの導入を検討して下さい。
guest

0

おはようございます。

問題文読ませていただきました。

更新されずに同じグラフしか表示されない

こちらはafter関数にて5秒ごとにupdate関数を呼ぶ際に、apiのレスポンス自体の更新も行っていないため、同じグラフしか表示されていないように感じております。

また5秒間隔でAPIを叩くことで、リクエスト制限にかからないのかなと思っております。

ご確認のほど、よろしくお願いいたします。????‍♂️

投稿2021/06/06 22:56

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問