Format values as mixed fractions.
GT.fmt_fraction(
columns=None,
rows=None,
accuracy="low",
simplify=True,
layout="inline",
use_seps=True,
pattern="{x}",
sep_mark=",",
locale=None,
)
With numeric values in a gt table, we can perform mixed-fraction-based formatting. There are several options for setting the accuracy of the fractions. Furthermore, there is an option for choosing a layout (i.e., typesetting style) for the mixed-fraction output.
The accuracy= parameter controls the type of fractions generated. It can be one of the keywords "low", "med", or "high" (to generate fractions with denominators of up to 1, 2, or 3 digits, respectively) or an integer value greater than zero to obtain fractions with a fixed denominator (2 yields halves, 3 is for thirds, 4 is quarters, etc.). If choosing to provide a numeric value for accuracy=, the option to simplify the fraction (where possible) can be taken with simplify=True (the default for this is True).
For HTML output, the "inline" layout (the default) places the numerals of the fraction on the baseline and uses a standard slash character. The "diagonal" layout will generate fractions that are typeset with raised and lowered numerals and a virgule (i.e., a fraction slash).
Parameters
columns: SelectExpr = None
-
The columns to target. Can either be a single column name or a series of column names provided in a list.
rows: int | list[int] | None = None
-
In conjunction with columns=, we can specify which of their rows should undergo formatting. The default is all rows, resulting in all rows in targeted columns being formatted. Alternatively, we can supply a list of row indices.
accuracy: str | int = "low"
-
The accuracy of the fraction. Use "low" for denominators up to 1 digit (e.g., halves, thirds, quarters, etc.), "med" for up to 2-digit denominators, and "high" for up to 3-digit denominators. Alternatively, supply a positive integer to fix the denominator to that value (e.g., accuracy=8 gives eighths). The default is "low".
simplify: bool = True
-
When accuracy= is an integer, should the fraction be simplified via GCD reduction? For while simplify=False yields "2/4". Has no effect when accuracy= is a keyword example, with accuracy=4 and a value of 0.5, simplify=True yields a "1/2" string representation. The default is True.
layout: str = "inline"
-
The layout of the fraction. "inline" renders the fraction on the baseline with a standard slash (e.g., 3/4). "diagonal" renders a diagonal fraction with a raised numerator, lowered denominator, and a fraction slash character (HTML only and falls back to inline in other contexts). The default is "inline".
use_seps: bool = True
-
Whether to use digit grouping separators in the whole-number part. The default is True.
pattern: str = "{x}"
-
A formatting pattern that allows for decoration of the formatted value. The formatted value is represented by the {x} (which can be used multiple times, if needed) and all other characters will be interpreted as string literals.
sep_mark: str = ","
-
The mark to use as a thousands separator. The default is "," and can be overridden by a locale setting.
locale: str | None = None
-
An optional locale ID that can be used for applying a locale-specific thousands separator.
Returns
GT
-
The GT object is returned. This is the same object that the method is called on so that we can facilitate method chaining.
Examples
Let’s format the num column of the exibble dataset as fractions with the default "low" accuracy.
from great_tables import GT
from great_tables.data import exibble
(
GT(exibble[["num", "char"]])
.fmt_fraction(columns="num")
)
| num |
char |
| 1/9 |
apricot |
| 2 2/9 |
banana |
| 33 1/3 |
coconut |
| 444 2/5 |
durian |
| 5,550 |
None |
| None |
fig |
| 777,000 |
grapefruit |
| 8,880,000 |
honeydew |
We can increase the accuracy to "med" or "high" for more precise fractions. We can also use a fixed denominator (here, tenths) to get uniform fractions. With simplify=False, the denominator stays fixed even when the fraction could be reduced, and layout="diagonal" gives us a typeset diagonal-fraction style.
import polars as pl
df = pl.DataFrame({
"item": ["Icate", "Octyl", "Sepal", "Unkel"],
"frac_sales": [0.3, 0.1, 0.8, 0.5],
"frac_revenue": [0.2, 0.4, 0.7, 0.9],
})
(
GT(df, rowname_col="item")
.fmt_fraction(
columns=["frac_sales", "frac_revenue"],
accuracy=10,
simplify=False,
layout="diagonal",
)
)
|
frac_sales |
frac_revenue |
| Icate |
3⁄10 |
2⁄10 |
| Octyl |
1⁄10 |
4⁄10 |
| Sepal |
8⁄10 |
7⁄10 |
| Unkel |
5⁄10 |
9⁄10 |
The pizzaplace dataset has a full year of sales data. We can summarize the sell count and revenue by pizza size within each type, then express those as fractions. Using layout="diagonal" with accuracy=10 and simplify=False gives uniform tenths in a typeset style, and text_transform() replaces any zero-fraction values with nil.
import polars as pl
import polars.selectors as cs
from great_tables import md, loc, data
grouped = (
data.pl.pizzaplace
.group_by("type", "size")
.agg(
pl.col("id").count().alias("sold"),
pl.col("price").sum().alias("income"),
)
.with_columns(
(pl.col("sold") / pl.col("sold").sum().over("type")).alias("f_sold"),
(pl.col("income") / pl.col("income").sum().over("type")).alias("f_income"),
)
.sort(["type", "income"], descending=[False, True])
)
(
GT(grouped, rowname_col="size", groupname_col="type")
.tab_header(
title="Pizzas Sold in 2015",
subtitle="Fraction of Sell Count and Revenue by Size per Type",
)
.fmt_integer(columns="sold")
.fmt_currency(columns="income")
.fmt_fraction(
columns=cs.starts_with("f_"),
accuracy=10,
simplify=False,
layout="diagonal",
)
.sub_missing(missing_text="")
.tab_spanner(label="Sold", columns=cs.contains("sold"))
.tab_spanner(label="Revenue", columns=cs.contains("income"))
.text_transform(
locations=loc.body(),
fn=lambda x: "<em>nil</em>" if x == "0" else x,
)
.cols_label(
sold="Amount",
income="Amount",
f_sold=md("_f_"),
f_income=md("_f_"),
)
.cols_align(align="center", columns=cs.starts_with("f"))
.tab_options(
table_width="400px",
row_group_as_column=True,
)
)
| Pizzas Sold in 2015 |
| Fraction of Sell Count and Revenue by Size per Type |
|
Sold
|
Revenue
|
| Amount |
f |
Amount |
f |
| chicken |
L |
4,932 |
4⁄10 |
$102,339.00 |
5⁄10 |
| M |
3,894 |
4⁄10 |
$65,224.50 |
3⁄10 |
| S |
2,224 |
2⁄10 |
$28,356.00 |
1⁄10 |
| classic |
L |
4,057 |
3⁄10 |
$74,518.50 |
3⁄10 |
| S |
6,139 |
4⁄10 |
$69,870.25 |
3⁄10 |
| M |
4,112 |
3⁄10 |
$60,581.75 |
3⁄10 |
| XL |
552 |
nil |
$14,076.00 |
1⁄10 |
| XXL |
28 |
nil |
$1,006.60 |
nil |
| supreme |
L |
4,564 |
4⁄10 |
$94,258.50 |
5⁄10 |
| M |
4,046 |
3⁄10 |
$66,475.00 |
3⁄10 |
| S |
3,377 |
3⁄10 |
$47,463.50 |
2⁄10 |
| veggie |
L |
5,403 |
5⁄10 |
$104,202.70 |
5⁄10 |
| M |
3,583 |
3⁄10 |
$57,101.00 |
3⁄10 |
| S |
2,663 |
2⁄10 |
$32,386.75 |
2⁄10 |