Skip to content

Instantly share code, notes, and snippets.

@avi-perl
Last active December 15, 2022 21:27
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save avi-perl/83e77d069d97edbdde188a4f41a015c4 to your computer and use it in GitHub Desktop.
Save avi-perl/83e77d069d97edbdde188a4f41a015c4 to your computer and use it in GitHub Desktop.
Convert a pandas.DataFrame object into a rich.Table object for stylized printing in Python.
from datetime import datetime
from typing import Optional
import pandas as pd
from rich import box
from rich.console import Console
from rich.table import Table
console = Console()
def df_to_table(
pandas_dataframe: pd.DataFrame,
rich_table: Table,
show_index: bool = True,
index_name: Optional[str] = None,
) -> Table:
"""Convert a pandas.DataFrame obj into a rich.Table obj.
Args:
pandas_dataframe (DataFrame): A Pandas DataFrame to be converted to a rich Table.
rich_table (Table): A rich Table that should be populated by the DataFrame values.
show_index (bool): Add a column with a row count to the table. Defaults to True.
index_name (str, optional): The column name to give to the index column. Defaults to None, showing no value.
Returns:
Table: The rich Table instance passed, populated with the DataFrame values."""
if show_index:
index_name = str(index_name) if index_name else ""
rich_table.add_column(index_name)
for column in pandas_dataframe.columns:
rich_table.add_column(str(column))
for index, value_list in enumerate(pandas_dataframe.values.tolist()):
row = [str(index)] if show_index else []
row += [str(x) for x in value_list]
rich_table.add_row(*row)
return rich_table
if __name__ == "__main__":
sample_data = {
"Date": [
datetime(year=2019, month=12, day=20),
datetime(year=2018, month=5, day=25),
datetime(year=2017, month=12, day=15),
],
"Title": [
"Star Wars: The Rise of Skywalker",
"[red]Solo[/red]: A Star Wars Story",
"Star Wars Ep. VIII: The Last Jedi",
],
"Production Budget": ["$275,000,000", "$275,000,000", "$262,000,000"],
"Box Office": ["$375,126,118", "$393,151,347", "$1,332,539,889"],
}
df = pd.DataFrame(sample_data)
# Initiate a Table instance to be modified
table = Table(show_header=True, header_style="bold magenta")
# Modify the table instance to have the data from the DataFrame
table = df_to_table(df, table)
# Update the style of the table
table.row_styles = ["none", "dim"]
table.box = box.SIMPLE_HEAD
console.print(table)
import pandas as pd
from rich.text import Text
from rich.console import Console
from rich.table import Table
console = Console()
def table_to_df(rich_table: Table) -> pd.DataFrame:
"""Convert a rich.Table obj into a pandas.DataFrame obj with any rich formatting removed from the values.
Args:
rich_table (Table): A rich Table that should be populated by the DataFrame values.
Returns:
DataFrame: A pandas DataFrame with the Table data as its values."""
table_data = {
x.header: [Text.from_markup(y).plain for y in x.cells] for x in table.columns
}
return pd.DataFrame(table_data)
if __name__ == "__main__":
# This example is taken from the rich documentation
table = Table(show_header=True, header_style="bold magenta")
table.add_column("Date", style="dim", width=12)
table.add_column("Title")
table.add_column("Production Budget", justify="right")
table.add_column("Box Office", justify="right")
table.add_row(
"Dec 20, 2019",
"Star Wars: The Rise of Skywalker",
"$275,000,000",
"$375,126,118",
)
table.add_row(
"May 25, 2018",
"[red]Solo[/red]: A Star Wars Story",
"$275,000,000",
"$393,151,347",
)
table.add_row(
"Dec 15, 2017",
"Star Wars Ep. VIII: The Last Jedi",
"$262,000,000",
"[bold]$1,332,539,889[/bold]",
)
# Show the rich Table
console.print(table)
# Convert the Table into a DataFrame
df = table_to_df(table)
print(df)
@avi-perl
Copy link
Author

avi-perl commented Oct 10, 2021

Now available as PyPI package!

This functionality is now available via a PyPI package!

$ pip install rich-tools

More information and example can be found in the package repository.

@jfthuong
Copy link

Cool Gist, man!

I would like to recommend an argument of maximum number of columns to display (otherwise, many columns might render terribly on the screen):

def df_to_table(
    df: pd.DataFrame,
    rich_table: Table,
    show_index: bool = True,
    index_name: Optional[str] = None,
    max_columns: Optional[int] = None,
) -> Table:
    """Convert a pandas.DataFrame obj into a rich.Table obj.
    Args:
        pandas_dataframe (DataFrame): A Pandas DataFrame to be converted to a rich Table.
        rich_table (Table): A rich Table that should be populated by the DataFrame values.
        show_index (bool): Add a column with a row count to the table. Defaults to True.
        index_name (str, optional): The column name to give to the index column. Defaults to None, showing no value.
    Returns:
        Table: The rich Table instance passed, populated with the DataFrame values."""

    if show_index:
        index_name = str(index_name) if index_name else ""
        rich_table.add_column(index_name)

    columns = df.columns[:max_columns] if max_columns else df.columns
    for column in columns:
        rich_table.add_column(str(column))

    for index, value_list in enumerate(df.values.tolist()):
        values = value_list[:max_columns] if max_columns else value_list
        row = [str(index)] if show_index else []
        row += [str(x) for x in values]
        rich_table.add_row(*row)

    return rich_table

Alternatively, we could also pass a list of columns to display as an argument.... (although in that case, it would be simpler to just pass df[my_selection_of_columns] to the function :)

@avi-perl
Copy link
Author

@jfthuong thanks!

I put this functionality into a little library some time ago here.

Any chance you'd be up to submitting a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment