1
0

More than 1 year has passed since last update.

[dearpygui] drag&dropでプロットする

Posted at

やりたいこと

ドキュメントのギャラリーにあるような、データをドラッグしてグラフを表示してみたい

gallery.gif

demoを参考にしながら方法を調べてみました

dd_plot_2.gif

環境

Mac OS
Python 3.10.1

dearpygui 1.3.1
numpy 1.22.1

pip install dearpygui numpy

詳細

ドラッグ&ドロップの実装

まずは簡単なドラッグの実装から

ドラッグ側

ドラッグしたいアイテムにdpg.add_drag_payload()を設定
引数は
- parent : ドラッグしたいアイテムのタグ
- drag_data : ドラッグして渡したいデータ
- payload_type : ドラッグ元とドラッグ先の合言葉?のようなもの. 双方に同じ文字列を入力

ドロップ側

アイテム作成時にdrop_callback, payload_type引数を入力. それぞれ
- drop_callback : ドロップされたときに実行する関数
- payload_type : ドラッグ元と同じ文字列

下は10と表示してあるボタンをドラッグして、input_intアイテムに値を入れています

input_10.gif

from typing import Any, Union

import dearpygui.dearpygui as dpg


# ドラッグされたときに呼び出す関数
def input_drop_int(sender: Union[int, str], app_data: Any, user_data) -> None:
    """ドロップされた整数を入力する

    Parameters
    -----
    sender: Union[int, str]
        送信元のタグ
    app_data: Any
        ドロップされたデータ
    user_data
    """

    dpg.set_value(sender, app_data)


# ##################### 描画設定 #####################
dpg.create_context()
dpg.create_viewport(title='Plot view port', width=800, height=500)

with dpg.window(label='Drag&Drop Window', width=250, height=50):
    with dpg.group(horizontal=True):
        button = dpg.add_button(label=str(10))
        # drag_data: ドラッグ先に渡すデータ, payload_type: ドラッグ元とドラッグ先の合言葉?のようなもの, strを指定
        dpg.add_drag_payload(parent=button, drag_data=10, payload_type='Drag&Drop')

        input_int = dpg.add_input_int(label='drop', drop_callback=input_drop_int, payload_type='Drag&Drop')

dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()

with dpg.drag_payload()だとドラッグ中に表示さあれるウィンドウの編集ができます。

input_10_2.gif

with dpg.window(label='Drag&Drop Window', width=250, height=50):
    with dpg.group(horizontal=True):
        button = dpg.add_button(label=str(10))
        # drag_data: ドラッグ先に渡すデータ, payload_type: ドラッグ元とドラッグ先の合言葉?のようなもの, strを指定
        with dpg.drag_payload(parent=button, drag_data=10, payload_type='Drag&Drop'):
            dpg.add_text(default_value='value:10')

        input_int = dpg.add_input_int(label='drop', drop_callback=input_drop_int, payload_type='Drag&Drop')

グラフでやってみる

dd_plot.gif

"""Drag&Dropでグラフをかく
参考
https://github.com/hoffstadt/DearPyGui/blob/master/DearPyGui/dearpygui/demo.py
2205 ~ 2245行目
"""

from typing import Any, Union

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)
sin_data = np.sin(x_data)


# ドラッグされたときに呼び出す関数
def plot_drag_data(sender: Union[int, str], app_data: Any, user_data) -> None:
    """ドラックされたデータをプロットする

    Parameters
    -----
    sender: Union[int, str]
        送信元のタグ
    app_data: Any
        ドラッグされたデータ
    user_data
    """

    dpg.add_line_series(app_data[0], app_data[1], label=app_data[2], parent=sender)
    # 軸の範囲をデータに合わせる
    dpg.fit_axis_data('xaxis')
    dpg.fit_axis_data(sender)

    # 凡例を右クリックすると追加した線を削除できるボタンを追加
    dpg.add_button(label='delete', user_data=dpg.last_item(), parent=dpg.last_item(),
                   callback=lambda s, a, u: dpg.delete_item(u))


# ##################### 描画設定 #####################
dpg.create_context()
dpg.create_viewport(title='Plot view port', width=800, height=500)

with dpg.window(label='Drag&Drop Window', width=-1, height=-1):
    # グループ内のアイテムを横に並べる
    with dpg.group(horizontal=True):
        # グループ内のアイテムを縦に並べる
        with dpg.group():
            dpg.add_text(default_value='sources:')

            # button追加&ボタンをドラッグしたときの情報追加
            dpg.add_button(label='sin', tag='sin_src')
            # drag_data: ドラッグ先に渡すデータ, payload_type: ドラッグ元とドラッグ先の合言葉?のようなもの, strを指定
            with dpg.drag_payload(parent='sin_src', drag_data=(x_data, sin_data, 'sin'), payload_type='plotting'):
                dpg.add_text('sin')
                dpg.add_simple_plot(default_value=sin_data)

        with dpg.plot(label='Drag&Drop Plot', width=700, height=440):
            # 凡例, x軸
            dpg.add_plot_legend()
            dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis')
            # y軸作成、dropされた時のコールバックを設定、payload_typeはドラッグ元と同じ文字列を指定
            dpg.add_plot_axis(dpg.mvYAxis, label='y1', drop_callback=plot_drag_data, payload_type='plotting')

dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()

y2, y3, plot, legendにもドラッグできるように変更
(Demo.pyを参考にしています)

dd_plot_2.gif

"""
参考
https://github.com/hoffstadt/DearPyGui/blob/master/DearPyGui/dearpygui/demo.py
2205 ~ 2245行目
"""

from typing import Any, Union

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)
sin_data = np.sin(x_data)


def make_y_data(wave):
    freq = dpg.get_value('freq')
    if wave == 'sin':
        y_data = np.sin(freq * x_data)
    else:
        y_data = np.cos(freq * x_data)
    return y_data, freq


def dropped_axis(sender: Union[int, str], app_data: Any, user_data) -> None:
    """"y軸にドロップされたデータを表示する

    Parameters
    -----
    sender: Union[int, str]
        送信元のタグ
    app_data: Any
        ドラッグされたデータ
    user_data
    """

    y_data, freq = make_y_data(app_data[-1])
    dpg.add_line_series(app_data[0], y_data, label=f"{app_data[-1]}({freq}x)", parent=sender)
    dpg.fit_axis_data('xaxis')
    dpg.fit_axis_data(sender)

    # 凡例を右クリックすると追加した線を削除できるボタンを追加
    dpg.add_button(label='delete', user_data=dpg.last_item(), parent=dpg.last_item(),
                   callback=lambda s, a, u: dpg.delete_item(u))


def dropped_legend(sender, app_data, user_data):
    """legendにドロップした時の動作"""

    y_data, freq = make_y_data(app_data[-1])

    parent = dpg.get_item_info(sender)["parent"]
    yaxis2 = dpg.get_item_info(parent)["children"][1][2]
    dpg.add_line_series(app_data[0], y_data, label=f"{app_data[-1]}({freq}x)", parent=yaxis2)
    dpg.fit_axis_data('xaxis')
    dpg.fit_axis_data(yaxis2)

    dpg.add_button(label="Delete Series", user_data=dpg.last_item(), parent=dpg.last_item(),
                   callback=lambda s, a, u: dpg.delete_item(u))


def dropped_plot(sender, app_data, user_data):
    """プロットにドロップした時の動作"""
    y_data, freq = make_y_data(app_data[-1])

    yaxis1 = dpg.get_item_info(sender)["children"][1][0]
    dpg.add_line_series(app_data[0], y_data, label=f"{app_data[-1]}({freq}x)", parent=yaxis1)
    dpg.fit_axis_data('xaxis')
    dpg.fit_axis_data(yaxis1)

    dpg.add_button(label="Delete Series", user_data=dpg.last_item(), parent=dpg.last_item(),
                   callback=lambda s, a, u: dpg.delete_item(u))


dpg.create_context()
dpg.create_viewport(title='DD', width=800, height=500)

with dpg.window(label='Drag&Drop Window', width=-1, height=-1):
    # グループ内のアイテムを横に並べる
    with dpg.group(horizontal=True):
        # グループ内のアイテムを縦に並べる
        with dpg.group():
            dpg.add_text(default_value='sources:')
            dpg.add_input_int(label='freq', width=80, default_value=1, tag='freq')

            # button追加&ボタンをドラッグしたときの情報追加
            dpg.add_button(label='sin', tag='sin_src')
            with dpg.drag_payload(parent='sin_src', drag_data=(x_data, 'sin'), payload_type='plotting'):
                dpg.add_text('sin')

            dpg.add_button(label='cos', tag='cos_src')
            with dpg.drag_payload(parent='cos_src', drag_data=(x_data, 'cos'), payload_type='plotting'):
                dpg.add_text('cos')

        with dpg.plot(label='Drag&Drop Plot', width=600, height=375, drop_callback=dropped_plot,
                      payload_type='plotting'):
            # 凡例, x軸
            dpg.add_plot_legend(drop_callback=dropped_legend, payload_type='plotting')
            dpg.add_plot_axis(dpg.mvXAxis, label='x', tag='xaxis')
            # y軸作成、dropされた時のコールバックを設定、payload_typeはドラッグ元と同じ文字列を指定
            dpg.add_plot_axis(dpg.mvYAxis, label='y1', drop_callback=dropped_axis, payload_type='plotting')
            dpg.add_plot_axis(dpg.mvYAxis, label='y2', drop_callback=dropped_axis, payload_type='plotting')
            dpg.add_plot_axis(dpg.mvYAxis, label='y3', drop_callback=dropped_axis, payload_type='plotting')

dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()

参考

DearPyGui/demo.py at master · hoffstadt/DearPyGui

1
0
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
1
0