Skip to content

a study of pandas dataframes with different levels¤

the goal of this work is to study how index and column names are presented in html tables.

start with a dataframe with multi indexes. each level of the study removes indexes rather than add.

we can think about 4 quadrants in the dataframe representation:

  1. the region where the names of the indexes are presented
  2. the region where the column values are shown
  3. the region where the index values are shown
  4. the region where the values are shown

there are natural solutions when either row or columns are provided. the names are column or row scoped headers for the primary axis of the table. a table with column names is column major while row names are row major. there are ambiguities about the major axis when both the indexes are named, this poses specific challenges to region 1 our table representation, it is likely that under these conditions we will have empty cells. we'll need principles that help us choose the best conformation under ambiguous conditions.

if empty cells are presented, should they bed in thead? tbody? is there an advantage to empty columns vs empty rows. again this only matters in the single axis use case.

    import pandas, midgy
/tmp/ipykernel_21646/3616882755.py:1: DeprecationWarning: 
Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),
(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)
but was not found to be installed on your system.
If this would cause problems for you,
please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466

  import pandas, midgy
%%
<style>
:is(.jp-OutputArea-output.jp-RenderedHTMLCommon, .nb-outputs) :is(td,th) {
    border: 1px solid;
}
</style>
    df = pandas.DataFrame(
        index=pandas.MultiIndex.from_product(
            [[100], [10, 20, 30], [1, 2]]
        ),
        columns=pandas.MultiIndex.from_product(
            [["AZ"], ["A", "Z"], ["A", "B", "C"]]
        )
    ).rename_axis(
        index=["hundreds", "tens", "ones"],
        columns=["outer", "middle", "inner"]
    ).head(2).fillna("")

iterate through different pairings of row and column names

    for i in range(1, df.index.nlevels + 1):
        for j in range(1, df.index.nlevels + 1):
            data = df
            while data.index.nlevels &gt; i: 
                data = data.droplevel(0, axis=0)
                if data.index.nlevels == 1: break
            while data.columns.nlevels &gt; j:
                data = data.droplevel(0, axis=1)
                if data.columns.nlevels == 1: break
            for row_names in ([None]*data.index.nlevels, data.index.names):
                for col_names in ([None]*data.columns.nlevels, data.columns.names):
                    title = str(len(row_names)) + [" un", " "][any(row_names)] + F"named rows and {len(col_names)} " + ["un", ""][any(col_names)] + "named columns"
                    out = data.rename_axis(index=row_names, columns=col_names).style.set_caption(title)
                    display(out)
            display({"text/html": "<hr/>"}, raw=True)
1 unnamed rows and 1 unnamed columns
  A B C A B C
1
2
1 unnamed rows and 1 named columns
inner A B C A B C
1
2
1 named rows and 1 unnamed columns
  A B C A B C
ones            
1
2
1 named rows and 1 named columns
inner A B C A B C
ones            
1
2

1 unnamed rows and 2 unnamed columns
  A Z
  A B C A B C
1
2
1 unnamed rows and 2 named columns
middle A Z
inner A B C A B C
1
2
1 named rows and 2 unnamed columns
  A Z
  A B C A B C
ones            
1
2
1 named rows and 2 named columns
middle A Z
inner A B C A B C
ones            
1
2

1 unnamed rows and 3 unnamed columns
  AZ
  A Z
  A B C A B C
1
2
1 unnamed rows and 3 named columns
outer AZ
middle A Z
inner A B C A B C
1
2
1 named rows and 3 unnamed columns
  AZ
  A Z
  A B C A B C
ones            
1
2
1 named rows and 3 named columns
outer AZ
middle A Z
inner A B C A B C
ones            
1
2

2 unnamed rows and 1 unnamed columns
    A B C A B C
10 1
2
2 unnamed rows and 1 named columns
  inner A B C A B C
10 1
2
2 named rows and 1 unnamed columns
    A B C A B C
tens ones            
10 1
2
2 named rows and 1 named columns
  inner A B C A B C
tens ones            
10 1
2

2 unnamed rows and 2 unnamed columns
    A Z
    A B C A B C
10 1
2
2 unnamed rows and 2 named columns
  middle A Z
  inner A B C A B C
10 1
2
2 named rows and 2 unnamed columns
    A Z
    A B C A B C
tens ones            
10 1
2
2 named rows and 2 named columns
  middle A Z
  inner A B C A B C
tens ones            
10 1
2

2 unnamed rows and 3 unnamed columns
    AZ
    A Z
    A B C A B C
10 1
2
2 unnamed rows and 3 named columns
  outer AZ
  middle A Z
  inner A B C A B C
10 1
2
2 named rows and 3 unnamed columns
    AZ
    A Z
    A B C A B C
tens ones            
10 1
2
2 named rows and 3 named columns
  outer AZ
  middle A Z
  inner A B C A B C
tens ones            
10 1
2

3 unnamed rows and 1 unnamed columns
      A B C A B C
100 10 1
2
3 unnamed rows and 1 named columns
    inner A B C A B C
100 10 1
2
3 named rows and 1 unnamed columns
      A B C A B C
hundreds tens ones            
100 10 1
2
3 named rows and 1 named columns
    inner A B C A B C
hundreds tens ones            
100 10 1
2

3 unnamed rows and 2 unnamed columns
      A Z
      A B C A B C
100 10 1
2
3 unnamed rows and 2 named columns
    middle A Z
    inner A B C A B C
100 10 1
2
3 named rows and 2 unnamed columns
      A Z
      A B C A B C
hundreds tens ones            
100 10 1
2
3 named rows and 2 named columns
    middle A Z
    inner A B C A B C
hundreds tens ones            
100 10 1
2

3 unnamed rows and 3 unnamed columns
      AZ
      A Z
      A B C A B C
100 10 1
2
3 unnamed rows and 3 named columns
    outer AZ
    middle A Z
    inner A B C A B C
100 10 1
2
3 named rows and 3 unnamed columns
      AZ
      A Z
      A B C A B C
hundreds tens ones            
100 10 1
2
3 named rows and 3 named columns
    outer AZ
    middle A Z
    inner A B C A B C
hundreds tens ones            
100 10 1
2

    df
outer AZ
middle A Z
inner A B C A B C
hundreds tens ones
100 10 1
2