streamlit-elements icon indicating copy to clipboard operation
streamlit-elements copied to clipboard

DataGrid shows no table (only the arrows for switching pages)

Open yoeldk opened this issue 2 years ago • 7 comments

Hey Everyone, I tried running the following code (taken from the streamlit-gallery repo), but I cannot see any table (only the arrows for switching pages are shown). wondering what am I missing here:

import streamlit as st
from streamlit_elements import mui, elements

DEFAULT_COLUMNS = [
    { "field": 'id', "headerName": 'ID', "width": 90 },
    { "field": 'firstName', "headerName": 'First name', "width": 150, "editable": True, },
    { "field": 'lastName', "headerName": 'Last name', "width": 150, "editable": True, },
    { "field": 'age', "headerName": 'Age', "type": 'number', "width": 110, "editable": True, },
]

DEFAULT_ROWS = [
{ "id": 1, "lastName": 'Snow', "firstName": 'Jon', "age": 35 },
{ "id": 2, "lastName": 'Lannister', "firstName": 'Cersei', "age": 42 },
{ "id": 3, "lastName": 'Lannister', "firstName": 'Jaime', "age": 45 },
{ "id": 4, "lastName": 'Stark', "firstName": 'Arya', "age": 16 },
{ "id": 5, "lastName": 'Targaryen', "firstName": 'Daenerys', "age": None },
{ "id": 6, "lastName": 'Melisandre', "firstName": None, "age": 150 },
{ "id": 7, "lastName": 'Clifford', "firstName": 'Ferrara', "age": 44 },
{ "id": 8, "lastName": 'Frances', "firstName": 'Rossini', "age": 36 },
{ "id": 9, "lastName": 'Roxie', "firstName": 'Harvey', "age": 65 },
]

with elements("new_element"):
    mui.DataGrid(
                columns=DEFAULT_COLUMNS,
                rows = DEFAULT_ROWS,
                pageSize=5,
                checkboxSelection=True,
            )

yoeldk avatar Mar 09 '23 13:03 yoeldk

This code worked for me:

from streamlit_elements_fluence import elements, mui, html, sync, dashboard
import streamlit as st

st.title("Test")
columns = [
    {"field": "id", "headerName": "ID", "width": 70},
    {"field": "firstName", "headerName": "First name", "width": 130},
    {"field": "lastName", "headerName": "Last name", "width": 130},
    {
        "field": "age",
        "headerName": "Age",
        "type": "number",
        " width": 90,
    },
]

rows = [
    {"id": 1, "lastName": "Snow", "firstName": "Jon", "age": 35},
    {"id": 2, "lastName": "Lannister", "firstName": "Cersei", "age": 42},
    {"id": 3, "lastName": "Lannister", "firstName": "Jaime", "age": 45},
]
with elements("playground"):
    with mui.Box(sx={"height": 300}):
        mui.DataGrid(
            columns=columns,
            rows=rows,
            pageSize=2,
            checkboxSelection=True,
        )

Note the "mui.Box" surrounding the DataGrid

2023-03-09 15_37_05-Main · Streamlit - Personal - Microsoft​ Edge

acschofield avatar Mar 09 '23 14:03 acschofield

Thanks @acschofield that was super helpful! I have another question that is not directly related but wondered if you know the answer - any idea how to add links to that table ? TIA

yoeldk avatar Mar 09 '23 15:03 yoeldk

Not sure how to do that or even if it's possible with the python interface. In our application, the user selects a row and then presses one of the buttons below the table to take an action on that row. A bit clunky in UI terms but it may be a work around for you.

acschofield avatar Mar 09 '23 15:03 acschofield

That's also a possibility. Can you please share the code for doing that?

yoeldk avatar Mar 09 '23 16:03 yoeldk

It's part of a large application so it is difficult to share. But basically, you set a selection callback on the datagrid:

                    mui.DataGridPro(
                        columns=columns,
                        rows=rows,
                        checkboxSelection=False,
                        disableSelectionOnClick=False,
                        onSelectionModelChange=_handle_select, ...

Then in "_handle_select" you can store the selected row in session_state:

    def _handle_select(model) -> None:
        st.session_state.selected_item= model[0] if len(model) else None

selected_item gets the "id" of the selcted row.

Then in your button handling code you can reference st.session_state.selected_item and take some action-

acschofield avatar Mar 10 '23 08:03 acschofield

Thank you so much @acschofield

yoeldk avatar Mar 10 '23 08:03 yoeldk

class DataGrid(Dashboard.Item):
    DEFAULT_COLUMNS = [
        { "field": 'id', "headerName": 'ID', "width": 90 },
        { "field": 'firstName', "headerName": 'First name', "width": 150, "editable": True, },
        { "field": 'lastName', "headerName": 'Last name', "width": 150, "editable": True, },
        { "field": 'age', "headerName": 'Age', "type": 'number', "width": 110, "editable": True, },
    ]
    DEFAULT_ROWS = [
        { "id": 1, "lastName": 'Snow', "firstName": 'Jon', "age": 35 },
        { "id": 2, "lastName": 'Lannister', "firstName": 'Cersei', "age": 42 },
        { "id": 3, "lastName": 'Lannister', "firstName": 'Jaime', "age": 45 },
        { "id": 4, "lastName": 'Stark', "firstName": 'Arya', "age": 16 },
        { "id": 5, "lastName": 'Targaryen', "firstName": 'Daenerys', "age": None },
        { "id": 6, "lastName": 'Melisandre', "firstName": None, "age": 150 },
        { "id": 7, "lastName": 'Clifford', "firstName": 'Ferrara', "age": 44 },
        { "id": 8, "lastName": 'Frances', "firstName": 'Rossini', "age": 36 },
        { "id": 9, "lastName": 'Roxie', "firstName": 'Harvey', "age": 65 },
    ]


    def _handle_edit(self, params):
        print(params)


    def __init__(self, board, x, y, w, h, df=None, **item_props):
        super().__init__(board, x, y, w, h, **item_props)
        self.df = df

        if df is not None:
            self.columns = [{"field": col, "headerName": col, "width": 150, "editable": True} for col in df.columns]
        else:
            self.columns = self.DEFAULT_COLUMNS


    def __call__(self):
        if self.df is not None:
            self.df['id'] = range(1, len(self.df) + 1) # Create a unique id col to workaround ElementFrontendError
            data = self.df.to_dict('records')
        else:
            data = self.DEFAULT_ROWS

        with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
            with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
                mui.icon.ViewCompact()
                mui.Typography("Data grid")

            with mui.Box(sx={"flex": 1, "minHeight": 0}):
                mui.DataGrid(
                    columns=self.columns,
                    rows=data,
                    pageSize=5,
                    rowsPerPageOptions=[5],
                    checkboxSelection=True,
                    disableSelectionOnClick=True,
                    onCellEditCommit=self._handle_edit,
                )

Usage:

  from mui_elements.data_grid import DataGrid
  
  if 'w' not in state:
    board = Dashboard()
    
    w = SimpleNamespace(
      dashboard= board,
      table = DataGrid(board, 1,2,3,4, df=df), # your custom pd dataframe
    )
    state.w = w
  else:
    w = state.w

  with elements('ABC'):
    event.Hotkey("ctrl+s", sync(), bindInputs=True, overrideDefault=True)

    with w.dashboard(rowHeight=57):
      w.table()

neldivad avatar Oct 05 '23 11:10 neldivad