はじめに
以下の記事からDearPyGuiというライブラリを知り, グラフ描画について興味が湧いたので調べてみました。
複数y軸, 時間軸, リアルタイム描画など簡単にできたので紹介します。
環境
Mac OS
Python 3.10.1
dearpygui 1.3.1
numpy 1.22.1
pip install dearpygui numpy
プロットのデモ
show_implot_demo()
でプロットのデモが見れます(コードは無いですが、、、)
Helpには以下を参照してとありました。
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.create_viewport(title='Plot demo', width=600, height=600)
# demo
dpg.show_implot_demo()
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
こちらにもあります。
こっちはコードを確認できます。
import dearpygui.dearpygui as dpg
import dearpygui.demo as demo
dpg.create_context()
dpg.create_viewport(title='Demo', width=600, height=600)
demo.show_demo()
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
単軸, 複数y軸
これらはドキュメントを見る方が確実かな?
y軸は最大3つまで追加出来るようです。
プロット内のズーム、凡例から表示/非表示などできます。
"""dearpyguiのプロット例 (単軸)
参考URL
https://dearpygui.readthedocs.io/en/latest/documentation/plots.html#plots
"""
import dearpygui.dearpygui as dpg
import numpy as np
# ################# プロットデータ作成 #################
data_len: int = 100
x_data: np.ndarray = np.linspace(-np.pi, np.pi, data_len)
y_data = np.sin(x_data)
# ##################### 描画設定 #####################
dpg.create_context()
dpg.create_viewport(title='Plot view port', width=850, height=550)
dpg.setup_dearpygui()
dpg.show_viewport()
with dpg.window(label='Plot window', width=-1, height=-1):
with dpg.plot(label='Plot', width=800, height=500):
dpg.add_plot_legend() # 凡例追加
# x軸追加
dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis')
# y軸とデータ曲線追加. データ曲線のparent引数は連動させたいy軸のtagを入力
dpg.add_plot_axis(dpg.mvYAxis, label='y', tag='yaxis')
# parent=dpg.last_item() は最後に追加したアイテム
dpg.add_line_series(x_data, y_data, label='sin', parent=dpg.last_item(), tag='line')
# y軸を追加する場合(最大3軸)はこの下に軸とデータ曲線を追加していく
dpg.start_dearpygui()
dpg.destroy_context()
時間軸
`time`引数を`True`にすると時間軸にできます。x軸のデータはunix秒です。
ただしそのままだとUTCの時刻表示になってしまうよう?なので, +9時間して日本時間に調整しています
JST_TZ = 60 * 60 * 9
jst_now = time.time() + JST_TZ
dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis', time=True)
"""dearpyguiの時間軸例
x軸を追加する時, time引数をTrueにして (30行目),
データ曲線のx値にunix秒のリストを渡すと時刻列になる
ただしそのままだとUTCの時刻表示になってしまうよう?なので, +9時間して日本時間に調整している(16, 17行目)
"""
import time
import dearpygui.dearpygui as dpg
import numpy as np
# ################# プロットデータ作成 #################
data_len: int = 100
y_data = np.random.randint(0, 100, data_len)
# ####### 時間軸作成 #######
JST_TZ = 60 * 60 * 9 # 日本時間調整用
jst_now = time.time() + JST_TZ
# numpy配列のままだとうまく表示できなかったのでリストに変換
x_data: list = list(np.linspace(jst_now, jst_now + data_len - 1, data_len))
# ##################### 描画設定 #####################
dpg.create_context()
dpg.create_viewport(title='Plot view port', width=850, height=550)
dpg.setup_dearpygui()
dpg.show_viewport()
with dpg.window(label='Plot window', width=-1, height=-1):
with dpg.plot(label='Time plot', width=800, height=500):
dpg.add_plot_legend() # 凡例追加
# x, y軸追加
dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis', time=True)
dpg.add_plot_axis(dpg.mvYAxis, label='y', tag='yaxis')
# データ線追加, 親は最後に追加したアイテム (=y軸)
dpg.add_line_series(x_data, y_data, label='data', parent=dpg.last_item(), tag='line')
dpg.start_dearpygui()
dpg.destroy_context()
リアルタイム
以下を参考にしています
画面表示のトータル時間から描画間隔を設定しています。
# ################# 時間経過判定用 #################
elapsed_time: float = 0.0
interval: float = 0.05
# 今までdpg.start_dearpygui()だった箇所を変更
while dpg.is_dearpygui_running():
total_time = dpg.get_total_time() # 画面が開いてからのトータル時間 (秒)
# interval 秒経過したらグラフ更新
if total_time - elapsed_time >= interval:
elapsed_time = total_time
plot_callback()
dpg.render_dearpygui_frame()
plot_callback()
関数内でデータをプロットしています。
def plot_callback() -> None:
"""データをプロットする"""
global x_data, y_data
y_data = update_array(y_data) # データ更新用関数
# 第1引数は値を入力したいアイテムのtag (= dpg.add_line_series(tag='line'))
dpg.set_value('line', [x_data, y_data])
"""dearpyguiのリアルタイムプロット例
参考URL
https://dearpygui.readthedocs.io/en/latest/documentation/render-loop.html
https://dearpygui.readthedocs.io/en/latest/documentation/plots.html#updating-series-data
https://github.com/hoffstadt/DearPyGui/issues/303
"""
import dearpygui.dearpygui as dpg
import numpy as np
# ################# プロットデータ作成 #################
data_len: int = 100
x_data: np.ndarray = np.linspace(0, data_len - 1, data_len)
y_data = np.empty(data_len)
y_data[:] = np.nan
# ################# 時間経過判定用 #################
elapsed_time: float = 0.0
interval: float = 0.05
def update_array(data: np.ndarray) -> np.ndarray:
"""np.ndarrayの末尾に新しい値を追加
Parameters
----------
data: np.ndarray
データ入力するnp.ndarray
Returns
-------
result: np.ndarray
追加後のデータ
"""
new_y = np.random.randint(0, 100) # 追加する値
data[:data_len - 1] = data[1:data_len]
data[data_len - 1] = new_y
return data
def plot_callback() -> None:
"""データをプロットする"""
global x_data, y_data
y_data = update_array(y_data)
# 第1引数は値を入力したいアイテムのtag (= dpg.add_line_series(tag='line'))
dpg.set_value('line', [x_data, y_data])
# ##################### 描画設定 #####################
dpg.create_context()
dpg.create_viewport(title='Plot view port', width=420, height=300)
dpg.setup_dearpygui()
dpg.show_viewport()
with dpg.window(label='Plot window', width=-1, height=-1):
with dpg.plot(label=f"Real time plot \n interval: {interval} sec", width=400, height=250):
dpg.add_plot_legend() # 凡例追加
# x, y軸追加
dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis')
dpg.add_plot_axis(dpg.mvYAxis, label='y', tag='yaxis')
# データ線追加, 親は最後に追加したアイテム (=y軸)
dpg.add_line_series(x_data, y_data, label='data', parent=dpg.last_item(), tag='line')
while dpg.is_dearpygui_running():
total_time = dpg.get_total_time() # 画面が開いてからのトータル時間 (秒)
# interval 秒経過したらグラフ更新
if total_time - elapsed_time >= interval:
elapsed_time = total_time
plot_callback()
dpg.render_dearpygui_frame()
dpg.destroy_context()
その他
dpg.fit_axis_data(tag)
で軸をデータ範囲に調整できます
# 毎回範囲内に調整したい時
dpg.set_value(lineのtag, [x_data, y_data])
dpg.fit_axis_data(axisのtag)
参考
DearPyGuiをはじめる10行 - Qiita
Plots — Dear PyGui documentation
Render Loop — Dear PyGui documentation
Add support for timers · Issue #303 · hoffstadt/DearPyGui · GitHub