LoginSignup
0
3

More than 1 year has passed since last update.

GUIでデータファイルを選択してグラフ化

Last updated at Posted at 2021-07-18

はじめに

大量の同じフォーマットのExcel,CSVファイルのデータをまとめて一つのグラフにしたい。直感的にわかりやすいようにGUIでファイルの選択、軸範囲の設定を行いたい。

仕様

無題.png
・「ファイルを選択」ボタンでグラフ化するファイルを選択する。※ファイルは複数選択可能
・選択可能なファイルの拡張子はxls,xlsx,csv
・処理するファイルのデータのヘッダー行数を指定する。ヘッダーがない場合は、0または空白を指定する
・グラフのx列、y列となる処理するファイルのデータの列数を指定する
・x列、y列の組み合わせは最大4つまで指定可能
・x列またはy列のどちらか一方でも空欄の場合はグラフ化を行わない
・保存するグラフのファイル名は「保存ファイル名」で指定可能。空欄の場合のファイル名は「現在時刻+条件番号」となる
・グラフのx軸の範囲は「x最小」,「x最大」,y軸の範囲は「y最小」,「y最大」で設定可能。空欄の条件は自動設定になる
・「実行ボタン」でグラフ化の処理が走る
・グラフ化したファイルはGUIのコードが存在するフォルダ内に保存される

コード

import PySimpleGUI as sg
import pandas as pd
import matplotlib.pyplot as plt
import os
import numpy as np
import datetime

INPUT_BOX_SIZE = 5
HEADER_ROW = 1
SAVE_FILE_NAME_ROW = 2
OFFSET_DATA_NUM = 3
LINE_PER_DATA = 6
COND_LINE_NUM = 4
X_COL_OF_LINE = 0
Y_COL_OF_LINE = 1
X_MIN_OF_LINE = 2
X_MAX_OF_LINE = 3
Y_MIN_OF_LINE = 4
Y_MAX_OF_LINE = 5

def plotfig(axobj, x_data, y_data, filename, cmap, xlabel, ylabel, x_min, x_max, y_min, y_max):
    ##グラフ描画用の関数
    #引数の説明
    #axobj:グラフオブジェクト,x_data:x軸データ, y_data:y軸データ, filename:元データのファイル名
    #cmap:グラフのカラー, xlabel:x軸ラベル, ylabel:y軸ラベル
    #x_min:x軸最小値, x_max:x軸最大値, y_min:y軸最小値, y_max:y軸最大値
    axobj.plot(x_data, y_data, label=filename, color=cmap, marker='o')
    axobj.grid()
    axobj.legend()
    axobj.set_xlabel(xlabel)
    axobj.set_ylabel(ylabel)
    ## 軸範囲の設定 ※GUIで指定されていない場合は自動で設定
    # x軸
    if x_min.strip() and x_max.strip():
        axobj.set_xlim(left=int(x_min), right=int(x_max))
    elif x_min.strip():
        axobj.set_xlim(left=int(x_min))
    elif x_max.strip():
        axobj.set_xlim(right=int(x_max))
    # y軸
    if y_min.strip() and y_max.strip():
        axobj.set_ylim(bottom=int(y_min), top=int(y_max))
    elif y_min.strip():
        axobj.set_ylim(bottom=int(y_min))
    elif y_max.strip():
        axobj.set_ylim(top=int(y_max))

#  セクション1 - オプションの設定と標準レイアウト
sg.theme('Dark Blue 3')

layout = [
    #1行目
    [sg.InputText('ファイル一覧',enable_events=True,), sg.FilesBrowse('ファイルを選択', key='-FILES-', file_types=(("Excel ファイル", "*.xlsx"),("Excel ファイル", "*.xls"),("CSV ファイル", "*.csv")))],
    #2行目
    [sg.Text('ヘッダ行数', size=(10, 1)),sg.InputText('1', size=(INPUT_BOX_SIZE, 1)),sg.Text('保存ファイル名', size=(12, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE*5, 1))],
    #3行目
    [sg.Text('条件', size=(5, 1)),sg.Text('x列', size=(INPUT_BOX_SIZE, 1)),sg.Text('y列', size=(INPUT_BOX_SIZE, 1)),
    sg.Text('x最小', size=(INPUT_BOX_SIZE-1, 1)), sg.Text('x最大', size=(INPUT_BOX_SIZE-1, 1)), sg.Text('y最小', size=(INPUT_BOX_SIZE-1, 1)), sg.Text('y最大', size=(INPUT_BOX_SIZE-1, 1))],
    #4行目
    [sg.Text('1',size=(5, 1)),sg.InputText('1', size=(INPUT_BOX_SIZE, 1)),sg.InputText('2', size=(INPUT_BOX_SIZE, 1)),
    sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1))],
    #5行目
    [sg.Text('2',size=(5, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),
    sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1))],
    #6行目
    [sg.Text('3',size=(5, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),
    sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1))],
    #7行目
    [sg.Text('4',size=(5, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),sg.InputText(' ', size=(INPUT_BOX_SIZE, 1)),
    sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1)), sg.InputText('', size=(INPUT_BOX_SIZE, 1))],
    #8行目
    [sg.Submit(button_text='実行ボタン')]
]

