Spaces:
Build error
Build error
| import gradio as gr | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| import io | |
| import PIL.Image | |
| def process_excel_files(file1, file2): | |
| ファイル1 = pd.read_excel(file1.name) | |
| ファイル2 = pd.read_excel(file2.name) | |
| 比較列名1 = ファイル1.columns[3] | |
| 比較列名2 = ファイル2.columns[3] | |
| IDs1 = ファイル1.iloc[:, 0].values | |
| ラベル1 = ファイル1.iloc[:, 1].values | |
| データ1 = ファイル1.iloc[:, 3].values | |
| IDs2 = ファイル2.iloc[:, 0].values | |
| ラベル2 = ファイル2.iloc[:, 1].values | |
| データ2 = ファイル2.iloc[:, 3].values | |
| 加工後df1 = pd.DataFrame({'id': IDs1,'label': ラベル1,'value': データ1 }) | |
| 加工後df2 = pd.DataFrame({'id': IDs2,'label': ラベル2,'value': データ2 }) | |
| 共通ID = set(IDs1).intersection(set(IDs2)) | |
| if not 共通ID: | |
| return PIL.Image.new('RGB', (400, 200), color='white'), "エラー: 両ファイル間に共通のIDがありません。" | |
| ソート後df1 = 加工後df1[加工後df1['id'].isin(共通ID)].sort_values('id') | |
| ソート後df2 = 加工後df2[加工後df2['id'].isin(共通ID)].sort_values('id') | |
| # 同じIDの順序でデータを整列 | |
| 合体後df = pd.merge(ソート後df1, ソート後df2, on='id', suffixes=('_1', '_2')) | |
| # データを取得 | |
| IDs = 合体後df['id'].values | |
| ラベル = 合体後df['label_1'].values # ファイル1のラベルを使用 | |
| 値1 = 合体後df['value_1'].values | |
| 値2 = 合体後df['value_2'].values | |
| 差分 = 値2 - 値1 | |
| # グラフ用にラベルを短縮(長すぎる場合) | |
| short_labels = [str(label)[:15] + '...' if len(str(label)) > 15 else str(label) for label in ラベル] | |
| # 可視化 | |
| 図表, ( ax3,ax1, ax2) = plt.subplots(3, 1, figsize=(12, 18)) | |
| # X軸インデックス | |
| x = np.arange(len(IDs)) | |
| width = 0.8 | |
| ########################################################################################### 増減の可視化 | |
| colors = ['red' if x < 0 else 'green' for x in 差分] | |
| bars3 = ax3.bar(x, 差分, width, color=colors, alpha=0.7) | |
| ax3.set_title('diff : file1 >> file2') | |
| ax3.set_ylabel('Difference') | |
| ax3.set_xticks(x) | |
| # ラベルを垂直(90度)に変更 | |
| ax3.set_xticklabels(short_labels, rotation=90, ha='center', va='top') | |
| ax3.axhline(y=0, color='black', linestyle='-', alpha=0.5) | |
| ax3.grid(True, linestyle='--', alpha=0.7, axis='y') | |
| # 値をバーの上または下に表示 | |
| for bar in bars3: | |
| height = bar.get_height() | |
| y_pos = height + 0.1 if height >= 0 else height - 0.3 | |
| ax3.text(bar.get_x() + bar.get_width()/2., y_pos, | |
| f'{height:.2f}', ha='center', va='bottom', rotation=0, fontsize=8) | |
| ########################################################################################### # ファイル1のデータ(元データ) | |
| bars1 = ax1.bar(x, 値1, width, color='blue', alpha=0.7) | |
| ax1.set_title(f'file1') | |
| ax1.set_ylabel('Value') | |
| ax1.set_xticks(x) | |
| # ラベルを垂直(90度)に変更 | |
| ax1.set_xticklabels(short_labels, rotation=90, ha='center', va='top') | |
| ax1.grid(True, linestyle='--', alpha=0.7, axis='y') | |
| # 値をバーの上に表示 | |
| for bar in bars1: | |
| height = bar.get_height() | |
| ax1.text(bar.get_x() + bar.get_width()/2., height + 0.1, | |
| f'{height:.2f}', ha='center', va='bottom', rotation=0, fontsize=8) | |
| ########################################################################################### ファイル2のデータ | |
| bars2 = ax2.bar(x, 値2, width, color='green', alpha=0.7) | |
| ax2.set_title(f'file2') | |
| ax2.set_ylabel('Value') | |
| ax2.set_xticks(x) | |
| # ラベルを垂直(90度)に変更 | |
| ax2.set_xticklabels(short_labels, rotation=90, ha='center', va='top') | |
| ax2.grid(True, linestyle='--', alpha=0.7, axis='y') | |
| # 値をバーの上に表示 | |
| for bar in bars2: | |
| height = bar.get_height() | |
| ax2.text(bar.get_x() + bar.get_width()/2., height + 0.1, | |
| f'{height:.2f}', ha='center', va='bottom', rotation=0, fontsize=8) | |
| # 下部に余白を追加して、垂直ラベルのためのスペースを確保 | |
| plt.subplots_adjust(bottom=0.15) | |
| plt.tight_layout() | |
| # 画像をバイト列に変換してPIL Imageに変換 | |
| buf = io.BytesIO() | |
| plt.savefig(buf, format='png', dpi=100) | |
| buf.seek(0) | |
| 画像 = PIL.Image.open(buf) | |
| 統計 = { | |
| "比較した項目数": len(IDs), | |
| "増加した項目数": sum(0<差分), | |
| "減少した項目数": sum(差分<0), | |
| "最大の増加": int(np.max(差分)*100)/100 if len(差分[0<差分]) > 0 else 0, | |
| "最大の減少": int(np.min(差分)*100)/100 if len(差分[差分<0]) > 0 else 0, | |
| } | |
| 変化量データ = [{"id": IDs[i], "ラベル": ラベル[i], "変化量": 差分[i]}for i in range(len(IDs))] | |
| 変化量プラス = sorted([item for item in 変化量データ if item["変化量"] > 0],key=lambda x: x["変化量"], reverse=True) | |
| 変化量マイナス = sorted([item for item in 変化量データ if item["変化量"] < 0],key=lambda x: x["変化量"]) | |
| 分析結果 = "\n".join([f"{k}: {v}" for k, v in 統計.items()]) | |
| 分析結果 += "\n\n最も変化の大きいプラス 5件:\n" | |
| for item in 変化量プラス[:5]: 分析結果 += f"{item['変化量']:.2f} : {item['ラベル']} \n" | |
| 分析結果 += "\n最も変化の大きいマイナス 5件:\n" | |
| for item in 変化量マイナス[:5]: 分析結果 += f"{item['変化量']:.2f} : {item['ラベル']} \n" | |
| plt.close(図表) # 図を閉じてメモリリーク防止 | |
| return 画像, 分析結果 | |
| # Gradioインターフェースの作成 | |
| with gr.Blocks(title="Excelファイル比較アプリ") as app: | |
| gr.Markdown("# Excelファイル比較ツール") | |
| gr.Markdown("2つのExcelファイルをアップロードし、4列目のデータの増減を可視化します。") | |
| with gr.Row(): | |
| 比較元 = gr.File(label="比較元Excelファイル") | |
| 比較先 = gr.File(label="比較先Excelファイル") | |
| with gr.Row(): | |
| 画像出力 = gr.Image(label="比較結果グラフ") | |
| 統計出力 = gr.Textbox(label="統計情報", lines=12) | |
| 比較開始ボタン = gr.Button("比較開始") | |
| 比較開始ボタン.click( fn=process_excel_files, inputs=[比較元, 比較先], outputs=[画像出力, 統計出力] ) | |
| if __name__ == "__main__": | |
| app.launch(share=True) # 公開リンクを生成するためにshare=Trueを設定 |