Ag-Grid component with input support

when I replace the function:

def get_data():
    df = pd.DataFrame(
        np.random.randint(0, 100, 100).reshape(-1, 5), columns=list("abcde")
    )
    return df

[/quote]

when I replace the function:

def get_data():
    df = pd.read_csv("myfile.csv")
    return df

input function is just disappear.
Do you know why?

Has anyone managed to implement grid detail? as shown here: master-detail-grids

Is there a way to use AgGrid to populate an empty table and use it as user input?

Hello,

Is there a way to give the application multiple update_mode_value ? @PablocFonseca
I want the table to update when the selection changes and also when value changes.

Thanks,

I just found the solution in the code.


Thanks for this amazing package !

@PablocFonseca many thanks… as many others have commented, this is a great component!

Is there a way to register new/custom gridOptions components? I am trying to figure out how to replicate https://blog.ag-grid.com/binding-boolean-values-to-checkboxes-in-ag-grid/#vanilla-javascript to bind a boolean field to a checkbox within Streamlit.

Thanks again,
JT

Just as an FYI to my previous post on Master-Detail. I have not solved it, but have made progress. See code sniped:

import streamlit as st 
from st_aggrid import AgGrid, GridOptionsBuilder, JsCode
import pandas as pd

df = pd.DataFrame({
        'group': [1,1,2,2],
        'x': [1,2,3,4],
        'y': [1,2,3,4],
    })

getDetailRowData = JsCode('''function(e) {
            let rowData = [
                { make: "Toyota", model: "Celica", price: 35000 },
                { make: "Ford", model: "Mondeo", price: 32000 },
                { make: "Porsche", model: "Boxter", price: 72000 }
                ];
            e.successCallback(rowData)
        };''')

gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_columns('group', cellRenderer='agGroupCellRenderer')

go = gb.build()
go['masterDetail'] = True
go['detailCellRendererParams'] = {
    'detailGridOptions':{
        'columnDefs':[
            {'field':'make'},
            {'field':'model'},
            {'field':'price'}
        ]
    },
    'getDetailRowData': getDetailRowData
}

AgGrid(df, theme='streamlit', allow_unsafe_jscode=True, 
       gridOptions=go, enable_enterprise_modules=True
)

This results in:

I guess next on my list is to figure out how to leverage the content of e (the input to the getDetalRowData Js function) to dynamically change the detail table shown.

@sis , You have managed to find a way to interactively delete rows. Is there a way to delete multiple selected rows at one go?

Thanks in advance.

Hi @Shawn_Pereira,

a possible solution is in the below snippet (it uses multiple rows selection of AgGrid + streamlit button press to submit deletion request).

Snippet
import string

import numpy as np
import pandas as pd
import streamlit as st
from st_aggrid import AgGrid, GridOptionsBuilder, GridUpdateMode

st.set_page_config(layout='wide')

def display_table(df: pd.DataFrame) -> AgGrid:
    # Configure AgGrid options
    gb = GridOptionsBuilder.from_dataframe(df)
    gb.configure_selection('multiple', use_checkbox=True) 
    return AgGrid(
        df,
        gridOptions=gb.build(),
        # this override the default VALUE_CHANGED
        update_mode=GridUpdateMode.MODEL_CHANGED
    )


# Define dummy data
rng = np.random.default_rng(2021)
N_SAMPLES = 100
N_FEATURES = 10
df = pd.DataFrame(rng.integers(0, N_SAMPLES, size=(
    N_SAMPLES, N_FEATURES)), columns=list(string.ascii_uppercase[:N_FEATURES]))

# Display data and selected rows
left, right = st.columns(2)
with left:
    st.info("Select rows to be deleted")
    response = display_table(df)
with right:
    st.warning("Rows selected for deletion")
    rows_to_delete = pd.DataFrame(response['selected_rows'])
    st.write(rows_to_delete)

# Delete rows on button press
if st.button("Delete rows") and not rows_to_delete.empty:
    # Lookup table is needed because AgGrid does not return rows indices
    lookup = df.merge(rows_to_delete, on=list(df.columns), how='left', indicator=True)
    _df = df.drop(lookup[lookup['_merge'] == 'both'].index)
    st.success('Rows deleted')
    st.write(_df)
