本記事では、PySide6でデスクトップアプリを作成する雛形コードを載せました。本アプリの動作検証用のサンプルのexcelファイルと雛形コードは、次のgithubにアップしています。https://github.com/hk29-ai/template_for_GUI_app_using_pyside6
■ライブラリのインストール
pip install pyside6
■作成したアプリの仕様
本プログラムを実行すると、次のようなwindowが表示されます。上部にある「Excelファイルを選択」のボタンを押下します。
下図のようなダイアログが表示されるので、エクセルファイルを選択します。
上記の後、下図のようにエクセル内のシート名が一覧で表示されます。
次に、下図のように処理したいシート名を選択します(複数可)。そして下部にある「データ処理の実行」ボタンを押します。
処理が終わると、下図のように完了の表示がされます。
アウトプットは、下図のようにグラフ画像を出力します(一部抜粋)。
また、下図のように複数のシートを行方向に結合して、ひとつのcsvファイルに保存します。
■本プログラム
import os import sys import pandas as pd import matplotlib.pyplot as plt import matplotlib.cm as cm import japanize_matplotlib plt.rcParams['font.size'] = 15 # グラフの基本フォントサイズの設定 from PySide6.QtWidgets import ( QApplication, QFileDialog, QMainWindow, QPushButton, QVBoxLayout, QWidget, QLabel, QTextEdit, QListWidget, QAbstractItemView ) from PySide6.QtCore import Qt from PySide6.QtGui import QFont, QPalette, QColor, QIcon class MainWindow(QMainWindow): def __init__(self): super().__init__() self.resize(450, 500) self.setWindowTitle("アプリの雛形") self.x_name = 'x' self.y_name = 'y' # ファイル選択ボタンを作成 self.select_file_button = QPushButton("1. Excelファイルを選択") self.select_file_button.clicked.connect(self.open_file_dialog) # ボタンのサイズを2行分に設定 self.select_file_button.setFixedHeight(2 * self.select_file_button.fontMetrics().height()) # ボタンの背景色を薄いピンク色に設定 赤:#FFB6C1 黄色:#FFFFE0 青:#ADD8E6 self.select_file_button.setStyleSheet("background-color: #FFB6C1; font-size: 16px;") # ファイルパスを表示するラベル self.file_path_label = QLabel() # 進捗状況の表示 self.process_label = QLabel(self) my_font = QFont("Arial", 20) # フォント名とサイズを指定 my_font.setBold(True) # 太字に設定 self.process_label.setFont(my_font) self.process_label.setAlignment(Qt.AlignCenter) # 中央揃え # フォントの色 self.palette_blue = QPalette() self.palette_blue.setColor(QPalette.WindowText, QColor(0, 0, 255)) # 青字を指定 # シート名を表示するリストウィジット self.sheet_list = QListWidget() self.sheet_list.setSelectionMode(QAbstractItemView.MultiSelection) # テキストエディタを作成 self.text_edit = QTextEdit() # テキストボックスの高さを2行分に設定 self.text_edit.setFixedHeight(3.5 * self.text_edit.fontMetrics().height()) # テキストボックスに表示する文章を中央揃えに設定 self.text_edit.setAlignment(Qt.AlignCenter) # テキストボックスの背景色を薄い黄色に設定 self.text_edit.setStyleSheet("background-color: #FFFFE0; font-size: 16px;") # 黄色:#FFFFE0 self.text_edit.insertPlainText("2. 上記に表示されているリストから、\nデータ処理するシートを選択(複数可)") # 実行ボタン self.run_button = QPushButton("3. データ処理の実行") self.run_button.clicked.connect(self.start_processing) # ボタンのサイズを2行分に設定 self.run_button.setFixedHeight(2 * self.run_button.fontMetrics().height()) # ボタンの背景色を薄い青色に設定 self.run_button.setStyleSheet("background-color: #ADD8E6; font-size: 16px;") # レイアウト layout = QVBoxLayout() layout.addWidget(self.select_file_button) layout.addWidget(self.file_path_label) layout.addWidget(self.sheet_list) layout.addWidget(self.text_edit) layout.addWidget(self.run_button) layout.addWidget(self.process_label) # ウィジェットを作成し、メインウィンドウに設定 widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) # ファイル選択のダイアログ def open_file_dialog(self): options = QFileDialog.Options() file_path, _ = QFileDialog.getOpenFileName(self, "excelファイルを選択", "", "Excel Files (*.xlsx);;All Files (*)", options=options) if file_path: # シートリストを初期化 self.sheet_list.clear() self.file_path_label.setText(file_path) # シート名の一覧を取得する excel_file = pd.ExcelFile(file_path) sheet_names = excel_file.sheet_names self.sheet_list.addItems(sheet_names) # ファイルパスをインスタンス変数化 self.selected_excel_file = file_path # フォルダパスを取得してインスタンス変数化 self.folder_path = os.path.dirname(file_path) # ファイル名の取得 file_name = os.path.basename(file_path) # ファイルパスから、拡張子なしのファイル名と拡張子の取得 file_name_wo_extension, extension = os.path.splitext(file_name) self.file_name = file_name_wo_extension # 折れ線グラフ def plot_graph_1(self, df, i, select_sheet_name): # データを抽出 x_data = df[self.x_name].values y_data = df[self.y_name].values # データを辞書へ格納 self.data_dict[select_sheet_name] = (x_data, y_data) # 散布図 fig = plt.figure(figsize=(6,4)) plt.scatter(x_data, y_data) # 折れ線図 plt.plot(x_data, y_data) if select_sheet_name == 'ガンマ関数': plt.yscale('log') plt.grid() plt.xlabel(f"{self.x_name}") plt.ylabel(f"{self.y_name}") plt.title(f"{select_sheet_name}") # 保存するファイルパス _save_jpg_path = f"{self.folder_path}/{str(i).zfill(2)}_{select_sheet_name}.jpg" # 画像ファイルに出力 plt.savefig(_save_jpg_path, bbox_inches="tight") print(f"save {_save_jpg_path}") plt.clf() # カテゴリ別の折れ線グラフ def plot_graph_2(self, df): ### ガンマ分布の確率密度関数のデータだけ抽出してグラフ化する x_name = 'x_data' y_name = 'y_data' label = 'select_sheet_name' legend_name = '' title = 'ガンマ分布の確率密度関数' # データフレームから条件指定で行データを抽出する df = df[df[label].str.contains(title)] # プロットするカラーを指定するための処理 cnt = len(df.groupby(label).count().index.to_list()) color_list = [] for j in range(cnt): color_list.append(cm.hsv(j/cnt)) # jet cool autumn hsv color_list # ひとつのグラフにカテゴリ別にプロットする handle_list = [] for i, legend in enumerate(df[label].unique()): # ラベルを文字列から絞って抽出する index = legend.index("_") label_name = legend[index + 1:] # 折れ線図を作成 plt.plot(df.loc[df[label] == legend, x_name], df.loc[df[label] == legend, y_name], #facecolor = 'None', #edgecolors = color_list[i], color = color_list[i], label = label_name) plt.grid() plt.legend(bbox_to_anchor = (1, 1), title = legend_name) plt.xlabel(x_name) plt.ylabel(y_name) plt.title(title) # 保存するファイルパス save_jpg_path = f"{self.folder_path}/{self.file_name}.jpg" plt.savefig(save_jpg_path, bbox_inches="tight") print(f"save {save_jpg_path}") # 選択したシートに対して実行 def start_processing(self): self.process_label.setText("処理中...") QApplication.processEvents() # GUIを更新する # 選択したシートをリストへ格納する selected_items = self.sheet_list.selectedItems() self.selected_sheet_names = [item.text() for item in selected_items] print('選択されたーシート', self.selected_sheet_names) # シート毎に処理する(グラフを作成して、画像ファイルに保存する) self.data_dict = {} # 各シートデータをひとつにするための辞書 for _i, _select_sheet_name in enumerate(self.selected_sheet_names, start=1): _df = pd.read_excel(self.selected_excel_file, sheet_name = _select_sheet_name, usecols = "A:B", # AからB列までを選択 engine = "openpyxl" ) # グラフ化1 self.plot_graph_1(_df, _i, _select_sheet_name) # シート別のデータを1つに結合する rows = [] for _select_sheet_name, (x_data, y_data) in self.data_dict.items(): for x, y in zip(x_data, y_data): rows.append([_select_sheet_name, x, y]) # データフレーム作成 df1 = pd.DataFrame(rows, columns=["select_sheet_name", "x_data", "y_data"]) save_csv_path = f"{self.folder_path}/{self.file_name}.csv" df1.to_csv(save_csv_path, index=False, encoding="shift-jis") print(f"save {save_csv_path}") # グラフ化2 self.plot_graph_2(df1) print('処理が完了しました') self.process_label.setPalette(self.palette_blue) self.process_label.setText('処理が完了しました。') if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.setWindowIcon(QIcon("image.ico")) window.show() sys.exit(app.exec())
以上
<広告>
リンク
リンク
リンク