jupyter-widgets / ipydatagrid

Fast Datagrid widget for the Jupyter Notebook and JupyterLab
BSD 3-Clause "New" or "Revised" License
559 stars 52 forks source link

Unable to distinguish between zero and NaN after editing #521

Open gdsutton opened 3 months ago

gdsutton commented 3 months ago

I am trying to have a column, formatted as a %, that can have both 0% and also appear blank if the user deletes the contents.

Currently, deleting the contents with the delete key continues to show 0% in the grid, despite the fact that the data behind it shows it as NaN. If I enter 0, it also shows as0% in the grid but in the data it shows as zero, I want to be able to have the delete key make the cell blank, which represents the fact that NaN is stored behind the scenes.

Apologies if there is an easy way to do this, have tried all sorts of vega expressions and the missing parameter (which appears to do nothing), I think the issue is less to do with the vega epression applied for formatting, and more to do with the fact that pressing delete leaves a zero in the grid cell without formatting, despite registering it as NaN in grid.data.


from ipydatagrid import DataGrid, TextRenderer, VegaExpr
import numpy as np
import pandas as pd

data = {
    'weight': [1, 2],
    'perc': [np.nan, 0.5]
}

df = pd.DataFrame(data)

vega_percent_fmt = """
                if(
                    !isValid(cell.value) | cell.value=='NaN' | cell.value==null,
                    ' ',
                    if(cell.value>=0, 
                        format(cell.value, ',.0f') + '%', 
                        ' ')
                )
            """

renderers = {
 "perc": TextRenderer(text_color="black", 
                    text_value=VegaExpr(vega_percent_fmt), # with and without this the cell formats as 0
                    horizontal_alignment="center",
                    missing='y',
                    ),}  

grid = DataGrid(
    df, base_row_size=20, base_column_size=150, renderers=renderers, editable=True, layout={"height": "200px"}
)

def on_change(e):
    print(grid.data)

grid.on_cell_change(on_change) 
grid

it is worth noting that when the grid renders, initially, the NaN value is rendered as blank which is what I want, the issue comes when a user enters a value, then later decides to remove it that there is no way to get back to blank that I can see.

Any help would be much appreciated, as is all work done so far, this is a really a great tool!

gdsutton commented 3 months ago

As is often the way, I have found a way around this within moments of posting, for others reference:

Making the grid rewrite the data to itself every time a change is detected gives me what I need, feel like there is probably a better way to do this, my grid is only small so performance isn's an issue.

vega_percent_fmt = """
        if(cell.value>=0, cell.value + '%', '  ')
"""

def on_change(e):
    dat = grid.data
    grid.data = dat

grid.on_cell_change(on_change) 
jgunstone commented 2 months ago

probs linked to this: https://github.com/bloomberg/ipydatagrid/issues/434