Skip to content

Commit a021585

Browse files
authored
Support multiple column levels (#509)
* Support multiple column levels * Make repeated column titles span multiple columns * Select table data with iloc rather than loc * Include header breaks from header levels * remove unnecessary listcomp * remove space from comment * Go from itertools.accumlate to numpy.cumsum for python 2.7 compatibility * remove numpy dependency * Simplify running total
1 parent c852db9 commit a021585

File tree

1 file changed

+60
-2
lines changed

1 file changed

+60
-2
lines changed

dash_bootstrap_components/_table.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from functools import reduce
2+
from itertools import groupby
3+
from operator import add
4+
15
import dash_html_components as html
26

37

@@ -70,15 +74,69 @@ def _generate_table_from_df(
7074
)
7175
elif isinstance(header, dict):
7276
df = df.rename(columns=header)
77+
78+
# Get the actual headers
79+
n_levels = df.columns.nlevels
80+
header_values = [
81+
list(df.columns.get_level_values(level))
82+
for level in range(n_levels)
83+
]
84+
85+
# The sizes of consecutive header groups at each level
86+
header_spans = [
87+
[len(list(group)) for _, group in groupby(level_values)]
88+
for level_values in header_values
89+
]
90+
91+
# The positions of header changes for each level as an integer
92+
header_breaks = [
93+
[sum(level_spans[:i]) for i in range(1, len(level_spans) + 1)]
94+
for level_spans in header_spans
95+
]
96+
97+
# Include breaks from higher levels
98+
header_breaks = [
99+
sorted(set(reduce(add, header_breaks[:level])).union({0}))
100+
for level in range(1, n_levels + 1)
101+
]
102+
103+
# Go from header break positions back to cell spans
104+
header_spans = [
105+
reversed(
106+
[
107+
level_breaks[i] - level_breaks[i - 1]
108+
for i in range(len(level_breaks) - 1, 0, -1)
109+
]
110+
)
111+
for level_breaks in header_breaks
112+
]
113+
73114
table = [
74-
html.Thead(html.Tr(children=[html.Th(col) for col in df.columns]))
115+
html.Thead(
116+
[
117+
html.Tr(
118+
children=[
119+
html.Th(
120+
header_values[level][pos],
121+
colSpan=span,
122+
)
123+
for pos, span in zip(
124+
header_breaks[level], header_spans[level]
125+
)
126+
]
127+
)
128+
for level in range(n_levels)
129+
]
130+
)
75131
]
76132
else:
77133
table = []
78134
table.append(
79135
html.Tbody(
80136
[
81-
html.Tr([html.Td(df.iloc[i][col]) for col in df.columns])
137+
html.Tr(
138+
[html.Td(df.iloc[i, j]) for j in range(len(df.columns))]
139+
)
82140
for i in range(len(df))
83141
]
84142
)

0 commit comments

Comments
 (0)