從[Day19]~[Day23],我們將一起運用gt
來製作四張生活化表格。
過程皆分為四大部份:
雖然gt
開發者花費了很多時間精力在整合Polars,但是Pandas可是gt
的起家厝,我們希望使用者能選擇自己喜歡的DataFrame來製作表格。
因此作為本系列文的第一個範例,我將和大家一起以Pandas搭配gt
,來製作一張由1984~2043年的天干地支與西元年份的對照表(註1)。
本日成果預覽如下:
首先生成所需的資料:
from great_tables import GT, md, style, loc
from itertools import cycle
import pandas as pd
def generate_data() -> list[int, int, str]:
sky = cycle(range(10))
land = cycle(range(12))
year = (str(y) for y in range(1984, 1984 + 60))
return [(next(sky), next(land), next(year)) for _ in range(60)]
定義一個generate_data()
函數,其會建立一個data
列表,裡面共有六十個元組,每個元組內有三個元素,分別代表天干索引值、地支索引值及西元年份,像是:
[(0, 0, '1984'),
(1, 1, '1985'),
...
(8, 10, '2042'),
(9, 11, '2043')]
接著使用data
來製作DataFrame:
sky_cols = list("甲乙丙丁戊己庚辛壬癸")
def assign_year(df_: pd.DataFrame, data: list[int, int, str]) -> pd.DataFrame:
for col, row, year in data:
df_.iloc[row, col] = year
return df_
def generate_df(data) -> pd.DataFrame:
land_index = [
"子鼠(水)",
"丑牛(土中藏水)",
"寅虎(木)",
"卯兔(木)",
"宸龍(土中藏木)",
"巳蛇(火)",
"午馬(火)",
"未羊(土中藏火)",
"申猴(金)",
"酉雞(金)",
"戌狗(土中藏金)",
"亥豬(水)",
]
return (
pd.DataFrame(dict.fromkeys(sky_cols, "-"), index=land_index)
.pipe(assign_year, data)
.reset_index(names="地支")
)
data = generate_data()
df = generate_df(data)
分段說明如下:
sky_cols
。assign_year()
函數,其接收變數df_
及變數data
,功用是透過迴圈將data
中的值更新給df_
。generate_df()
函數,並接收data
為變數:
land_index
。sky_cols
,地支為land_index
。pipe()
及上面定義的assign_year()
來指定正確的年份。reset_index()
,將index欄「擠入」DataFrame中作為第一欄,並給定欄位名「"地支"」。在產生df
之後,以下面這段程式碼來製作gt
表格:
def make_gt(df: pd.DataFrame) -> GT:
return (
GT(df)
.tab_header("天干地支西元年份對照表")
.tab_options(table_background_color="#F1F1F1")
.tab_spanner(label="木", columns=["甲", "乙"])
.tab_spanner(label="火", columns=["丙", "丁"])
.tab_spanner(label="土", columns=["戊", "己"])
.tab_spanner(label="金", columns=["庚", "辛"])
.tab_spanner(label="水", columns=["壬", "癸"])
.tab_spanner(label=md("**天干**"), columns=sky_cols)
.cols_label(**{"地支": md("**地支**")})
.cols_align(align="center", columns=sky_cols)
.tab_style(
style=style.fill(color="#F4FAF1"),
locations=loc.body(
columns=df.columns.to_list(),
rows=lambda df_: pd.Series([True, False] * 6),
),
)
.opt_stylize(style=4, color="blue")
)
gtbl = make_gt(df)
定義一個make_gt()
函數,其接收df_
為參數並回傳GT
instance。內部程式分段說明如下:
GT.tab_header()
加入標題「"天干地支西元年份對照表"」。GT.tab_options()
設定表格背景顏色為「"#F1F1F1"」。GT.tab_spanner()
設定"金木水火土"共五個階層。GT.tab_spanner()
設定一個「天干」階層,請留意此階層比「"金木水火土"」階層還高一階級。GT.cols_label()
重新命名「"地支"」的欄位名。GT.cols_align()
設定全部欄位皆為中央對齊。GT.tab_style()
設定表格背景顏色。其中row
參數為一個lambda函數,其會回傳一個True
與False
交叉的Pandas Series。當回傳True
時,該行的背景顏色將會被指定為「"#F4FAF1"」;False
的話則維持原狀。GT.opt_stylize()
導入gt
提供的佈景主題,style
參數設定為「4」,color
參數則設為「"Blue"」。最後編寫一個_write_html()
函數,其接收gtbl
及filename
作為參數。其內透過呼叫gtbl.as_raw_html()
將製作好的表格輸出為HTML格式並寫入filename
檔案中。
output_filename = "cycle.html"
def _write_html(gtbl: GT, filename: str):
with open(filename, "w") as f:
f.write(gtbl.as_raw_html())
_write_html(gtbl, output_filename)
註1:天干分別為「甲乙丙丁戊己庚辛壬癸」十組,而地支分別為「子丑寅卯宸巳午未申酉戌亥」十二組,由甲子年至癸亥年每六十年作為一個循環(參考自維基百科-生肖姓名學)。1984~2043為當前所在的循環,故選其為製表材料。