PythonでExcelのデータを読み込み、名前をつけて保存する。
Pythonの練習第2弾。今回は、かなり昔の記事エクセルからデータを読み込み、Peakを検出しエクセルに出力する - 生物屋さんのためのゼロからのプログラミングをPythonを使って書いてみた。ただし、今回はエクセルのデータの読み込みと書き出しのみを行った。
ソースコードは下記。
import tkinter import tkinter.filedialog import openpyxl import numpy as np #エクセルの読み込みと書き込み、そして保存する関数 def openFile(event): fileType = [("excel", "*.xlsx")] iDir = "/Users/Desktop/" filePath = tkinter.filedialog.askopenfilename(filetypes = fileType, initialdir = iDir) wb = openpyxl.load_workbook(filePath) sheet = wb.active #入れ物の作成 u = np.zeros((sheet.max_column, sheet.max_row)) #入れ物に数値を入れる for i in range(1,sheet.max_column+1): for j in range(1, sheet.max_row+1): u[i-1][j-1] = sheet.cell(row=j, column=i).value #データを入れるためのシートを作る wb.create_sheet(index=2, title="Copy Data") sheet2 = wb["Copy Data"] # シートにデータを貼り付ける for i in range(1, sheet.max_column+1): for j in range(1, sheet.max_row+1): sheet2.cell(row=j, column=i).value = u[i-1][j-1] #新しいExcelファイルを名前をつけて保存する closePath = tkinter.filedialog.asksaveasfilename() wb.save(closePath+".xlsx") #GUIの作成 root = tkinter.Tk() root.title("Excel Test") root.geometry("100x100") #イベントを起こすためのボタンの作成 button1 = tkinter.Button(text = "Open", width = 50) button1.bind("<Button-1>", openFile) button1.pack() #実行 root.mainloop()
このプログラムを実行すると、オープンダイアログが立ち上がるので、目的のExcelファイルを選択。今回は下記のような単純な数字が並んだものにした。
そして、すぐに保存用のダイアログが立ち上がるので、適当に名前をつけて保存すると、のように、新しいシートにデータを書き込める。
幾つかのコードを見ていく。
まず、Javaでエクセルを取り扱うには、
poi-3.17.jar poi.examples-3.17.jar poi.excelant-3.17.jar poi-ooxml-3.17.jar poi-ooxml-schemas-3.17.jar poi-scratchpad-3.17.jar xmlbeans-2.6.0.jar
上記のjarファイルをEclipseに入れる必要があった(詳細はEclipseでImageJのPlugin作成 -マウスでクリックした場所にOval ROIを描き、Excelファイルにデータを書き出す。- - 生物屋さんのためのゼロからのプログラミング参照)。
一方、Pythonの場合は、まず、ターミナルで、
sudo pip3 install openpyxl
と入力すると、"openpyxl"がインストールできる。
ただし、この時、インストールされた"openpyxl"は「”ライブラリ”⇨”Frameworks”⇨”Python.framework”⇨”Versions”⇨”3.6”⇨”lib”⇨”Python3.6”⇨”site-packages”」に入っているので(僕のMacでは)、”site-packages”の中から出して、一つ上の”Python3.6”に移す必要がある。
そして、
import openpyxl
を書くだけで、PythonでExcelが扱えるようになる。
(ただし、Mac Excel 2011とopenpyxlの相性が悪いのか、Mac Excel 2011で作成したExcelファイルは開けなかったが、Mac Excel 2016で作成したExcelファイルは扱えた。理由は不明)
Excelファイルを開く場合、多くのサイトでは、カレントディレクトリに開きたいExcelファイルを移して、Excelファイル名をコードに手入力する方法を紹介している。
しかし、これでは使い勝手が非常に悪いので、オープンダイアログを使って開きたいExcelファイルを選択できるようにした。ソースコードは下記。
fileType = [("excel", "*.xlsx")] iDir = "/Users/Desktop/" filePath = tkinter.filedialog.askopenfilename(filetypes = fileType, initialdir = iDir) wb = openpyxl.load_workbook(filePath)
実質一行で完結するので、Javaに比べると非常に楽である。
次に、なんらかの数値処理を行うために、Excelのデータを配列に取り込むためのコードが下記。
#入れ物の作成 u = np.zeros((sheet.max_column, sheet.max_row)) #入れ物に数値を入れる for i in range(1,sheet.max_column+1): for j in range(1, sheet.max_row+1): u[i-1][j-1] = sheet.cell(row=j, column=i).value
配列には"numpy"を使用した。"numpy"のインストールには、"openpyxl"と同様に、ターミナルで
sudo pip3 install numpy
と入力することでインストールでき、"openpyxl"と同様に”Python3.6”に移せば使えるようになる。
まだnumpyの使い方がよく分からなかったため、下記の部分で”作りたい大きさ”の空の入れ物を作った。
#入れ物の作成 u = np.zeros((sheet.max_column, sheet.max_row))
Excelのデータを配列に入れる時の注意点として、数の数え方の違いがある。
#入れ物に数値を入れる for i in range(1,sheet.max_column+1): for j in range(1, sheet.max_row+1): u[i-1][j-1] = sheet.cell(row=j, column=i).value
上記の部分でExcelのデータを配列に入れているのだが、エクセル上では”1”から数え始めるのに対し、配列は”0”から始まるため微調整が必要となる。
Excelにデータを貼る場合も、Pythonは非常に楽であった。コードは下記。
# シートにデータを貼り付ける for i in range(1, sheet.max_column+1): for j in range(1, sheet.max_row+1): sheet2.cell(row=j, column=i).value = u[i-1][j-1]
Javaの場合は、記入するための"cell"を最初に作る必要があり、これを怠ったり、記入するデータサイズと異なっているとエラーが生じていた。なので、Excel操作に関しては圧倒的にPythonが楽そうである。
最後に、保存ダイアログを使ったExcelファイルの保存方法は下記。
#新しいExcelファイルを名前をつけて保存する closePath = tkinter.filedialog.asksaveasfilename() wb.save(closePath+".xlsx")
オープンダイアログと同様、一行で終わるので非常に楽である。
上記のコードをグローバル変数を使った物に少しmodifyしたので、追記。
import tkinter import tkinter.filedialog import openpyxl import numpy as np #エクセルファイルを開く def openFile(event): global sheet global wb fileType = [("excel", "*.xlsx")] iDir = "/Users/Desktop/" filePath = tkinter.filedialog.askopenfilename(filetypes = fileType, initialdir = iDir) wb = openpyxl.load_workbook(filePath) sheet = wb.active getData() #ExcelファイルのDataを取得 def getData (): global u global sheet2 u = np.zeros((sheet.max_column, sheet.max_row)) for i in range(1, sheet.max_column+1): for j in range(1, sheet.max_row+1): u[i-1][j-1] = sheet.cell(row = j, column = i).value #Excelファイルを名前をつけて保存する def saveFile(event): wb.create_sheet(index=1, title="Copy") sheet2 = wb["Copy"] for i in range(1, sheet.max_column + 1): for j in range(1, sheet.max_row + 1): sheet2.cell(row=j, column=i).value = (u[i - 1][j - 1]) * 2 closePath = tkinter.filedialog.asksaveasfilename() wb.save(closePath+".xlsx") #GUIの作成およびボタンの設置 root = tkinter.Tk() root.title("Test") root.geometry("100x100") openButton = tkinter.Button(text = "Open", width = 25) saveButton = tkinter.Button (text = "Save", width = 25) openButton.bind("<Button-1>", openFile) saveButton.bind("<Button-1>", saveFile) openButton.pack() saveButton.pack() root.mainloop()
関数間で変数を共有できるように、global文を使った。
具体的には、下記の部分などである。
global u global sheet2
こうすることで、関数をまたいで変数を使える。
このコードを実行すると、のように2つのボタンがついたGUIが立ち上がり、OpenボタンでExcelファイルを呼び出し、Saveボタンで名前を付けて保存できるようにした。