Skip to content

css technique for aligning decimals.ยค

all of my recent plotting techniques rely on access to cell values in css. when we have the values in css, along with their extent (min/max), we can adjust the values using math to align decimal points.

%%
our primary directive is calculate the order of magnitude of our values and their sign.
we only need the maximum number of digits and signs before the decimal;
we'll refer to these values with the prefix `--tens`

    display\
```css
#aligned {
    --tens-max: calc(
        round(up, max(1, log(abs(var(--0-max)), 10)))
        + abs(min(0, sign(var(--0-max))))
    );
    --tens-min: calc(
        round(up, max(1, log(abs(var(--0-min)), 10)))
        + abs(min(0, sign(var(--0-min))))
    );
    --tens-total: calc(max(var(--tens-max), var(--tens-min)));
}
```

this technique should work for any monospace sized font. we added background grids to verify alignment.

    display\
```css
#aligned {
    font-size: 36px;
    font-family: monospace;
    background: linear-gradient(90deg, transparent 98%, gray 2%);
    background-size: 0.25em 1em;
    tr {
        background: unset;
    }
}
```

for each cell value we use the `::before` element to insert a single character width for 
each `--tens` unit. if padding is not removed then we'll end up with extra left whitespace.s

    display\
```css
#aligned td {
    text-align: left;    
    &::before {
        display: inline-block;
        content: "";
        --tens: calc(
            round(up, max(1, log(abs(var(--0)), 10)))
            + abs(min(0, sign(var(--0))))
        );
        width: calc(1ch * (var(--tens-total) - var(--tens)));
        padding: 0;
    }
}
```
    import nbconvert_a11y.table
    (df := DataFrame(
        numpy.random.randn(30, 1)
    ).pow(9))


some values of `-0.000` dont fit the pattern because the are registered to css as zeros and are NOT negative.
this needs to amended in the table renderer.

    df.table(id="aligned")
pandas dataframe with 30 rows, 1 columns with 1 index levels and 1 columns levels.
None 0
0 -741.791
1 -0.000
2 -0.000
3 0.013
4 0.000
5 0.037
6 0.000
7 366.714
8 94.998
9 112818.814
10 -2.705
11 0.440
12 -0.000
13 0.000
14 3.757
15 -0.000
16 -0.034
17 0.077
18 -0.000
19 -18.245
20 -0.001
21 42.072
22 30.207
23 0.000
24 0.000
25 0.001
26 -0.520
27 -6.687
28 112.378
29 0.000
min -741.791
max 112818.814
diff 113560.605

our primary directive is calculate the order of magnitude of our values and their sign. we only need the maximum number of digits and signs before the decimal; we'll refer to these values with the prefix --tens

display\
#aligned {
    --tens-max: calc(
        round(up, max(1, log(abs(var(--0-max)), 10)))
        + abs(min(0, sign(var(--0-max))))
    );
    --tens-min: calc(
        round(up, max(1, log(abs(var(--0-min)), 10)))
        + abs(min(0, sign(var(--0-min))))
    );
    --tens-total: calc(max(var(--tens-max), var(--tens-min)));
}

this technique should work for any monospace sized font. we added background grids to verify alignment.

display\
#aligned {
    font-size: 36px;
    font-family: monospace;
    background: linear-gradient(90deg, transparent 98%, gray 2%);
    background-size: 0.25em 1em;
    tr {
        background: unset;
    }
}

for each cell value we use the ::before element to insert a single character width for each --tens unit. if padding is not removed then we'll end up with extra left whitespace.s

display\
#aligned td {
    text-align: left;    
    &::before {
        display: inline-block;
        content: "";
        --tens: calc(
            round(up, max(1, log(abs(var(--0)), 10)))
            + abs(min(0, sign(var(--0))))
        );
        width: calc(1ch * (var(--tens-total) - var(--tens)));
        padding: 0;
    }
}
import nbconvert_a11y.table
(df := DataFrame(
    numpy.random.randn(30, 1)
).pow(9))

some values of -0.000 dont fit the pattern because the are registered to css as zeros and are NOT negative. this needs to amended in the table renderer.

df.table(id="aligned")