Skip to content

feat: add the tab_footnote() method #763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 40 commits into
base: main
Choose a base branch
from
Draft

Conversation

rich-iannone
Copy link
Member

@rich-iannone rich-iannone commented Aug 12, 2025

This PR adds the tab_footnote() method which allows you to add footnotes for different locations in the table. The method integrates footnote mark placement into the rendering pipeline for table headings, column labels, body cells, etc., and extends the internal data structures and options to support footnote config.

Here's an example of how this works in practice:

import polars as pl
from great_tables import GT, loc, md, html
from great_tables.data import towny

tbl_data = (
    pl.from_pandas(towny)
    .filter(pl.col('csd_type') == 'city')
    .select(['name', 'density_2021', 'population_2021', 'density_2016', 'population_2016'])
    .top_k(8, by='population_2021')
    .sort('population_2021', descending=True)
    .with_columns([
        ((pl.col('population_2021') - pl.col('population_2016')) / pl.col('population_2016') * 100).round(1).alias('pop_change'),
        ((pl.col('density_2021') - pl.col('density_2016')) / pl.col('density_2016') * 100).round(1).alias('density_change')
    ])
)

(
    GT(tbl_data, rowname_col='name')
    .tab_header(
        title=md('Ontario Cities: **2016 vs 2021 Census Data**'),
        subtitle='Comparison of population and density changes over 5 years.'
    )
    .tab_stubhead(label='Municipality')
    .tab_spanner(label='2016 Census', columns=['population_2016', 'density_2016'])
    .tab_spanner(label='2021 Census', columns=['population_2021', 'density_2021'])
    .tab_spanner(label='5-Year Change', columns=['pop_change', 'density_change'])
    .fmt_integer(columns=['population_2016', 'population_2021'])
    .fmt_number(columns=['density_2016', 'density_2021'], decimals=1)
    .fmt_number(columns=['pop_change', 'density_change'], decimals=1)
    .cols_label(
        population_2016='Population',
        density_2016='Density',
        population_2021='Population',
        density_2021='Density',
        pop_change='Population (%)',
        density_change='Density (%)'
    )
    .tab_footnote(
        footnote='Data taken from the census.',
        locations=loc.title()
    )
    .tab_footnote(
        footnote='Municipality names as they appear in the census.',
        locations=loc.stubhead()  # Test stubhead footnote
    )
    .tab_footnote(
        footnote='Population and density figures from the 2016 Census.',
        locations=loc.spanner_labels(ids=['2016 Census'])
    )
    .tab_footnote(
        footnote='Population and density figures from the 2021 Census.',
        locations=loc.spanner_labels(ids=['2021 Census'])
    )
    .tab_footnote(
        footnote='Percentage change calculated as ((2021 - 2016) / 2016) × 100.',
        locations=loc.spanner_labels(ids=['5-Year Change'])
    )
    .tab_footnote(
        footnote='Density measured in persons per square kilometer.',
        locations=loc.column_labels(columns=['density_2016', 'density_2021'])
    )
    .tab_footnote(
        footnote='Part of the Greater Toronto Area.',
        locations=loc.stub(rows=['Toronto', 'Brampton', 'Mississauga'])
    )
    .tab_footnote(
        footnote='Highest population growth in this dataset.',
        locations=loc.body(columns='pop_change', rows=3)
    )
    .tab_source_note(
        source_note = md("Data taken from the `towny` dataset (originally from the **gt** package).")
    )
)

And here is how it looks:

image

Fixes: #164

Copy link

codecov bot commented Aug 12, 2025

Codecov Report

❌ Patch coverage is 92.15116% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.70%. Comparing base (5196b53) to head (6b58300).

Files with missing lines Patch % Lines
great_tables/_utils_render_html.py 92.59% 18 Missing ⚠️
great_tables/_locations.py 89.70% 7 Missing ⚠️
great_tables/_footnotes.py 92.30% 1 Missing ⚠️
great_tables/_text.py 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #763      +/-   ##
==========================================
+ Coverage   91.43%   91.70%   +0.26%     
==========================================
  Files          47       47              
  Lines        5547     5868     +321     
==========================================
+ Hits         5072     5381     +309     
- Misses        475      487      +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 03:54 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 03:58 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 13:41 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 19:58 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 20:00 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 21:06 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 12, 2025 22:10 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 14:48 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 16:00 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 16:25 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 16:38 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 16:45 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 17:39 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 17:51 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 18:09 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 18:35 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 18:48 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 18:53 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 18:59 Destroyed
@github-actions github-actions bot temporarily deployed to pr-763 August 13, 2025 19:08 Destroyed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

epic: Implement footnotes
1 participant