Skip to content

API Documentation

Basic usage

import pandas as pd
from pytabulator import TableOptions, render_data_frame
from shiny import render
from shiny.express import input, ui

ui.div("Click on row to print name", style="padding: 10px;")


@render.code
async def txt():
    print(input.tabulator_row_clicked())
    return input.tabulator_row_clicked()["Name"]


@render_data_frame(table_options=TableOptions(height=500))
def tabulator():
    return pd.read_csv(
        "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
    )

See also detailed example.

pytabulator.shiny_bindings

render_data_frame

Bases: Renderer[DataFrame]

A decorator for a function that returns a DataFrame

Parameters:

Name Type Description Default
table_options TableOptions

Table options.

{}
Source code in pytabulator/shiny_bindings.py
class render_data_frame(Renderer[DataFrame]):
    """A decorator for a function that returns a `DataFrame`

    Args:
        table_options (TableOptions): Table options.
    """

    def auto_output_ui(self) -> Tag:
        return output_tabulator(self.output_id)

    def __init__(
        self,
        _fn: ValueFn[DataFrame] = None,
        *,
        table_options: TableOptions | dict = {},
    ) -> None:
        super().__init__(_fn)
        self.table_options = table_options

    async def render(self) -> Jsonifiable:
        df = await self.fn()
        # return {"values": value.values.tolist(), "columns": value.columns.tolist()}
        # TODO: convert with js
        data = df_to_dict(df)
        data["options"] = jsonifiable_table_options(self.table_options)
        return data

render_tabulator

Bases: Renderer[Tabulator]

A decorator for a function that returns a Tabulator table

Source code in pytabulator/shiny_bindings.py
class render_tabulator(Renderer[Tabulator]):
    """A decorator for a function that returns a `Tabulator` table"""

    def auto_output_ui(self) -> Tag:
        return output_tabulator(self.output_id)

    async def transform(self, value: Tabulator) -> Jsonifiable:
        # return {"values": value.values.tolist(), "columns": value.columns.tolist()}
        # TODO: convert with js
        return value.to_dict()

output_tabulator(id)

Create an output container for a Tabulator table

Parameters:

Name Type Description Default
id str

An output id of a Tabulator table.

required
Source code in pytabulator/shiny_bindings.py
def output_tabulator(id: str):
    """Create an output container for a `Tabulator` table

    Args:
        id (str): An output id of a `Tabulator` table.
    """
    return ui.div(
        tabulator_dep(),
        tabulator_bindings_dep,
        id=resolve_id(id),
        class_="shiny-tabulator-output",
    )

pytabulator.utils

create_columns(df, default_filter=False, default_editor=False, updates={})

Create columns configuration from a data frame

Parameters:

Name Type Description Default
df DataFrame

The data frame to create columns from.

required
default_filter bool

Whether to add a default header filter to each column.

False
default_editor bool

Whether to add a default editor to each column.

False
updates dict

Dictionary of updates that overwrite the default settings or add additional settings the columns.

{}
Source code in pytabulator/utils.py
def create_columns(
    df: DataFrame,
    default_filter: bool = False,
    default_editor: bool = False,
    updates: dict = {},
) -> list:
    """Create columns configuration from a data frame

    Args:
        df (DataFrame): The data frame to create columns from.
        default_filter (bool): Whether to add a default header filter to each column.
        default_editor (bool): Whether to add a default editor to each column.
        updates (dict): Dictionary of updates that overwrite the default settings or add additional settings the columns.
    """
    # (hozAlign, headerFilter, editor)
    setup = [
        (
            ("right", "number", "number")
            if dtype in [int, float]
            else ("left", "input", "input")
        )
        for dtype in df.dtypes.tolist()
    ]
    columns = [
        {"title": column, "field": column, "hozAlign": setup[i][0]}
        for i, column in enumerate(df.columns)
    ]

    if default_filter:
        for i, column in enumerate(columns):
            column["headerFilter"] = setup[i][1]

    if default_editor:
        for i, column in enumerate(columns):
            column["editor"] = setup[i][2]

    for key in updates:
        for column in columns:
            if column["field"] == key:
                column.update(updates[key])

    return columns

pytabulator.tabulator

Tabulator

Bases: object

Tabulator

Parameters:

Name Type Description Default
df DataFrame

A data frame.

required
table_options TableOptions

Table options.

{}
Source code in pytabulator/tabulator.py
class Tabulator(object):
    """Tabulator

    Args:
        df (DataFrame): A data frame.
        table_options (TableOptions): Table options.
    """

    def __init__(
        self,
        df: DataFrame,
        table_options: TableOptions | dict = {},
    ) -> None:
        self.df = df
        # self.table_options = table_options
        self._table_options = jsonifiable_table_options(table_options)

    def options(self, **kwargs) -> Tabulator:
        self._table_options.update(kwargs)
        return self

    def to_dict(self) -> dict:
        data = df_to_dict(self.df)
        # data["options"] = jsonifiable_table_options(self.table_options)
        data["options"] = self._table_options
        return data

pytabulator.tabulator_context

TabulatorContext

Bases: object

Table context

Source code in pytabulator/tabulator_context.py
class TabulatorContext(object):
    """Table context"""

    def __init__(self, id: str, session: Session = None) -> None:
        self.id = id
        self._session = require_active_session(session)
        self._message_queue = []

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.render()

    async def render(self):
        await self._session.send_custom_message(
            f"tabulator-{self.id}", {"id": self.id, "calls": self._message_queue}
        )

    def add_call(self, method_name: str, *args) -> None:
        """Add a method call that is executed on the table instance

        Args:
            method_name (str): The name of the method to be executed.
            *args (any): The arguments to be passed to the table method.
        """
        call = [method_name, args]
        self._message_queue.append(call)

    def trigger_download(
        self, type: Literal["csv", "json", "xlsx"] = "csv", file_name: str = None, *args
    ) -> None:
        """Trigger download

        Args:
            type (str): The data type of the file to be downloaded.
            file_name (str): The file name.
            *args (any): The arguments to be passed to the `table.download` method.
        """
        if not file_name:
            file_name = f"tabulator-data.{type}"

        self.add_call("download", type, file_name, *args)

    def add_row(self, row: dict = {}) -> None:
        """Add a row to the table

        Args:
            row (dict): Row data to add.
        """
        self.add_call("addRow", row)

    def delete_row(self, index: int | str) -> None:
        """Delete a row from the table

        Args:
            index: The index of the row to delete.
        """
        self.add_call("deleteRow", index)

    def delete_selected_rows(self) -> None:
        """Delete selected rows from table"""
        self.add_call("deleteSelectedRows")

    def undo(self) -> None:
        """Trigger undo"""
        self.add_call("undo")

    def redo(self) -> None:
        """Trigger redo"""
        self.add_call("redo")

    def trigger_get_data(self) -> None:
        """Trigger sending data"""
        self.add_call("getData")

add_call(method_name, *args)

Add a method call that is executed on the table instance

Parameters:

Name Type Description Default
method_name str

The name of the method to be executed.

required
*args any

The arguments to be passed to the table method.

()
Source code in pytabulator/tabulator_context.py
def add_call(self, method_name: str, *args) -> None:
    """Add a method call that is executed on the table instance

    Args:
        method_name (str): The name of the method to be executed.
        *args (any): The arguments to be passed to the table method.
    """
    call = [method_name, args]
    self._message_queue.append(call)

add_row(row={})

Add a row to the table

Parameters:

Name Type Description Default
row dict

Row data to add.

{}
Source code in pytabulator/tabulator_context.py
def add_row(self, row: dict = {}) -> None:
    """Add a row to the table

    Args:
        row (dict): Row data to add.
    """
    self.add_call("addRow", row)

delete_row(index)

Delete a row from the table

Parameters:

Name Type Description Default
index int | str

The index of the row to delete.

required
Source code in pytabulator/tabulator_context.py
def delete_row(self, index: int | str) -> None:
    """Delete a row from the table

    Args:
        index: The index of the row to delete.
    """
    self.add_call("deleteRow", index)

delete_selected_rows()

Delete selected rows from table

Source code in pytabulator/tabulator_context.py
def delete_selected_rows(self) -> None:
    """Delete selected rows from table"""
    self.add_call("deleteSelectedRows")

redo()

Trigger redo

Source code in pytabulator/tabulator_context.py
def redo(self) -> None:
    """Trigger redo"""
    self.add_call("redo")

trigger_download(type='csv', file_name=None, *args)

Trigger download

Parameters:

Name Type Description Default
type str

The data type of the file to be downloaded.

'csv'
file_name str

The file name.

None
*args any

The arguments to be passed to the table.download method.

