今天我們來說明,如何使用GT.fmt_unit()
搭配define_units()
,在表格中任意component格式化各種單位。
GT.fmt_unit()
GT.fmt_units(self, columns=None, rows=None, pattern='{x}')
GT.fmt_unit()可以讓我們格式化各種單位。
其原理是我們可以透過一些預先定義的語法(以下簡稱為「"約定語法"」),來代表如上下標、溫度甚至化學單位。針對化學單位的部份,建議大家可以參考Richard所寫的部落格文章,裡面有一個完整的範例可以參考。
今天我會針對個人最常使用的上標與下標,以下面這個df
DataFrame為例來說明:
import polars as pl
from great_tables import GT, html, define_units
df = (
pl.DataFrame({"x": pl.arange(1, 6, eager=True)})
.with_columns(
a2=pl.col("x").add(10), a1=pl.col("x").add(20), a0=pl.col("x").add(30)
)
.with_columns(
y=(
pl.col("a2").mul(pl.col("x").pow(2))
+ pl.col("a1").mul(pl.col("x"))
+ pl.col("a0")
)
)
)
shape: (5, 5)
┌─────┬─────┬─────┬─────┬─────┐
│ x ┆ a2 ┆ a1 ┆ a0 ┆ y │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪═════╪═════╪═════╡
│ 1 ┆ 11 ┆ 21 ┆ 31 ┆ 63 │
│ 2 ┆ 12 ┆ 22 ┆ 32 ┆ 124 │
│ 3 ┆ 13 ┆ 23 ┆ 33 ┆ 219 │
│ 4 ┆ 14 ┆ 24 ┆ 34 ┆ 354 │
│ 5 ┆ 15 ┆ 25 ┆ 35 ┆ 535 │
└─────┴─────┴─────┴─────┴─────┘
我們可以使用GT.fmt_unit()
對整欄進行格式化。
舉例來說,我們可以建立一個「"sup"」欄位及一個「"sub"」欄位:
(
df.select(
"x",
sup=pl.col("x").cast(pl.Utf8).add("^sup"),
sub=pl.col("x").cast(pl.Utf8).add("_sub"),
)
)
shape: (5, 3)
┌─────┬───────┬───────┐
│ x ┆ sup ┆ sub │
│ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ str │
╞═════╪═══════╪═══════╡
│ 1 ┆ 1^sup ┆ 1_sub │
│ 2 ┆ 2^sup ┆ 2_sub │
│ 3 ┆ 3^sup ┆ 3_sub │
│ 4 ┆ 4^sup ┆ 4_sub │
│ 5 ┆ 5^sup ┆ 5_sub │
└─────┴───────┴───────┘
「"sup"」欄位是由「"x"」欄位轉換為pl.Utf8
格式後再加上^sup
所組成;而「"sub"」欄位則其是由「"x"」欄位轉換為pl.Utf8
格式後再加上_sub
所組成。
其中的^
就是約定語法中的上標語法,而^sup
就是代表將sup
置於上標位置。同理,_
是約定語法中的下標語法,而_sub
就是代表將sub
置於下標位置。
此時如果針對「"sup"」及「"sub"」欄位使用GT.fmt_unit()
,則此兩欄位將會以適當的上下標來呈現:
(
GT(
df.select(
"x",
sup=pl.col("x").cast(pl.Utf8).add("^sup"),
sub=pl.col("x").cast(pl.Utf8).add("_sub"),
)
)
.fmt_units(["sup", "sub"])
.cols_align(align="right", columns=["sup", "sub"])
)
約定語法也可以在GT.cols_label()中使用。
舉例來說,我們可以建立一個「"area"」欄位,其值為「"x"」欄位與「"y"」欄位相乘而來:
(df.with_columns(area=pl.col("x").mul(pl.col("y"))).select("x", "y", "area"))
shape: (5, 3)
┌─────┬─────┬──────┐
│ x ┆ y ┆ area │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ i64 │
╞═════╪═════╪══════╡
│ 1 ┆ 63 ┆ 63 │
│ 2 ┆ 124 ┆ 248 │
│ 3 ┆ 219 ┆ 657 │
│ 4 ┆ 354 ┆ 1416 │
│ 5 ┆ 535 ┆ 2675 │
└─────┴─────┴──────
此時,如果我們想針對各欄位名稱添加單位,可以使用約定語法(註1)。例如:
(
GT(
df.with_columns(area=pl.col("x").mul(pl.col("y"))).select(
"x", "y", "area"
)
).cols_label(x="x(m)", y="y(m)", area="area({{mm^2}})")
)
可以看到「"area"」欄位使用了約定語法{{mm^2}})
來標示平方符號。
約定語法也可以在GT.tab_spanner()中使用。例如:
(
GT(df)
.cols_label(a2="{{a_2}}", a1="{{a_1}}", a0="{{a_0}}")
.tab_spanner("y={{a_2}}{{x^2}}+{{a_1}}x+{{a_0}}", ["a2", "a1", "a0", "y"])
)
這裡我們使用約定語法來表達方程式中的多個變數及係數。
如果想要在其它component中使用約定語法的話,需要搭配define_units()
。define_units()是gt
提供的小工具,其有一個to_html()
方法,可以將傳入的約定語法轉換為HTML輸出。
舉例來說,在GT.tab_header()
中並不支援約定語法,所以下面這個表格的subtitle
呈現結果不甚理想:
❌
(
GT(df)
.cols_label(a2="{{a_2}}", a1="{{a_1}}", a0="{{a_0}}")
.tab_header(
title="Linear Algebra", subtitle="y={{a_2}}{{x^2}}+{{a_1}}x+{{a_0}}"
)
)
此時,我們可以利用define_units()
來幫忙,其步驟如下:
u2html()
來幫忙執行define_units().to_html()
。u2html()
包裹起來後,利用Python字串相加的功能來生成subtitle
。html()
函數來包裹subtitle
。def u2html(x) -> str:
return define_units(x).to_html()
subtitle = (
"y"
+ "="
+ u2html("{{a_2}}")
+ u2html("{{x^2}}")
+ "+"
+ u2html("{{a_1}}")
+ "x"
+ "+"
+ u2html("{{a_0}}")
)
(
GT(df)
.cols_label(a2="{{a_2}}", a1="{{a_1}}", a0="{{a_0}}")
.tab_header(title="Linear Algebra", subtitle=html(subtitle))
)
這麼一來,運用類似的技巧,我們將可以在任何component中使用約定語法來呈現表格。
註1:執筆之時,針對是否應該允許於column label中使用約定語法,gt
團隊正於PR#446討論中,或可能於未來變更此行為。