posit-dev / great-tables

Make awesome display tables using Python.
https://posit-dev.github.io/great-tables/
MIT License
1.42k stars 48 forks source link

WIP allow for granular section restyling via convenience api #341

Open timkpaine opened 1 month ago

timkpaine commented 1 month ago

Summary

This is a work-in-progress PR for allowing more granular styling of the various components via the API currently used for cell styling (e.g. loc.body()). The motivation is that it's often desired to style e.g. all column labels at once. It looks like this was already started in part (there are many TODOs such as these).

This PR is nowhere near done yet, so please don't approve CI running (it will just make noise).

Early Example:

from great_tables import GT, style, loc
from superstore import superstore

(
    GT(superstore(10))
    .tab_style(style=style.text(color="red"), locations=loc.column_labels())
)
Screenshot 2024-05-14 at 13 42 14

Checklist

timkpaine commented 1 month ago
Screenshot 2024-05-14 at 13 53 17
timkpaine commented 1 month ago
Screenshot 2024-05-14 at 14 09 07
machow commented 1 month ago

Hey, thanks for this incredibly comprehensive PR! At first I was nervous about the idea of a PR implementing all locations at once, but after seeing your changes, it seems very reasonable! Happy to kick the tires, help with anything :)

machow commented 1 month ago

Here's my quick attempt at mapping the Loc names here, to those used in the R library gt:

code ```python from great_tables import GT import polars as pl # I made this in a spreadsheet, then used pl.DataFrame.to_init_repr() :) df = pl.DataFrame( [ pl.Series("Location category", ['Header', 'Stubhead', 'Column labels', None, 'Stub elements', None, None, 'Body elements', None, 'Footer elements', None, None, None], dtype=pl.String), pl.Series("gt R package", ['cells_title', 'cells_stubhead', 'cells_column_labels', 'cells_column_spanners', 'cells_stub', 'cells_row_groups', 'cells_stub_summary', 'cells_body', 'cells_summary', 'cells_footnotes', 'cells_source_notes', 'cells_grand_summary', 'cells_stub_grand_summary'], dtype=pl.String), pl.Series("Great Tables", ['LocHeader', 'LocStubhead', 'LocColumnLabels*', 'LocSpannerLabel', 'LocStub', 'LocRowGroupLabel', 'LocSummaryLabel', 'LocBody', 'LocSummary', 'LocFootnotes', 'LocSourceNotes', None, None], dtype=pl.String), pl.Series("extra1", ['LocTitle', 'LocStubheadLabel', 'LocColumnLabel', None, 'LocRowLabel', None, None, None, None, 'LocFooter', None, None, None], dtype=pl.String), pl.Series("extra2", ['LocSubtitle', None, None, None, None, None, None, None, None, None, None, None, None], dtype=pl.String), ] ) GT(df).sub_missing(missing_text="") ```
image

It seems like you may have surfaced two important things:

  1. The R program sometimes maps to sub-locations. E.g. cells_title(groups=...) -> title or subtitle.
  2. If you just represent the sub-locations directly (e.g. your use of LocTitle and LocSubtitle), then they can be used directly. This seems like a nice simplification :).

Potentially replacing StyleInfo(loc="some_string")

It seems like defining all Loc sub-locations might also let us replace things like StyleInfo(loc="footnotes") with StyleInfo(loc=loc), where loc is the LocFootnotes object itself. Replacing all the string checks with isinstance would make it very easy to find references to Loc classes in VS Code, etc..!

In any event, this is looking really great! Thanks for this huge effort---I'm happy to check anything, do anything to support!