()
Source code in pytabulator/tabulator_context.py
def trigger_download(
    self, type: Literal["csv", "json", "xlsx"] = "csv", file_name: str = None, *args
) -> None:
    """Trigger download

    Args:
        type (str): The data type of the file to be downloaded.
        file_name (str): The file name.
        *args (any): The arguments to be passed to the `table.download` method.
    """
    if not file_name:
        file_name = f"tabulator-data.{type}"

    self.add_call("download", type, file_name, *args)

trigger_get_data()

Trigger sending data

Source code in pytabulator/tabulator_context.py
def trigger_get_data(self) -> None:
    """Trigger sending data"""
    self.add_call("getData")

undo()

Trigger undo

Source code in pytabulator/tabulator_context.py
def undo(self) -> None:
    """Trigger undo"""
    self.add_call("undo")

pytabulator.TableOptions dataclass

Bases: TableOptions

Table options

Attributes:

Name Type Description
add_row_pos Literal['bottom', 'top']

Where to add rows. Defaults to "bottom".

columns list

Column definitions.

frozen_rows int

Number of frozen rows. Defaults to Ǹone.

group_by Union[str, list]

Columns to group by. Defaults to None.

header_visible bool

Whether to display the header of the table. Defaults to True.

height Union[int, None]

The height of the table in pixels. Defaults to 311.

history bool

Whether to enable history. Must be set if undo and redo is used. Defaults to False.

index str

The field to be used as a unique index for each row. Defaults to "id".

layout Literal['fitData', 'fitDataFill', 'fitDataStretch', 'fitDataTable', 'fitColumns']

The layout of the table. Defaults to "fitColumns".

movable_rows bool

Whether rows are movable. Defaults to False.

pagination_add_row Literal['page', 'table']

Where to add rows when pagination is enabled. Defaults to "page".

pagination bool

Whether to enable pagination. Defaults to False.

pagination_counter str

Whether to display counted rows in footer. Defaults to "rows".

resizable_column_fit bool

Maintain total column width when resizing a column. Defaults to False.

row_height int

Fixed height for rows. Defaults to None.

selectable_rows Union[str, bool, int]

Whether a row is selectable. An integer value sets the maximum number of rows, that can be selected. If set to "highlight", rows do not change their state when they are clicked. Defaults to "highlight".

Source code in pytabulator/_table_options_dc.py
@dataclass
class TableOptionsDC(TableOptions):
    """Table options

    Attributes:
        add_row_pos: Where to add rows. Defaults to `"bottom"`.
        columns: Column definitions.
        frozen_rows: Number of frozen rows. Defaults to `Ǹone`.
        group_by: Columns to group by. Defaults to `None`.
        header_visible: Whether to display the header of the table. Defaults to `True`.
        height: The height of the table in pixels. Defaults to `311`.
        history: Whether to enable history. Must be set if `undo` and `redo` is used. Defaults to `False`.
        index: The field to be used as a unique index for each row. Defaults to `"id"`.
        layout: The layout of the table. Defaults to `"fitColumns"`.
        movable_rows: Whether rows are movable. Defaults to `False`.
        pagination_add_row: Where to add rows when pagination is enabled. Defaults to `"page"`.
        pagination: Whether to enable pagination. Defaults to `False`.
        pagination_counter: Whether to display counted rows in footer. Defaults to `"rows"`.
        resizable_column_fit: Maintain total column width when resizing a column. Defaults to `False`.
        row_height: Fixed height for rows. Defaults to `None`.
        selectable_rows: Whether a row is selectable. An integer value sets the maximum number of rows, that can be selected.
            If set to `"highlight"`, rows do not change their state when they are clicked. Defaults to `"highlight"`.
    """

    add_row_pos: Literal["bottom", "top"] = "bottom"
    columns: list = None
    frozen_rows: int = None
    group_by: Union[str, list] = None
    header_visible: bool = True
    height: Union[int, None] = 311
    history: bool = False
    index: str = "id"
    layout: Literal[
        "fitData", "fitDataFill", "fitDataStretch", "fitDataTable", "fitColumns"
    ] = "fitColumns"
    movable_rows: bool = False
    pagination_add_row: Literal["page", "table"] = "page"
    pagination: bool = False
    pagination_counter: str = "rows"
    resizable_column_fit: bool = False
    row_height: int = None
    selectable_rows: Union[str, bool, int] = "highlight"

    def to_dict(self):
        return asdict(
            self,
            dict_factory=lambda x: {
                snake_to_camel_case(k): v for (k, v) in x if v is not None
            },
        )