はじめに
はじめまして、未経験/独学からフロントエンドエンジニアとしての就職を目指しているYuuhaと申します。
技術力向上のため、日々新しい技術を取り入れて学習するようにしています。
今回は、デスクトップアプリを一度作成してみたいと思っていたので、Eelを使用してExcelを扱うアプリを作った時の話です。
制作の背景
何か問題解決のために技術を使いたいと思い、身内に聞き取りをしてみたところ、「Excelの表から特定の項目だけ抽出して新しいExcelに変換する機能が欲しい」ということでアプリの内容が決まりました。
Eelを選んだ理由は単純で、Pythonなら少し触ったことがあったこと、早くリリースするために学習コストがかからないHTML,CSSでUIが実装できるという点がポイントでした。
制作したもの
今回制作したものは、学習目的かつ、実際に機能することと早くリリースすることを優先していたので、プロダクトとしてのクオリティは保証できないので、その点はご了承ください。
アプリの概要
アプリの概要は下のような表があった場合、特定の項目(列)を抽出したい(例えば、itemAとitemDの列だけ抜き出して2×2の表を作る)という簡単なものです。
itemA | itemB | itemC | itemD | |
---|---|---|---|---|
1 | A-1 | B-1 | C-1 | D-1 |
2 | A-2 | B-2 | C-2 | D-2 |
表が上記のようなパターンのみであれば、PythonのライブラリのPandasを利用すれば簡単に実現できます。ただし、大きく分けて以下の3パターンのような特殊なパターンの表があったので、その場合にも対応できるようにしたいと思います。
1.表の項目が複数ある場合
以下のような表の場合、itemCは合計の値(itemCの最後の列)だけ抽出します。
itemA | itemB | itemC | ||||
---|---|---|---|---|---|---|
itemC-1 | itemC-2 | itemC-3 | 合計 | |||
1 | A-1 | B-1 | C-11 | C-12 | C-13 | C-sum1 |
2 | A-1 | B-1 | C-11 | C-22 | C-23 | C-sum2 |
2.Excelのシート1枚に対して複数の表が存在する場合
以下のような場合、各列の項目が一致しないので、各表ごとに分割して処理する必要があります。
itemA | itemB | itemC | |
1 | A-1 | B-1 | C-1 |
2 | A-2 | B-2 | C-2 |
itemA | itemD | itemE | |
1 | A-1 | D-1 | E-1 |
2 | A-2 | D-2 | E-2 |
3.目的となる表以外に関係のない表が存在する
こちらも似たような処理ですが、必要ない表は無視して進める処理が必要になります。
(この場合、上の表が必要ないものになります)
単価 | 数量 | 単位 | |
1 | 100 | 5 | kg |
2 | 200 | 2 | L |
itemA | itemB | itemC | |
1 | A-1 | B-1 | C-1 |
2 | A-2 | B-2 | C-2 |
以上の3パターンに対応できるように実装しました。次の項で、今回それぞれのパターンに合わせて行った実装を紹介します。
Excel処理部分の実装の概要
複数の表がある場合、各表ごとに分割する
詳しい解説は省きますが、groupby()によって空白の行があればそこを境界として表を分割し、dropna()で空白行を消去しています。
input_file = pd.ExcelFile(pathnames)
sheet_names = input_file.sheet_names
for sheet_name in sheet_names:
main_columns = {}
for i in range(max):
main_columns[i] = {}
df = pd.read_excel(p,index_col=None,header=None,sheet_name=sheet_name)
filtered_df = df.iloc[1:,:end]
dfg = filtered_df.groupby((df.isnull().all(axis=1)).cumsum())
for index, g in dfg:
g = g.dropna(how="all")
if len(g) > 0:
g = g.values
d = pd.DataFrame(g[1:,:], columns=g[0])
分割した表をさらに項目ごとに分解する
下記で登場するdivisionsは列の項目の始点の番号です。したがって、2つ目以降のdivisionsの1つ前の番号は、1つ前の項目の最終列になります。なので、下記のようにcolumn_itemはすべての列の項目の最終列に該当します。
#上記の続き
num = 0
prev = 0
for i in divisions:
if i >= 1:
if num == 0:
column_item = d.iloc[:,0:i]
else:
column_item = d.iloc[:,prev:i]
num += 1
prev = i
実装の基本的な考え方は以上となります。あとは、抽出したい項目などをsqlite3などのデータベースを使用して記録・呼び出しすることで、表の抽出ができるようにしました。
まとめ
以上が今回制作したデスクトップアプリの概要でした。
より良い実装方法や間違いなどございましたら、コメントなどでご指摘いただけると幸いです。
もし、このアプリを使用したいという方は、githubのリポジトリからdist.zipにexeファイルが入っているので、そちらをご利用ください。(exeファイル化には、pyinstallerを使用しているので、ウイルスファイル扱いされる可能性があります。その点はご注意ください。)
アプリの内容自体は簡単なものでしたが、新しい言語を学習することで、これまで触っていた言語の復習になったり、新しい発見があったりしたので、これからもいろいろな分野に触れていこうと思います。