Table (Great Tables)
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 410
## file: app.py
import pandas as pd
from great_tables import GT
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
app_ui = ui.page_fluid(output_gt("sales_table"), title="Great Tables")
def server(input, output, session):
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)
app = App(app_ui, server)
## file: requirements.txt
# Pinned below 0.22: 0.22.0 added a hard multimark dependency, which has no
# pure Python wheel and so cannot install under Pyodide.
great-tables<0.22import pandas as pd
from great_tables import GT
from great_tables.shiny import render_gt
from shiny.express import ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
ui.page_opts(title="Great Tables", fillable=True)
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)import pandas as pd
from great_tables import GT
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
app_ui = ui.page_fluid(output_gt("sales_table"), title="Great Tables")
def server(input, output, session):
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)
app = App(app_ui, server)Relevant Functions
-
great_tables.shiny.output_gt
output_gt(id, placeholder=False) -
great_tables.shiny.render_gt
render_gt(fn)
Details
Great Tables creates polished presentation tables with headers, annotations, value formatting, color scales, and targeted styles. Use a data grid instead when users need to sort, filter, select, or edit the data, or Table when a plain HTML table is enough.
Great Tables is a separate package, so install it with pip install great-tables alongside Shiny. Then:
- Build and return a
GTobject from a function decorated with@render_gt. - In Express, the decorated function creates its output automatically.
- In Core, add
output_gt("id")to the UI and give the decorated function the same name.
Shiny reruns the function whenever any reactive values it reads change, so the table can respond to inputs just like other outputs.
See the Great Tables user guide for the full set of formatting and styling options.
Variations
Header, spanners, and styling
Chain GT methods to add a stubhead and column spanner, relabel columns, color cells by value with .data_color(), and target specific cells with .tab_style().
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 300
## file: app.py
import pandas as pd
from great_tables import GT, loc, md, style
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"profit": [33000, 61000, 102000, 74000, 139000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
"growth": [0.08, 0.14, 0.21, -0.03, 0.27],
}
)
app_ui = ui.page_fluid(output_gt("sales_table"), title="Great Tables")
def server(input, output, session):
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(
title="Quarterly product performance",
subtitle="Revenue, profitability, and year-over-year growth",
)
.tab_stubhead(label="Product")
.tab_spanner(label="Financials", columns=["revenue", "profit", "margin"])
.cols_label(
revenue="Revenue", profit="Profit", margin="Margin", growth="YoY growth"
)
.fmt_currency(columns=["revenue", "profit"], decimals=0)
.fmt_percent(columns=["margin", "growth"], decimals=1)
.data_color(
columns="margin",
palette=["#f8d7da", "#fff3cd", "#d1e7dd"],
domain=[0.15, 0.35],
)
.tab_style(
style=[style.fill("#e7f5ff"), style.text(weight="bold")],
locations=loc.body(rows=[4]),
)
.opt_row_striping()
.tab_source_note(md("**Source:** Illustrative quarterly results"))
)
app = App(app_ui, server)
## file: requirements.txt
# Pinned below 0.22: 0.22.0 added a hard multimark dependency, which has no
# pure Python wheel and so cannot install under Pyodide.
great-tables<0.22import pandas as pd
from great_tables import GT, loc, md, style
from great_tables.shiny import render_gt
from shiny.express import ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"profit": [33000, 61000, 102000, 74000, 139000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
"growth": [0.08, 0.14, 0.21, -0.03, 0.27],
}
)
ui.page_opts(title="Great Tables", fillable=True)
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(
title="Quarterly product performance",
subtitle="Revenue, profitability, and year-over-year growth",
)
.tab_stubhead(label="Product")
.tab_spanner(label="Financials", columns=["revenue", "profit", "margin"])
.cols_label(
revenue="Revenue", profit="Profit", margin="Margin", growth="YoY growth"
)
.fmt_currency(columns=["revenue", "profit"], decimals=0)
.fmt_percent(columns=["margin", "growth"], decimals=1)
.data_color(
columns="margin",
palette=["#f8d7da", "#fff3cd", "#d1e7dd"],
domain=[0.15, 0.35],
)
.tab_style(
style=[style.fill("#e7f5ff"), style.text(weight="bold")],
locations=loc.body(rows=[4]),
)
.opt_row_striping()
.tab_source_note(md("**Source:** Illustrative quarterly results"))
)import pandas as pd
from great_tables import GT, loc, md, style
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"profit": [33000, 61000, 102000, 74000, 139000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
"growth": [0.08, 0.14, 0.21, -0.03, 0.27],
}
)
app_ui = ui.page_fluid(output_gt("sales_table"), title="Great Tables")
def server(input, output, session):
@render_gt
def sales_table():
return (
GT(sales, rowname_col="product")
.tab_header(
title="Quarterly product performance",
subtitle="Revenue, profitability, and year-over-year growth",
)
.tab_stubhead(label="Product")
.tab_spanner(label="Financials", columns=["revenue", "profit", "margin"])
.cols_label(
revenue="Revenue", profit="Profit", margin="Margin", growth="YoY growth"
)
.fmt_currency(columns=["revenue", "profit"], decimals=0)
.fmt_percent(columns=["margin", "growth"], decimals=1)
.data_color(
columns="margin",
palette=["#f8d7da", "#fff3cd", "#d1e7dd"],
domain=[0.15, 0.35],
)
.tab_style(
style=[style.fill("#e7f5ff"), style.text(weight="bold")],
locations=loc.body(rows=[4]),
)
.opt_row_striping()
.tab_source_note(md("**Source:** Illustrative quarterly results"))
)
app = App(app_ui, server)Reacting to inputs
Read a reactive value inside the decorated function and the table rebuilds whenever that value changes.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 300
## file: app.py
import pandas as pd
from great_tables import GT
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
app_ui = ui.page_fluid(
ui.input_slider("min_revenue", "Minimum revenue", 0, 500000, 0, step=50000),
output_gt("sales_table"),
title="Great Tables",
)
def server(input, output, session):
@render_gt
def sales_table():
subset = sales[sales["revenue"] >= input.min_revenue()]
return (
GT(subset, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)
app = App(app_ui, server)
## file: requirements.txt
# Pinned below 0.22: 0.22.0 added a hard multimark dependency, which has no
# pure Python wheel and so cannot install under Pyodide.
great-tables<0.22import pandas as pd
from great_tables import GT
from great_tables.shiny import render_gt
from shiny.express import input, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
ui.page_opts(title="Great Tables", fillable=True)
ui.input_slider("min_revenue", "Minimum revenue", 0, 500000, 0, step=50000)
@render_gt
def sales_table():
subset = sales[sales["revenue"] >= input.min_revenue()]
return (
GT(subset, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)import pandas as pd
from great_tables import GT
from great_tables.shiny import output_gt, render_gt
from shiny import App, ui
sales = pd.DataFrame(
{
"product": ["Essentials", "Plus", "Pro", "Teams", "Enterprise"],
"revenue": [184000, 267000, 352000, 296000, 421000],
"margin": [0.18, 0.23, 0.29, 0.25, 0.33],
}
)
app_ui = ui.page_fluid(
ui.input_slider("min_revenue", "Minimum revenue", 0, 500000, 0, step=50000),
output_gt("sales_table"),
title="Great Tables",
)
def server(input, output, session):
@render_gt
def sales_table():
subset = sales[sales["revenue"] >= input.min_revenue()]
return (
GT(subset, rowname_col="product")
.tab_header(title="Quarterly product performance")
.fmt_currency(columns="revenue", decimals=0)
.fmt_percent(columns="margin", decimals=1)
)
app = App(app_ui, server)