great_tables
  • Get Started
  • Examples
  • Reference
  • Blog
  1. Extra
  2. Extending Great Tables
  • Intro
  • Overview
  • Table Structure
    • Header and Footer
    • Stub (Row Labels)
    • Column Labels
  • Format
    • Formatting Values
    • Nanoplots
  • Style
    • Styling the Table Body
    • Styling the whole table
    • Colorizing with Data
  • Theming
    • Table Theme Options
    • Premade Themes
  • Selecting table parts
    • Column Selection
    • Row Selection
    • Location selection
  • Extra
    • Contributing Guidelines
    • Extending Great Tables

On this page

  • Writing an Add-on Function
    • Wrapping
    • Composing
    • Extending
  • Extending with Plots
  • Extending with Icons
  • Beyond
  1. Extra
  2. Extending Great Tables

Extending Great Tables

The Great Tables package boasts a diverse range of methods for creating beautiful tables. With no shortage of tools, styles, formats and themes, you can produce a very wide range of tables. If you haven’t yet, head over to the examples gallery for a flavor of the variety that is possible.

But what happens when there’s something you want to add to your table, and it’s not directly supported by Great Tables? Let’s say you have a very specific use case for your great table, so it’s not necessarily broad enough to contribute to the package. Or maybe it is generalizable, but implementing it is beyond the scope of your current project. Not every feature fits neatly into a pull request.

gt-extras is a great case study in this, filling your table desires that aren’t supported by Great Tables directly.

Writing an Add-on Function

When adding to Great Tables, you have three main approaches: wrapping, extending, and what we might call composing.

  • Wrapping is when you simplify existing functionality by bundling common parameter combinations. It doesn’t add new capabilities, instead makes specific or complex styling tasks more accessible.
  • Composing multiple methods into a single function, allowing you to build more complex table logic or reusable patterns.
  • Extending, on the other hand, adds new functionality by adding behavior beyond built-in methods. This could include processing data outside the package, or generating custom content (like HTML or images), that gets integrated into your table.

All approaches are valuable contributions to the Great Tables ecosystem, and the choice between them depends on whether you’re making it easier to access existing tooling or creating entirely new capabilities.

Wrapping

Let’s wrap tab_style() to perform a specific action supported by the general function. tab_style() takes locations= and style= parameters, so let’s assign those. Something this lightweight might be useful for someone who knows what effect they want, but doesn’t want to investigate the entire space of options for styling.

def highlight_cols(gt: GT, columns: SelectExpr) -> GT:
    locations = [
        loc.body(columns=columns),
        loc.column_labels(columns=columns),
    ]

    # Make the wrapped tab_style call
    return gt.tab_style(
        style=style.fill(color="lightblue"),
        locations=locations,
    )

In fact, many of the functions in gt-extras are wrappers. What you see above is pulled from the source code for the function gt_highlight_cols(), which is a wrapper function that doesn’t add new functionality to Great Tables, instead it makes a common action much easier.

Composing

A little more complex than wrapping, we can also compose methods to perform several steps, such as applying multiple styles, formatting, or themes all at once.

Here’s a flavor of the composed methods that gt-extras used in the ESPN theme:

def some_theme(gt: GT) -> GT:
    return (
        gt.opt_all_caps()
        .opt_table_font(
            font=google_font("Lato"),
            weight=400,
        )
        .opt_row_striping()
    )

This is where composing really shines. Maybe you want a very standardized look, or you want all of your tables to mimic your favorite one. Take advantage of tab_options() for your own premade themes, with styles from any of the table theme options of your choosing.

Extending

Perhaps the most complex, this involves new behavior not supported by Great Tables methods alone. Formatting values is a common way to do this:

def fmt_threshold(gt, columns, threshold: float):
    """Format values to 0 if they are under threshold.""""
    def _truncate(val: float)
        return "0" if val < threshold else str(val)

    return gt.fmt(_truncate, columns)

Alternatively, we can extend the post-processing step by building an HTML string containing two side-by-side tables. This function takes two separate GT objects, renders them as HTML using as_raw_html(), and then joins them in custom HTML structure, which would not be possible with Great Tables methods alone.

def double_table(gt1: GT, gt2: GT) -> str:
    table_1_html = gt1.as_raw_html()
    table_2_html = gt2.as_raw_html()

    return f"""<div>{table_1_html}</div><div>{table_2_html}</div>"""

Again, this is a sneak peek of the gt-extras function, gt_two_column_layout(), which does a little more heavy lifting than Great Tables itself supports. This time, we’re adding new behavior.

Extending with Plots

Embedded plots in tables (also known as sparklines) are a powerful tool. So much so that some plotting is already built in, called nanoplots. But there are endless plot types you could want in your great tables, and for these fmt() is your friend.

The key to adding custom plots to your tables is using fmt() with a function that converts your data values into visual representations. Your formatting function should take a value from your table and return an HTML string containing your plot – whether that’s an SVG, a series of styled <div> elements, or even embedded images.

Here’s a basic pattern for a plot extension:

def create_my_plot(value):
    # Transform the data value into a visual representation
    # This could use any plotting library or even pure HTML/CSS
    plot_html = f"<svg>...</svg>"  # Your plot generation logic here
    return plot_html


# Apply to your table
gt.fmt(fns=create_my_plot, columns="my_data_column")

Check out this blog post for a deeper dive into different approaches for creating plots in tables.

Extending with Icons

They say a picture is worth a thousand words. Maybe you want to take fmt_icon() and run with it, but with your own custom icon sets or specialized styling needs. For example:

  • Create domain-specific icon mappings: Automatically map data values to meaningful icons (like status indicators, ratings, or categories)
  • Apply custom styling: Add animations, colors, or hover effects to your icons

Here’s an example of how you might create a custom icon extension that maps numerical ratings to star icons:

def fmt_star_rating(filled_stars: int):
    star_html = "★" * filled_stars
    return f'<span style="color: gold; font-size: 18px;">{star_html}</span>'


# Apply to your table, again `fmt()` comes in handy!
gt.fmt(fns=fmt_star_rating, columns="my_data_column")

Beyond

For inspiration on ways to extend Great Tables, check out gt-extras and its source code.

Function Type
gt_plt_bar Extend
gt_color_box Extend
gt_data_color_by_group Wrap
gt_add_divider Wrap
gt_theme_538 Compose
Contributing Guidelines