Skip to content

the table regionยค

a first sketch of adding interactive controls to the table. the controls use the @property to define the types making our variables ammenable to animations.

overall, the concept of flat table is for the uninspired. here we create experiment with perspective and z positioning. these approaches will be live you are holding and moving through data rather than a boring as single position.

its not a bad first sketch and it tells a story moving forward.

jump to the demo

%reload_ext nbconvert_a11y.repr
from nbconvert_a11y.repr import get_table, TableOptions, new
from nbconvert_a11y.table import init_table

df = DataFrame(numpy.random.randn(2, 6), columns=pandas.MultiIndex.from_product([range(2), range(3)], names=["x", "y"]))
df = df.reindex(df.columns)
df[:] = numpy.random.randn(*df.shape)
%%
<figure>
<figcaption>
our basis for a dataframe table includes containers for captions, data, interface controls, style, and interactivity.
these design decisions were made it enhance the accessibility and assistiveness (ie labor reduction) of exploring information.                                    
    </figcaption>

```html
{{init_table("xx").prettify()}}
```
</figure> 

&gt; originally this research started focusing on notebooks. we wound up making them tables with controls in a very similar
way that is described here. the notebook use case confirms a need for a richer set of semantics around tables.


<style>
a[href="#demo"] {
    display: block;
    height: 300px;
    width: 400px;
    background: -moz-element(#demo);
    background-size: content;
    background-repeat: no-repeat;
    font-size: 4rem;
}
</style>
our basis for a dataframe table includes containers for captions, data, interface controls, style, and interactivity. these design decisions were made it enhance the accessibility and assistiveness (ie labor reduction) of exploring information.
<section aria-labelledby="xx-figcaption">
 <figure>
  <figcaption id="xx-figcaption">
  </figcaption>
  <table id="xx" role="table">
   <caption id="xx-caption">
   </caption>
  </table>
 </figure>
 <form aria-labelledby="xx-figcaption" name="xx">
 </form>
 <style id="xx-style">
 </style>
 <script id="xx-script">
 </script>
</section>

originally this research started focusing on notebooks. we wound up making them tables with controls in a very similar way that is described here. the notebook use case confirms a need for a richer set of semantics around tables.

Table is a first pass at a more fluent interface for working with html tables.

@dataclass
class Table:
    object: object
    options: TableOptions = field(default_factory=TableOptions)
    repr: bs4.Tag = None
    id: str = None

    def build(self, *args, **kwargs):
        self.repr = get_table(self.object, self.options, *args, **kwargs)
        self.id = self.repr.figure.table.attrs["id"]
        return self

    def _repr_html_(self):
        if self.repr:
            return self.repr.prettify()
%%
initialize and build the `Table` as <var>self</var>

    self = table = Table(df)
    self.options.axis = self.options.Axis.column
    self.build(id="demo")

add an explicit caption to the table which describes the context the dataframe is being used in.
the implicit caption lives on the `self.repr.figure.table.caption` which describes the type and shape
of the table.

    self.repr.figure.figcaption.append(new("q", "a random ass dataframe"))

{{table.repr}}

starting defining css properties and styles for the table.

    self.repr.style.append(
```text/css
@property --dir {
    syntax: "<number>";
    inherits: true;
    initial-value: 1;
}
@property --rotate {
    syntax: "<number>";
    inherits: true;
    initial-value: 0;
}
@property --depth {
    syntax: "<length>";
    inherits: true;
    initial-value: 3in;
}
@property --distance {
    syntax: "<length>";
    inherits: true;
    initial-value: 6in;
}
@property --angle {
    syntax: "<length>";
    inherits: true;
    initial-value: 50%;
}
form label {
    display: block;
}
table[id] {
    margin: 10em;
    transform: rotateY(calc(1deg*var(--rotate)));
    transform-style: preserve-3d;
    transition: all 1s linear;
    tbody {
        transform-style: preserve-3d;
        tr {
            transform-style: preserve-3d;
            perspective: var(--distance);
            perspective-origin: var(--angle);
            transition: all 1s linear;
            background: unset !important;
            td {
                transform-style: preserve-3d;
                transition: all 1s linear;
                transform: translateZ(calc(var(--dir) * var(--val) * var(--depth))) rotateY(calc(-1deg*var(--rotate)));
            }
        }
    }
}


```
    )  

use long form to add the controls so we can visually identify some of the patterns
between the css properties and input types and changes.

    self.repr.form.extend((
        new(
            "label", "depth", 
            new("input", type="number", min=0, max=12, step=.5, value=3, name="depth", 
                onchange=\
                """document.getElementById("%s").style.setProperty("--depth", `${document.forms["%s"].elements.depth.value}in`);""" % (self.id, self.id)
               ), "inches"
        ),
        new(
            "label", "distance", 
            new("input", type="number", min=0, max=12, step=.5, value=3, name="distance", 
                onchange=\
                """document.getElementById("%s").style.setProperty("--distance", `${document.forms["%s"].elements.distance.value}in`);""" % (self.id, self.id)
               ), "inches"
        ),
        new(
            "label", "angle", 
            new("input", type="number", min=0, max=100, step=2, value=50, name="angle", 
                onchange=\
                ("""document.getElementById("%s").style.setProperty("--angle", `${document.forms["%s"].elements.angle.value}""" % (self.id, self.id))  + "%`);"
               ), "%"
        ), 
        new("label", "direction", new("input", type="number", min=-1, max=1, step=2, value=1, name="dir", onchange=\
            """document.getElementById("%s").style.setProperty("--dir", document.forms["%s"].elements.dir.value);""" % (self.id, self.id)                        
                        ),)
    ))

initialize and build the Table as self

self = table = Table(df)
self.options.axis = self.options.Axis.column
self.build(id="demo")

add an explicit caption to the table which describes the context the dataframe is being used in. the implicit caption lives on the self.repr.figure.table.caption which describes the type and shape of the table.

self.repr.figure.figcaption.append(new("q", "a random ass dataframe"))
a random ass dataframe
pandas dataframe with 6 rows, 6 columns with 2 index levels and 2 columns levels.
x000111
y012012
001.3290.0090.166-0.159-0.857-0.729
01-0.3171.786-0.281-0.811-0.842-0.096
02-1.7810.1521.152-0.7230.1500.993
101.7931.2280.034-0.721-1.0252.279
11-1.094-0.0130.6420.334-0.738-0.695
12-0.9801.5571.666-0.663-0.051-2.366
min-1.781-0.013-0.281-0.811-1.025-2.366
max1.7931.7861.6660.3340.1502.279
diff3.5751.7991.9461.1451.1754.646

starting defining css properties and styles for the table.

self.repr.style.append(
@property --dir {
    syntax: "<number>";
    inherits: true;
    initial-value: 1;
}
@property --rotate {
    syntax: "<number>";
    inherits: true;
    initial-value: 0;
}
@property --depth {
    syntax: "<length>";
    inherits: true;
    initial-value: 3in;
}
@property --distance {
    syntax: "<length>";
    inherits: true;
    initial-value: 6in;
}
@property --angle {
    syntax: "<length>";
    inherits: true;
    initial-value: 50%;
}
form label {
    display: block;
}
table[id] {
    margin: 10em;
    transform: rotateY(calc(1deg*var(--rotate)));
    transform-style: preserve-3d;
    transition: all 1s linear;
    tbody {
        transform-style: preserve-3d;
        tr {
            transform-style: preserve-3d;
            perspective: var(--distance);
            perspective-origin: var(--angle);
            transition: all 1s linear;
            background: unset !important;
            td {
                transform-style: preserve-3d;
                transition: all 1s linear;
                transform: translateZ(calc(var(--dir) * var(--val) * var(--depth))) rotateY(calc(-1deg*var(--rotate)));
            }
        }
    }
}


)  

use long form to add the controls so we can visually identify some of the patterns between the css properties and input types and changes.

self.repr.form.extend((
    new(
        "label", "depth", 
        new("input", type="number", min=0, max=12, step=.5, value=3, name="depth", 
            onchange=\
            """document.getElementById("%s").style.setProperty("--depth", `${document.forms["%s"].elements.depth.value}in`);""" % (self.id, self.id)
           ), "inches"
    ),
    new(
        "label", "distance", 
        new("input", type="number", min=0, max=12, step=.5, value=3, name="distance", 
            onchange=\
            """document.getElementById("%s").style.setProperty("--distance", `${document.forms["%s"].elements.distance.value}in`);""" % (self.id, self.id)
           ), "inches"
    ),
    new(
        "label", "angle", 
        new("input", type="number", min=0, max=100, step=2, value=50, name="angle", 
            onchange=\
            ("""document.getElementById("%s").style.setProperty("--angle", `${document.forms["%s"].elements.angle.value}""" % (self.id, self.id))  + "%`);"
           ), "%"
    ), 
    new("label", "direction", new("input", type="number", min=-1, max=1, step=2, value=1, name="dir", onchange=\
        """document.getElementById("%s").style.setProperty("--dir", document.forms["%s"].elements.dir.value);""" % (self.id, self.id)                        
                    ),)
))