Gist Blog

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

Author
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.

Jun 13, 2022

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 :)

Author
Jun 13, 2022

@jfthuong thanks!

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

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

To make a comment, please visit this posts Gist.

Add your comment!