# セクション 2 - ウィンドウの生成
window = sg.Window('グラフ保存', layout)

# セクション 3 - イベントループ
while True:
    event, values = window.read()

    if event is None:
        print('exit')
        break

    if event == '実行ボタン':
        # ファイルのパスを抽出
        files = values['-FILES-'].split(';')
        # ファイルの数を抽出
        files_num = len(files)
        # 処理対象のデータのヘッダー行を抽出
        header_row = values[HEADER_ROW]
        # 画像の保存ファイル名を抽出
        input_save_file_name = values[SAVE_FILE_NAME_ROW].strip()

        d_temp={}
        # グラフ処理
        for k, v in values.items():   # 一度pd.Seriesに変換
            # ヘッダー数を除いてデータフレームを作成
            if type(k)==str:
                continue
            # GUIの入力データ以外は無視
            if k < OFFSET_DATA_NUM:
                continue
            d_temp[k-1] = pd.Series(v)

        df = pd.DataFrame(d_temp)
        # DataFrameの行列をGUIの表示の形に成形
        pd_cond = pd.DataFrame(df.values.reshape(COND_LINE_NUM, LINE_PER_DATA))

    # グラフオブジェクトの作成
        fig = np.zeros(COND_LINE_NUM)
        ax = np.zeros(COND_LINE_NUM)
        cmap = plt.get_cmap("tab10") # カラーマップを定義
        fig_list = ['']*COND_LINE_NUM
        ax_list = ['']*COND_LINE_NUM
        for n in range(COND_LINE_NUM):
            fig_list[n] = plt.figure()
            ax_list[n] = fig_list[n].add_subplot(1,1,1)

    # ファイルからデータ読み込み
        for i, file in enumerate(files):
            _, ext = os.path.splitext(file)
            #Excelファイルの場合
            if ext==".xls" or ext==".xlsx":
                if header_row.strip() and int(header_row) > 0:
                    readdata = pd.read_excel(file, header=int(header_row)-1)#行数は1始まりを期待しいるため-1。0始まりなら-1は不要。
                else:
                    readdata = pd.read_excel(file, header=None)
            #CSVファイルの場合
            elif ext==".csv":
                if header_row.strip() and int(header_row) > 0:
                    readdata = pd.read_csv(file, header=int(header_row)-1)
                else:
                    readdata = pd.read_csv(file, header=None)
            #グラフの凡例につけるためのファイル名※拡張子は除いている
            filename = os.path.splitext(os.path.basename(file))[0]
            # 条件ごとに各ファイルのデータを重ねる
            for j in range(COND_LINE_NUM):
                #x列、y列が空欄の場合は処理を行わない
                if not pd_cond.iloc[j,X_COL_OF_LINE].strip() or not pd_cond.iloc[j,Y_COL_OF_LINE].strip():
                    continue
                # 処理対応データ格納列の情報を抽出してint化
                x_col = int(pd_cond.iloc[j, X_COL_OF_LINE])-1 #GUIの条件は1始まりなので-1
                y_col = int(pd_cond.iloc[j, Y_COL_OF_LINE])-1 #GUIの条件は1始まりなので-1
                x_data = readdata.iloc[:,x_col]
                y_data = readdata.iloc[:,y_col]
                # x_col,y_colは空欄でないことが保証されているが、最大最小値は空欄の可能性があるためここではint化しない
                x_min = pd_cond.iloc[j, X_MIN_OF_LINE]
                x_max = pd_cond.iloc[j, X_MAX_OF_LINE]
                y_min = pd_cond.iloc[j, Y_MIN_OF_LINE]
                y_max = pd_cond.iloc[j, Y_MAX_OF_LINE]
                # グラフ描画用の関数でグラフ描画
                plotfig(ax_list[j], x_data, y_data, filename, cmap(i), 
                        readdata.columns[x_col], readdata.columns[y_col],
                        x_min, x_max, y_min, y_max)

        # ファイル名に現在時刻を付けて画像を保存
        for j in range(COND_LINE_NUM):
                #x列、y列が空欄の場合は処理を行わない
                if not pd_cond.iloc[j,X_COL_OF_LINE].strip() or not pd_cond.iloc[j,Y_COL_OF_LINE].strip():
                    continue
                if not input_save_file_name:
                    dt_now = datetime.datetime.now()
                    save_file_name = dt_now.strftime('%Y年%m月%d日%H時%M分%S秒') + "_条件" + str(j+1)# GUIの条件は1始まりなので+1
                else:
                    save_file_name = input_save_file_name + "_条件" + str(j+1)# GUIの条件は1始まりなので+1
                fig_list[j].savefig(save_file_name)

        # ポップアップ
        sg.popup("終了~")

# セクション 4 - ウィンドウの破棄と終了
window.close()

注意点

importしているライブラリ以外にopenpyxlをインストールしておく必要有

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