Here a small function I wrote to quickly add data to named tables and single cell named cells.
It expects the tables to be empty and can/should be used when an Excel template report is created, saved, and later filled with data using Python
from typing import Any, Optional, Union
import pandas
import openpyxl
def find_worksheet_and_table(woorkbook, table_name):
for worksheet in workbook.worksheets:
for table in worksheet.tables.values():
if table.name == table_name:
return worksheet, table
raise KeyError(f'Unable to find table with name "{table_name}" in workbook!')
def populate_table(workbook, table_name, dataframe):
"""Modifies table and inserts values. Formulas are kepts as is."""
worksheet, table = find_worksheet_and_table(workbook, table_name)
table_start, table_end = table.ref.split(':')
table_start_row = int(''.join(x for x in table_start if x.isdigit()))
table_start_column = column_index_from_string(''.join(x for x in table_start if not x.isdigit()))
table_end_column_letter = ''.join(x for x in table_end if not x.isdigit())
new_table_ref = table_start + ':' + table_end_column_letter + str(table_start_row + len(dataframe))
table_first_cell = worksheet.cell(row=table_start_row, column=table_start_column)
table.ref = new_table_ref
for col_ix, column in enumerate(table.tableColumns):
if column.name in dataframe.columns:
for row_ix, row_value in enumerate(dataframe[column.name]):
cell_to_fill = table_first_cell.offset(column=col_ix, row=row_ix+1)
cell_to_fill.value = row_value
elif column.calculatedColumnFormula:
for ix in range(len(dataframe)):
cell_to_fill = table_first_cell.offset(column=col_ix, row=ix+1)
cell_to_fill.value = '='+table.tableColumns[col_ix].calculatedColumnFormula.attr_text
def populate_excel(
input_path: Union[str, pathlib.Path],
output_path: Union[str, pathlib.Path],
named_cell_using_single_values: Optional[dict[str, Any]],
table_using_dataframe : Optional[dict[str, pandas.DataFrame]],
):
"""
input_path: Excel file to read.
output_path: Save location for output Excel file.
named_cell_using_single_values: Dict of named cells with value to populate them with.
table_using_dataframe: Dict of named table with dataframes to populate them with.
Function to insert data into Excel using named cells and named tables.
"""
workbook = openpyxl.load_workbook(input_path)
if table_using_dataframe:
for table_name, dataframe in table_using_dataframe.items():
populate_table(workbook, table_name, dataframe)
if named_cell_using_single_values:
for named_cell, value in named_cell_using_single_values.items():
if not named_cell in workbook.defined_names:
raise KeyError(f"Unable to find named cell {named_cell} in workbook!")
worksheet_to_update, coordinate_to_update = next(workbook.defined_names[named_cell].destinations)
cell_to_update = workbook[worksheet_to_update][coordinate_to_update]
cell_to_update.value = value
workbook.save(output_path)
workbook.close()
dataframe_to_write = pandas.DataFrame(data = {'Column1': range(500), 'Column2': range(500), 'Column3': range(500)})
populate_excel(
'input.xlsx',
'output.xlsx',
{'my_named_cell': 'value for named cell!', 'my_named_cell2': 20},
{'MyTable': dataframe_to_write}
)