Row Selection

Just as you can target specific columns, Great Tables also provides flexible ways to select rows. The rows= argument appears in formatting methods, location specifiers, and styling calls, allowing you to apply operations to a precise subset of your data. This page covers each of the available selection mechanisms.

Selection Options

Location and formatter functions (e.g. loc.body() and fmt_number()) can be applied to specific rows, using the rows= argument.

Rows may be specified using any of the following:

  • None (the default), to select everything.
  • an integer for the row’s position.
  • a list of or integers.
  • a Polars selector for filtering.
  • a function that takes a DataFrame and returns a boolean Series.

The following sections will use a subset of the exibble data, to demonstrate these options.

from great_tables import GT, exibble, loc, style

lil_exibble = exibble[["num", "char", "currency"]].head(3)
gt_ex = GT(lil_exibble)

Using integers

Use a single integer, or a list of integers, to select rows by position.

gt_ex.fmt_currency("currency", rows=0, decimals=1)
num char currency
0.1111 apricot $50.0
2.222 banana 17.95
33.33 coconut 1.39

Notice that a dollar sign ($) was only added to the first row (index 0 in python).

Indexing works the same as selecting items from a python list. This negative integers select relative to the final row.

gt_ex.fmt_currency("currency", rows=[0, -1], decimals=1)
num char currency
0.1111 apricot $50.0
2.222 banana 17.95
33.33 coconut $1.4

The first and last rows now show currency formatting, while the middle row remains unchanged. Negative indices count backward from the end, just as with Python lists.

Using polars expressions

The rows= argument accepts polars expressions, which return a boolean Series, indicating which rows to operate on.

For example, the code below only formats the num column, but only when currency is less than 40.

import polars as pl

gt_polars = GT(pl.from_pandas(lil_exibble))

gt_polars.fmt_integer("num", rows=pl.col("currency") < 40)
num char currency
0.1111 apricot 49.95
2 banana 17.95
33 coconut 1.39

Here’s a more realistic example, which highlights the row with the highest value for currency.

import polars.selectors as cs

gt_polars.tab_style(
    style.fill("yellow"),
    loc.body(
        columns=cs.all(),
        rows=pl.col("currency") == pl.col("currency").max()
    )
)
num char currency
0.1111 apricot 49.95
2.222 banana 17.95
33.33 coconut 1.39

The row with the maximum currency value is highlighted with a yellow background. Using expressions for row selection keeps the logic declarative and close to the styling call.

Using a function

Since libraries like pandas don’t have lazy expressions, the rows= argument also accepts a function for selecting rows. The function should take a DataFrame and return a boolean series.

Here’s the same example as the previous polars section, but with pandas data, and a lambda for selecting rows.

gt_ex.fmt_integer("num", rows=lambda D: D["currency"] < 40)
num char currency
0.1111 apricot 49.95
2 banana 17.95
33 coconut 1.39

Here’s the styling example from the previous polars section.

import polars.selectors as cs

gt_ex.tab_style(
    style.fill("yellow"),
    loc.body(
        columns=lambda colname: True,
        rows=lambda D: D["currency"] == D["currency"].max()
    )
)
num char currency
0.1111 apricot 49.95
2.222 banana 17.95
33.33 coconut 1.39

Whether you prefer integer indexing for quick positional access, Polars expressions for declarative filtering, or functions for compatibility with pandas, the rows= argument adapts to your data workflow. Combined with column selection, these tools give you fine-grained control over exactly which cells your formatting and styling operations affect.