置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2023年8月11日 星期五

使用 Python 讀取、寫入 ods 的套件 pyexcel-ods3

作者:王一哲
日期:2023年8月11日



前言


這幾天有一位大學的學長問到如何用 Python 寫 LibreOffice Calc 的巨集,但是目前網路上能找到的資料很少。後來學長想到另一個作法,不要寫巨集,只要用 Pythoon 程式從 ods 檔中讀取資料,在程式中處理完資料,再將資料寫入 ods 檔中,應該也能做到類似的效果。我在網路上找到一些套件,其中一個就是 pyexcel-ods3,經過測試後可以成功地讀取、寫入 ods 檔,以下是簡單的筆記。


安裝套件


如果只要處理 ods 檔,可以在命令列界面中輸入以下指令安裝套件
pip3 install pyexcel-ods3
如果還要處理其它格式的檔案,例如 xlsx,可以在命令列界面中輸入以下指令安裝套件
pip3 install pyexcel
由於處理資料時使用 NumPy ndarray 會比較方便,建議安裝 NumPy。
pip3 install numpy
雖然在以下的程式中會使用到 json 及 collections,但這兩個套件是預設的,不需要另外安裝。


基本語法


以下的程式碼中,假設已經引入函式庫
import pyexcel_ods3 as pe
import json
import numpy as np
from collections import OrderedDict


由 ods 檔讀取資料


語法為
輸入資料 = pe.get_data("檔名", start_row=索引值, row_limit=列數)
json.dumps(輸入資料)

  1. 如果 ods 檔與程式碼放在同一個資料夾中,可以只輸入檔名。
  2. start_row:從 0 開始算,如果 start_row=2 會從 ods 檔第3列開始讀取資料。
  3. row_limit:讀取資料列數。
  4. get_data 讀到的資料格式是 json,要用 json.dumps 將資料轉成 OrderedDict,key 值為分頁名稱,對應的 value 為二維 list。
  5. pyexcel 的概念是將一個分頁當作很大的二維陣列,所以讀取、寫入的分頁資料都會是二維 list,例如
    [[1], [2], [3]]  # 只有1欄、內容為1、2、3
    [[1, 2, 3]]      # 只有1列、內容為1、2、3
    


更新要寫入 ods 檔的資料


語法為
輸出資料 = OrderedDict()
輸出資料.update({"分頁名稱": 二維 list 資料})
資料格式是二維 list,如果使用 NumPy ndarray 會回傳錯誤訊息。將輸出資料寫入 ods 檔時會覆蓋掉原來的檔案內容,無法指定只寫入某個分頁,因此要記得將原來在檔案中的資料也用 update 加到輸出資料中。


將輸出資料寫入 ods 檔


語法為
save_data("檔名", 輸出資料)
如果執行程式時要寫入的 ods 檔已開啟,要先關閉再開啟 ods 檔才能看到寫入資料後的內容。


範例程式碼


由指定分頁讀取一欄資料,將處理後的資料寫到另一個分頁


假設檔案 test.ods 只有一個名為 Input 的分頁,只有 A 欄中有資料,資料為整數 1 到 10。以下的程式碼會從 Input 分頁讀取 A 欄資料,將資料存入 NumPy ndarray x,再將 x 乘以 2 之後存入 y,最後將 y 寫入 Output 分頁的 A 欄。
from pyexcel_ods3 import save_data, get_data
import json
import numpy as np
from collections import OrderedDict
# 由 ods 檔讀取並處理資料
dataIn = get_data("test.ods")
print(json.dumps(dataIn))
x = np.asarray([d[0] for d in dataIn["Input"]])
y = 2*x
x = x.reshape(len(x), 1).tolist()
y = y.reshape(len(y), 1).tolist()
# 將資料寫入 ods 檔
dataOut = OrderedDict()
dataOut.update({"Input": x})
dataOut.update({"Output": y})
save_data("test.ods", dataOut)

  1. 第8行:由於 dataIn["Input"] 的值為二維 list,先用 for 迴圈取出 d[0] 的資料,再用 np.asarray 轉成 NumPy ndarray 指定給變數 x。
  2. 第10、11行:如果 x、y 原來的長度為 N,先用 reshape 將 x、y 轉成 $N \times 1$ 的二維 ndarray,再用 tolist() 轉換成 list,最後分別指定給 x、y。
  3. 第16行:用 save_data() 將資料 dataOut 寫入 test.ods。


由指定分頁讀取2欄資料,將處理後的資料寫到另一個分頁


假設檔案 test2.ods 只有一個名為 Input 的分頁,A、B 欄中有皆資料。以下的程式碼會從 Input 分頁讀取 A、B 欄資料,將 A 欄資料存入 x,再將 x 乘以 2 之後存入 z;將 B 欄資料存入 y,再將 y 乘以 3 之後存入 a;最後將 z、a 寫入 Output 分頁的 A、B 欄。
輸入、輸出資料
Input A 欄 Input B 欄 Output A 欄 Output B 欄
1 0.1 2 0.3
2 0.2 4 0.6
3 0.3 6 0.9
4 0.4 8 1.2
5 0.5 10 1.5
6 0.6 12 1.8
7 0.7 14 2.1
8 0.8 16 2.4
9 0.9 18 2.7
10 1.0 20 3.0

import pyexcel_ods3 as pe
import json
import numpy as np
from collections import OrderedDict
# 由 ods 檔讀取並處理資料
dataIn = pe.get_data("test2.ods")
json.dumps(dataIn)
x = np.asarray([d[0] for d in dataIn["Input"]])
y = np.asarray([d[1] for d in dataIn["Input"]])
z = 2*x
a = 3*y
# 將資料寫入 ods 檔
dataOut = OrderedDict()
dataOut.update({"Input": list(zip(x.tolist(), y.tolist()))})
dataOut.update({"Output": list(zip(z.tolist(), a.tolist()))})
pe.save_data("test2.ods", dataOut)

大部分的程式碼與前一個範例相似,以下只說明第14、15行。由於 x、y、z、a 都是一維 ndarray,需要先轉成二維 list 才能加到 dataOut 當中,可以分為以下3個步驟:
  1. 用 tolist() 從 ndarray 轉換成 list。
  2. 用 zip() 將轉換後的兩個 list 依序取出元素,組成兩個一組的數組 (tuple)。
  3. 用 list() 將一連串的數組轉換成二維 list,例如 x、y 轉換後的資料為
    [(1, 0.1), (2, 0.2), (3, 0.3), (4, 0.4), (5, 0.5), (6, 0.6), (7, 0.7), (8, 0.8), (9, 0.9), (10, 1.0)]
    



結語


由於使用 LibreOffice Calc 的人比較少,想要用 Python 讀取、寫入 ods 檔的人更少,網路上相關的文章特別難找,希望這篇筆記能幫助到有需要的人。

參考資料


  1. pyexcel GitHub 頁面
  2. pyexcel 手冊
  3. pyexcel-ods3 PyPI 頁面




HackMD 版本連結:https://hackmd.io/@yizhewang/BkuKCQ722

沒有留言:

張貼留言