Skip to content

ENH: JSON output from Styler as well as DataFrame #36680

Open
@attack68

Description

@attack68

Currently there are ways of performing a to_json() method with the desired output formatting but the procedure is a bit cumbersome:

df = pd.DataFrame(data=[[1.9999, 1.9999, 1.9999, 1.9999, 1.99]], columns=['A', 'B', 'C', 'D', 'E'])
df['A'] = df['A'].apply(lambda x: float(f'{x:,.00f}'))
df['B'] = df['B'].apply(lambda x: int(f'{x:,.00f}'))
df['C'] = df['C'].apply(lambda x: f'{x:,.01f}')
print(df.to_json(double_precision=3))

{"A":{"0":2.0},
"B":{"0":2},
"C":{"0":"2.0"},
"D":{"0":2.0},
"E":{"0":1.99}}

The Styler has its own formatter which can make things a little more aesthetic, and has the advantage of not affecting the underlying data:

df = pd.DataFrame(data=[[1.9999, 1.9999, 1.9999, 1.9999, 1.99]], columns=['A', 'B', 'C', 'D', 'E'])
print(Styler(df, uuid="", precision=3).format({
    'A': lambda x: float(f'{x:,.00f}'),
    'B': lambda x: int(f'{x:,.00f}'),
    'C': '{:,.01f}'.format
}).render())
<tr>
     <th id="T_7e7fd_level0_row0" class="row_heading level0 row0" >0</th>
     <td id="T_7e7fd_row0_col0" class="data row0 col0" >2.0</td>
     <td id="T_7e7fd_row0_col1" class="data row0 col1" >2</td>
     <td id="T_7e7fd_row0_col2" class="data row0 col2" >2.0</td>
     <td id="T_7e7fd_row0_col3" class="data row0 col3" >2.000</td>
     <td id="T_7e7fd_row0_col4" class="data row0 col4" >1.990</td>
 </tr>

But Styler does not have a to_json() method.

Describe the solution you'd like

I would like to add a simple extension to the Styler to create JSON from the formatted Styler Object, in a similar way as it constructs HTML tables:

class Styler:
    ...
    def to_json(self, **kwargs):
                """
        Applies the ``:meth:DataFrame.to_json`` method to the ``Styler`` object
        including existing formats.

        Parameters
        ----------
        **kwargs
            Any additional keyword arguments are passed to ``DataFrame.to_json()``.
            Useful to control the output structure of the JSON return.

        Returns
        -------
        None or str

        Examples
        --------
        >>> df = pd.DataFrame(data=[[1.9999, 1.9999, 1.9999, 1.9999, 1.99]],
                              columns=['A', 'B', 'C', 'D', 'E'])
        >>> df.style.format({
        ...  'A': lambda x: float(f'{x:,.00f}'),
        ...  'B': lambda x: int(f'{x:,.00f}'),
        ...  'C': '{:,.01f}'.format
        ...  }).to_json()
        {"A":{"0":2.0},"B":{"0":2.0},"C":{"0":"2.0"},"D":{"0":"1.999900"}}
        """
        df = self.data.copy()
        for r in range(len(df.index)):
            for c in range(len(df.columns)):
                formatter = self._display_funcs[(r, c)]
                df.iloc[r, c] = formatter(self.data.iloc[r, c])
        return df.to_json(**kwargs)

API breaking implications

None - new feature
Might be useful to make some minor adjustments to Styler factory default formatter, but this is optional and can happen later.

Describe alternatives you've considered

  • Building a formatter for a DataFrame without using styler and applying to_json to that.
  • Adding a formatter argument to DataFrame.to_json which performs the necessary adjustments before

Since Styler is inherently a 'display' context component and specifically designed for the web I thought it more suitable to add to_json to the Styler object.

Opinions welcome.. I will probably submit a PR if consensus approval..

Metadata

Metadata

Assignees

No one assigned

    Labels

    EnhancementIO HTMLread_html, to_html, Styler.apply, Styler.applymapNeeds DiscussionRequires discussion from core team before further action

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions