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)
Comments
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.
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 :)
@jfthuong thanks!
I put this functionality into a little library some time ago here.
Any chance you'd be up to submitting a PR?