Skip to content

Events and triggers

Events

Tabulator for Python provides the following reactive inputs:

  • input.{output_id}_row_clicked event: Sends the data of the clicked row.
  • input.{output_id}_row_edited event: Sends the data of the edited row. This event is fired each time a cell of the row is edited.
  • input.{output_id}_rows_selected event: Sends the data of all selected rows. This event is fired each time a new row is selected.
  • input.{output_id}_data event: Sends the complete data of the table. This event must be triggered from Shiny.
  • input.{output_id}_data_filtered event: Sends data of filtered rows. This event is triggered each time a filter is applied.
from shiny import render
from pandas import read_csv
from pytabulator import render_data_frame


# in this case (Shiny Express) the function name corresponds to the 'output_id'
# output_id = "tabulator"
#
# on-row-clicked event: input.tabulator_row_clicked
# on-row-edited event: input.tabulator_row_edited
#
@render_data_frame
def tabulator():
    return read_csv("https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv")


# row-on-click event
#
@render.code
async def txt():
    print(input.tabulator_row_clicked())
    return input.tabulator_row_clicked()["Name"]


# row-edited event
#
@render.code
def row_edited():
    data = input.tabulator_row_edited()
    print(data)
    return f"{data['Name']}, {data['Sex']}"

Triggers

With TabulatorContext you can trigger events on the table object. TabulatorContext must be used in an async function:

from shiny import reactive
from shiny.express import ui
from pytabulator import TabulatorContext

ui.input_action_button("trigger_download", "Download")
ui.input_action_button("add_row", "Add row")


# Trigger download of csv file
#
@reactive.Effect
@reactive.event(input.trigger_download)
async def trigger_download():
    print("download triggered")
    async with TabulatorContext("tabulator") as table:
        table.trigger_download("csv")


# Add a row to the table
#
@reactive.Effect
@reactive.event(input.add_row)
async def add_row():
    async with TabulatorContext("tabulator") as table:
        table.add_row({"Name": "Hans", "Sex": "male"})

Detailed example

from random import randrange

import pandas as pd
from pytabulator import TableOptions, Tabulator, TabulatorContext, render_tabulator
from pytabulator.utils import create_columns
from shiny import reactive, render
from shiny.express import input, ui

# Fetch data
#
df = pd.read_csv(
    "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
)[["PassengerId", "Name", "Pclass", "Sex", "Age", "Fare", "Survived"]]

# Setup
#
table_options = TableOptions(
    columns=create_columns(
        df,
        default_filter=True,
        default_editor=True,
        updates={
            "Pclass": {
                "formatter": "star",
                "formatterParams": {"stars": 3},
                "hozAlign": "center",
            },
            "Survived": {"formatter": "tickCross"},
            "Fare": {"formatter": "progress", "hozAlign": "left"},
        },
    ),
    height=413,
    pagination=True,
    pagination_add_row="table",
    layout="fitColumns",
    index="PassengerId",
    add_row_pos="top",
    selectable_rows=True,
    history=True,
)

# Shiny Express App
#
with ui.div(style="padding-top: 0px;"):
    ui.input_action_button("trigger_download", "Download")
    ui.input_action_button("add_row", "Add row")
    ui.input_action_button("delete_selected_rows", "Delete selected rows")
    ui.input_action_button("undo", "Undo")
    ui.input_action_button("redo", "Redo")
    ui.input_action_button("trigger_get_data", "Submit data")

ui.div(
    ui.input_text("name", "Click on 'Add row' to add the Person to the table."),
    style="padding-top: 20px;",
)
ui.div("Click on a row to print the name of the person.", style="padding: 10px;"),


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


ui.div(
    "Select multiple rows to print the names of the selected persons.",
    style="padding: 10px;",
),


@render.code
def selected_rows():
    data = input.tabulator_rows_selected()
    output = [item["Name"] for item in data]
    return "\n".join(output)


@render_tabulator
def tabulator():
    return Tabulator(df, table_options).options(
        editTriggerEvent="dblclick"
    )  # .options(selectableRows=True)


@reactive.Effect
@reactive.event(input.trigger_download)
async def trigger_download():
    print("download triggered")
    async with TabulatorContext("tabulator") as table:
        table.trigger_download("csv")


@reactive.Effect
@reactive.event(input.add_row)
async def add_row():
    async with TabulatorContext("tabulator") as table:
        table.add_row(
            {
                "Name": input.name() or "Hans",
                "Age": randrange(55),
                "Survived": randrange(2),
                "PassengerId": randrange(10000, 20000, 1),
                "SibSp": randrange(9),
            }
        )


@reactive.Effect
@reactive.event(input.delete_selected_rows)
async def delete_selected_rows():
    async with TabulatorContext("tabulator") as table:
        table.delete_selected_rows()


@reactive.Effect
@reactive.event(input.undo)
async def undo():
    async with TabulatorContext("tabulator") as table:
        table.undo()


@reactive.Effect
@reactive.event(input.redo)
async def redo():
    async with TabulatorContext("tabulator") as table:
        table.redo()


@reactive.Effect
@reactive.event(input.trigger_get_data)
async def trigger_get_data():
    async with TabulatorContext("tabulator") as table:
        table.trigger_get_data()


@reactive.Effect
@reactive.event(input.tabulator_data)
def tabulator_data():
    print(input.tabulator_data()[0])