7
9

More than 1 year has passed since last update.

DearPyGuiでプロットする

Last updated at Posted at 2022-01-23

はじめに

以下の記事からDearPyGuiというライブラリを知り, グラフ描画について興味が湧いたので調べてみました。
複数y軸, 時間軸, リアルタイム描画など簡単にできたので紹介します。

plot.pngmulti_axis.png
time_axis.pngreal_time.gif

環境

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()

demo2.png

単軸, 複数y軸

これらはドキュメントを見る方が確実かな?
y軸は最大3つまで追加出来るようです。
プロット内のズーム、凡例から表示/非表示などできます。

plot.pngmulti_axis.png

"""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_axis.png
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()

リアルタイム

以下を参考にしています

real_time.gif

画面表示のトータル時間から描画間隔を設定しています。


# ################# 時間経過判定用 #################
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)

また、プロット内を右クリックすると色々設定できます
right_click.png

参考

DearPyGuiをはじめる10行 - Qiita
Plots — Dear PyGui documentation
Render Loop — Dear PyGui documentation
Add support for timers · Issue #303 · hoffstadt/DearPyGui · GitHub

7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9