mwouts / itables

Pandas DataFrames as Interactive DataTables
https://mwouts.github.io/itables/
MIT License
768 stars 56 forks source link

Incorrect Precision Repr #154

Closed mck-star-yar closed 1 year ago

mck-star-yar commented 1 year ago

I am trying to align the precision representation for the column and it doesn't work. Assume the following exmaple:

from itables import show

df = pd.Series([1.0, 1.123])
with pd.option_context("display.float_format", "{:.3f}".format):
    show(df)
It shows 0
1
1.123
But expected 0
1 .000
1.123

The issue seems to be in itables/datatables_format.py:: _format_column. After formatted input is cast to numpy array, it looses the formatting:

    if dtype_kind == "f":
        try:
            return np.array(x).astype(float)
        except ValueError:
            pass

removing this line preserves proper formatting.

itables version == '1.4.4'

mwouts commented 1 year ago

Hey @mck-star-yar , thanks for reporting this.

You're right, we convert formatted numbers back to numbers. The motive for doing so is to get the sorting right in datatables.

One option would be to do the formatting in Javascript, but I am not so sure this will really work. For instance, this example uses $ (i.e. jQuery), which is a global Javascript variable that we don't provide anymore. Let us know if you find a better way to do that on the Javascript side!

Maybe a more pragmatic approach would be an option floats_as_strings=False by default, both in itables.options and show, and you could set it to True to discard the conversion back to float?

mwouts commented 1 year ago

Actually the JS example might work! At least I see that we have a similar example in the docs and that one works: https://mwouts.github.io/itables/advanced_parameters.html#advanced-cell-formatting-with-js-callbacks

mck-star-yar commented 1 year ago

Unfortunately, I'm not writing in JS. Can you please provide a code snippet for this JS function?

I tried following the examples you shared, but those doesn't make much sense to me. Tried like this but it fails:

from itables import show, JavascriptFunction
import pandas as pd

df = pd.Series([1.0, 1.123])
with pd.option_context("display.float_format", "{:.3f}".format):
    show(
        df,
        columnDefs=[
            {"targets": 0, "render": "DataTable.render.number(',', '.', 1, '')"}
        ],
    )
mwouts commented 1 year ago

Indeed, you're right! The linked example uses JS code rather than a JS function.

I did some experiment with a new JavascriptCode class in the columns_render branch, and I have had some success with this:

pip install git+https://github.com/mwouts/itables.git@columns_render

and then

import pandas as pd
from itables import show
from itables import JavascriptCode

import math
show(pd.Series([i * math.pi * 1e4 for i in range(1, 6)]), columnDefs=[
        {
            "targets": "_all",
            "render": JavascriptCode("$.fn.dataTable.render.number(',', '.', 3, '$')"),
        }
    ])

image

This worked in Jupyter Lab, but it did not work in Jupyter Book (the JS errors are $.fn.dataTable is undefined and $.getQueryParameters is not a function).

This is very experimental and I have the feeling that passing a function rather than JS code might work better. I see here that render can as well be a function. @AllanJard, is it easy to write a function that applies the same formatting as dataTable.render.number?

AllanJard commented 1 year ago

The code for it is here if you wanted to basically the same thing.

mck-star-yar commented 1 year ago

@mwouts, the code works perfectly. Thanks a lot for such quick help! What is the ETA for this feature to get into the main branch?

mwouts commented 1 year ago

Thank you for your feedback! I just got the precious help of @fwouts and we were able to make this work for both the connected and the offline mode, so we're good to go...