1 Like

Many thanks @sis , I will try your method.

God bless.

Loving your work Pablo. Fantastic!

I’m pretty new to all this and was hoping you could help me with something?
I can format columns (ie comma separated numbers, font color etc) but can’t seem to apply this formatting to the aggregated totals when grouping. Am I just missing something simple?

Any help hugely appreciated.

Thanks

Hi @PablocFonseca

Is it possible for editable data to be written back again to the data frame again ?

For example, let’s say
df = pd.read_csv(“file.csv”)
gb = GridOptionsBuilder.from_dataframe(df )
gb.configure_default_column(groupable=True, value=True, enableRowGroup=True, aggFunc=“sum”, editable=True)

In the ag grid table, I edit a cell, how do I returned the edited cell value to dataframe ? If possible also overwrite to file.csv ?

Hi,

Thanks for this excellent component, @PablocFonseca. I have one big problem that prevents me from using this component. When I click on the column hamburger to popup the filter, I cannot have the popup go away if I click on the hamburger again or just move the mouse away. How can I make the popup go away without any other side effect (such as clicking on another column causes the popup to go away but it sorts the table by that column now)?

Thanks again and wishing you a lovely and festive end of the year.

Dinesh

Hi @PablocFonseca,
Thanks for the amazing work on this streamlit component.
I was wondering if it possible to apply css style to the header just like it is possible with the cells ? Maybe I missed the parameter that I need to use but honestly didn’t find any.
Thanks for your help and thanks again for your work on this !

1 Like

Ag-Grid for Streamlit is very helpful! I will use it in my project.

I have just begun to play around with this component and so far it has been great. Perhaps I am missing something but does anyone know how to set a valueFormatter for numeric and datetime columns such that NaN and NaT data respectively show up as blank cells? I am able to do it by injecting some conditional formatting code but I imagine there is a better way.

Any help would be great!

After looking at @mkleinbort 's code for enabling other functionality in aggrid and looking at aggrid’s documentation, I found that I could color rows using the following code snippet:

            jscode = JsCode("""
            function(params) {
                if (params.data.state === 'failed') {
                    return {
                        'color': 'white',
                        'backgroundColor': 'red'
                    }
                }
            };
            """)
            
            gridOptions = gb.build()
            gridOptions['getRowStyle'] = jscode

            grid_response = AgGrid(
                df,
                gridOptions=gridOptions,
                allow_unsafe_jscode=True,
           )

where df is the dataframe.

There are more recommended ways to do row styling, but this was a simple one to start with, given my lack of javascript experience.

Hope this helps,

Dinesh

1 Like

Is there a way to wrap header titles in the tables? I was able to wrap cell contents but couldn’t find an option to wrap header titles? Is that feature supported by streamlit_aggrid?

Native Aggrid seems to support it like here: Text Wrapping in ag-Grid Column Headers & Cells

Thanks.

Did you try to set headerComponentParams in grid options, like the example you sent?

you can use gridBuilder.configure_default_column(headerComponentParams=…) for this

Thank you! That worked. Was able to also right align the wrapped header titles (instead of the default left align).

The final config worked to wrap headers like so:

gb.configure_default_column(
        floating_filter=True,
        min_column_width=10,
        maxWidth=110,
        headerComponentParams={
            "template":
                '<div class="ag-cell-label-container" role="presentation">' +
                '  <span ref="eMenu" class="ag-header-icon ag-header-cell-menu-button"></span>' +
                '  <div ref="eLabel" class="ag-header-cell-label" role="presentation">' +
                '    <span ref="eSortOrder" class="ag-header-icon ag-sort-order"></span>' +
                '    <span ref="eSortAsc" class="ag-header-icon ag-sort-ascending-icon"></span>' +
                '    <span ref="eSortDesc" class="ag-header-icon ag-sort-descending-icon"></span>' +
                '    <span ref="eSortNone" class="ag-header-icon ag-sort-none-icon"></span>' +
                '    <span ref="eText" class="ag-header-cell-text" role="columnheader" style="white-space: normal;text-align: right;"></span>' +
                '    <span ref="eFilter" class="ag-header-icon ag-filter-icon"></span>' +
                '  </div>' +
                '</div>'
        }   
    )