iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Python

眾裏尋它:Python表格利器Great Tables系列 第 19

[Day19] - 範例1:天干地支西元年份對照表

  • 分享至 

  • xImage
  •  

從[Day19]~[Day23],我們將一起運用gt來製作四張生活化表格。
過程皆分為四大部份:

  1. 資料生成(或收集)。
  2. DataFrame製作。
  3. 表格製作。
  4. 結果輸出。

雖然gt開發者花費了很多時間精力在整合Polars,但是Pandas可是gt的起家厝,我們希望使用者能選擇自己喜歡的DataFrame來製作表格。

因此作為本系列文的第一個範例,我將和大家一起以Pandas搭配gt,來製作一張由1984~2043年的天干地支與西元年份的對照表(註1)。

本日成果預覽如下:
table

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')]

2. DataFrame製作

接著使用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)

dataFrame

分段說明如下:

  • 定義一個代表十組天干的列表,sky_cols
  • 定義一個assign_year()函數,其接收變數df_及變數data,功用是透過迴圈將data中的值更新給df_
  • 定義一個generate_df()函數,並接收data為變數:
    • 建立一個代表十二組地支的列表,land_index
    • 建立一個裡面都是「"-"」的DataFrame,其中天干為sky_cols,地支為land_index
    • 搭配DataFrame的pipe()及上面定義的assign_year()來指定正確的年份。
    • 最後,使用DataFrame的reset_index(),將index欄「擠入」DataFrame中作為第一欄,並給定欄位名「"地支"」。

3. 表格製作

在產生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函數,其會回傳一個TrueFalse交叉的Pandas Series。當回傳True時,該行的背景顏色將會被指定為「"#F4FAF1"」;False的話則維持原狀。
  • 呼叫GT.opt_stylize()導入gt提供的佈景主題,style參數設定為「4」,color參數則設為「"Blue"」。

4. 結果輸出

最後編寫一個_write_html()函數,其接收gtblfilename作為參數。其內透過呼叫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為當前所在的循環,故選其為製表材料。

Code

本日程式碼傳送門


上一篇
[Day18] - 核心思維
下一篇
[Day20] - 範例2:手搖飲品表(以COMEBUY為例)
系列文
眾裏尋它:Python表格利器Great Tables30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言