wg-backend-django/dell-env/lib/python3.11/site-packages/dash_bootstrap_components/_table.py
2023-10-30 14:40:43 +07:00

145 lines
4.5 KiB
Python

from functools import reduce
from itertools import groupby
from operator import add
from dash import html
def _generate_table_from_df(
cls,
df,
float_format=None,
columns=None,
header=True,
index=False,
index_label=None,
date_format=None,
**table_kwargs
):
"""
Generate a Table component from a dataframe.
Parameters
----------
df : pandas.DataFrame
DataFrame to render as a table.
float_format : str, optional
Format to use for floating point numbers.
columns : sequence, optional
Columns to render.
header : boolean or list(str) or dict(str: str), optional
Write out the column names. If a list of strings is given it is assumed
to be aliases for the columns names (and hence must be the same length
as df.columns). A dict can be passed to rename some columns, the format
is {'<current_name>': '<new_name>'}. The dictionary need not have an
entry for every column.
index : boolean, optional
Render the row names (index).
index_label : str, optional
Column label for index column if desired. If None is passed, but both
header and index are True, then the index name is used.
date_format : str, optional
Format string for datetime objects.
**table_kwargs : Keyword arguments
Additional arguments to pass to the table component. See
dash_bootstrap_components.Table for details.
"""
import numpy as np
import pandas as pd
if columns is not None:
df = df.loc[:, columns]
if float_format is not None:
for c in df.select_dtypes(["float"]).columns:
df[c] = df[c].map(lambda x: "{1:{0}}".format(float_format, x))
if date_format is not None:
for c in df.select_dtypes(["datetime"]).columns:
df[c] = df[c].map(lambda x: x.strftime(date_format))
if index:
df = df.reset_index()
if index_label is not None:
df = df.rename(columns={"index": index_label})
if header:
if isinstance(header, (tuple, list, np.ndarray, pd.Index)):
try:
df.columns = header
except ValueError:
raise ValueError(
"If specifying column names with a sequence, the number "
"of names must exactly match the number of columns."
)
elif isinstance(header, dict):
df = df.rename(columns=header)
# Get the actual headers
n_levels = df.columns.nlevels
header_values = [
list(df.columns.get_level_values(level))
for level in range(n_levels)
]
# The sizes of consecutive header groups at each level
header_spans = [
[len(list(group)) for _, group in groupby(level_values)]
for level_values in header_values
]
# The positions of header changes for each level as an integer
header_breaks = [
[sum(level_spans[:i]) for i in range(1, len(level_spans) + 1)]
for level_spans in header_spans
]
# Include breaks from higher levels
header_breaks = [
sorted(set(reduce(add, header_breaks[:level])).union({0}))
for level in range(1, n_levels + 1)
]
# Go from header break positions back to cell spans
header_spans = [
reversed(
[
level_breaks[i] - level_breaks[i - 1]
for i in range(len(level_breaks) - 1, 0, -1)
]
)
for level_breaks in header_breaks
]
table = [
html.Thead(
[
html.Tr(
children=[
html.Th(
header_values[level][pos],
colSpan=span,
)
for pos, span in zip(
header_breaks[level], header_spans[level]
)
]
)
for level in range(n_levels)
]
)
]
else:
table = []
table.append(
html.Tbody(
[
html.Tr(
[html.Td(df.iloc[i, j]) for j in range(len(df.columns))]
)
for i in range(len(df))
]
)
)
return cls(table, **table_kwargs)