NCAS-CMS / NCAS-CMS/cf-python

HTML table construct inspection in Jupyter Notebooks

Open
#791 1 comment 1 reaction 1 assignee View on GitHub

@sadielbartholomew is already working on this.

Since Feb 19, 2020.

API review (4.0.0) enhancement
Dominant language
Python
Stars
150
Forks
23
Avg merge
1d 11h
Merged PRs (30d)
2

Description

IPython supports 'rich' display within Jupyter Notebooks (or see here for a great blog post about it), such that we could implement a _repr_html_ method in appropriate classes to output a real HTML table rather than the 'makeshift' tables we are constrained to returning in standard interpreter scenarios.

In particular, this would be beneficial to implement for any non-minimal-detail inspection call with a construct, e.g. for a field print(f) & f.dump(), as they can output a lot of information & we want it to be as easy as possible for users to pick out what they are interested in.

As well as the obvious separation of components in the output, with HTML tables you get basic cell shading & lines & bold text to make the output easier to digest. If we really wanted to push the boat out, we could even implement something more sophisticated to make rows or groups of them collapsible, as per the xarray example in the blog post linked above.

Demo

As a demonstration, I've coded up a basic tabular output for the minimal detail inspection of a field via (i.e. repr -> _repr_html_ for the field in notebooks). I used it simply to get a basic example to show and note I think a table is overkill for this context in practice; really I want to tabularise similarly the str and dump representations. The result (Out[3]):

table-cfdm-example

is produced by this example method inside the Field class:

def _repr_html_(self):
    """
    Outputs a HTML table representation within Jupyter notebooks.
    """
    # HTML tags to use to compose the table in HTML
    blank_table = '<table style="width:50%">{}</table>'
    blank_row_container = "<tr>{}</tr>"
    heading_row_content = "<th colspan='{}'>{}</th>"
    data_row_content = "<td>{}</td>"

    # Extract some info as processed otherwise into one_line_description
    x = [self._unique_domain_axis_identities()[axis] for axis in
         self.get_data_axes(default=())]
    axes_rows = [data_row_content.format(data) for data in x]

    # Construct and populate table
    type_of_construct = heading_row_content.format(
        1, str(self.__class__.__name__) + ":")
    identity_info = heading_row_content.format(
        len(axes_rows) - 1,
        "{} (units of {})".format(
            self.identity(''),
            self.get_property('units', None)
        )
    )
    heading_row = blank_row_container.format(
        type_of_construct + identity_info)

    return blank_table.format(heading_row + "".join(axes_rows))
Decisions to make

If we think this is a good idea, we should consider:

  • whether it is best to put the relevant methods here in cfdm, or in cf-python;
  • which inspection cases to implement a _repr_html_ for;
  • what format we want produced table outputs to be in each case (I think it best to develop a mock-up before coding any method up).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.