Many Great Tables methods accept a columns= argument for targeting specific columns. Rather than limiting you to a simple list of column names, the package supports a flexible selection system that includes positional indexing, pattern-matching functions, and Polars selectors. This page demonstrates each of these approaches.
As your table-building code grows, hardcoding column names becomes fragile. If a column is renamed or added upstream, your table code breaks silently or raises an error. Pattern-based selection (whether through functions or Polars selectors) makes your code more resilient to upstream changes and more expressive about intent. Instead of listing every column by name, you can declare what kind of columns you want (e.g., all numeric columns, all columns starting with a prefix), and the selection adapts automatically as the data evolves.
Selection Options
The columns= argument for methods like tab_spanner(), cols_move(), and tab_style() allows a range of options for selecting columns.
The simplest approach is just a list of strings with the exact column names. However, we can specify columns using any of the following:
- a single string column name.
- an integer for the column’s position.
- a list of strings or integers.
- a Polars selector.
- a function that takes a string and returns
True or False.
from great_tables import GT
from great_tables.data import exibble
lil_exibble = exibble[["num", "char", "fctr", "date", "time"]].head(4)
gt_ex = GT(lil_exibble)
gt_ex
| num |
char |
fctr |
date |
time |
| 0.1111 |
apricot |
one |
2015-01-15 |
13:35 |
| 2.222 |
banana |
two |
2015-02-15 |
14:40 |
| 33.33 |
coconut |
three |
2015-03-15 |
15:45 |
| 444.4 |
durian |
four |
2015-04-15 |
16:50 |
This five-column table will serve as the basis for demonstrating each selection approach.
Using integers
We can use a list of strings or integers to select columns by name or position, respectively.
gt_ex.cols_move_to_start(columns=["date", 1, -1])
| date |
char |
time |
num |
fctr |
| 2015-01-15 |
apricot |
13:35 |
0.1111 |
one |
| 2015-02-15 |
banana |
14:40 |
2.222 |
two |
| 2015-03-15 |
coconut |
15:45 |
33.33 |
three |
| 2015-04-15 |
durian |
16:50 |
444.4 |
four |
Note the code above moved the following columns:
- The string
"date" matched the column of the same name.
- The integer
1 matched the second column (this is similar to list indexing).
- The integer
-1 matched the last column.
Moreover, the order of the list defines the order of selected columns. In this case, "data" was the first entry, so it’s the very first column in the new table.
Using Polars selectors
When using a Polars DataFrame, you can select columns using Polars selectors. The example below uses Polars selectors to move all columns that start with "c" or "f" to the start of the table.
import polars as pl
import polars.selectors as cs
pl_df = pl.from_pandas(lil_exibble)
GT(pl_df).cols_move_to_start(columns=cs.starts_with("c") | cs.starts_with("f"))
| char |
fctr |
num |
date |
time |
| apricot |
one |
0.1111 |
2015-01-15 |
13:35 |
| banana |
two |
2.222 |
2015-02-15 |
14:40 |
| coconut |
three |
33.33 |
2015-03-15 |
15:45 |
| durian |
four |
444.4 |
2015-04-15 |
16:50 |
In general, selection should match the behaviors of the Polars DataFrame.select() method.
pl_df.select(cs.starts_with("c") | cs.starts_with("f")).columns
See the Selectors page in the polars docs for more information on this.
Using functions
A function can be used to select columns. It should take a column name as a string and return True or False.
gt_ex.cols_move_to_start(columns=lambda x: "c" in x)
| char |
fctr |
num |
date |
time |
| apricot |
one |
0.1111 |
2015-01-15 |
13:35 |
| banana |
two |
2.222 |
2015-02-15 |
14:40 |
| coconut |
three |
33.33 |
2015-03-15 |
15:45 |
| durian |
four |
444.4 |
2015-04-15 |
16:50 |
To summarize when to reach for each approach: use a plain list of names when you know exactly which columns you want and the list is short. Use Polars selectors when you want to match by dtype, prefix, suffix, or other structural properties of the columns. Use a function when you need custom logic that doesn’t fit neatly into a selector (e.g., matching against an external list or applying a complex naming convention rule).
These selection methods work consistently across all Great Tables methods that accept a columns= argument. Whether you prefer explicit column names, positional indexing, Polars selectors, or custom functions, you can choose the approach that best fits your workflow and data.