Excel file creation, editing, analysis with openpyxl and pandas. Use for .xlsx/.csv tasks including formulas, formatting, pivot tables, charts, data cleaning, and tabular file operations.
Unless otherwise stated by the user or existing template
A user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks.
LibreOffice Required for Formula Recalculation: You can assume LibreOffice is installed for recalculating formula values using the scripts/recalc.py script. The script automatically configures LibreOffice on first run, including in sandboxed environments where Unix sockets are restricted (handled by scripts/office/soffice.py)
For data analysis, visualization, and basic operations, use pandas which provides powerful data manipulation capabilities:
import pandas as pd
# Read Excel
df = pd.read_excel('file.xlsx') # Default: first sheet
all_sheets = pd.read_excel('file.xlsx', sheet_name=None) # All sheets as dict
# Analyze
df.head() # Preview data
df.info() # Column info
df.describe() # Statistics
# Write Excel
df.to_excel('output.xlsx', index=False)
Always use Excel formulas instead of calculating values in Python and hardcoding them. This ensures the spreadsheet remains dynamic and updateable.
# Bad: Calculating in Python and hardcoding result
total = df['Sales'].sum()
sheet['B10'] = total # Hardcodes 5000
# Bad: Computing growth rate in Python
growth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue']
sheet['C5'] = growth # Hardcodes 0.15
# Bad: Python calculation for average
avg = sum(values) / len(values)
sheet['D20'] = avg # Hardcodes 42.5
# Good: Let Excel calculate the sum
sheet['B10'] = '=SUM(B2:B9)'
# Good: Growth rate as Excel formula
sheet['C5'] = '=(C4-C2)/C2'
# Good: Average using Excel function
sheet['D20'] = '=AVERAGE(D2:D19)'
This applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes.
python scripts/recalc.py output.xlsx
status is errors_found, check error_summary for specific error types and locations#REF!: Invalid cell references#DIV/0!: Division by zero#VALUE!: Wrong data type in formula#NAME?: Unrecognized formula name# Using openpyxl for formulas and formatting
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
wb = Workbook()
sheet = wb.active
# Add data
sheet['A1'] = 'Hello'
sheet['B1'] = 'World'
sheet.append(['Row', 'of', 'data'])
# Add formula
sheet['B2'] = '=SUM(A1:A10)'
# Formatting
sheet['A1'].font = Font(bold=True, color='FF0000')
sheet['A1'].fill = PatternFill('solid', start_color='FFFF00')
sheet['A1'].alignment = Alignment(horizontal='center')
# Column width
sheet.column_dimensions['A'].width = 20
wb.save('output.xlsx')
# Using openpyxl to preserve formulas and formatting
from openpyxl import load_workbook
# Load existing file
wb = load_workbook('existing.xlsx')
sheet = wb.active # or wb['SheetName'] for specific sheet
# Working with multiple sheets
for sheet_name in wb.sheetnames:
sheet = wb[sheet_name]
print(f"Sheet: {sheet_name}")
# Modify cells
sheet['A1'] = 'New Value'
sheet.insert_rows(2) # Insert row at position 2
sheet.delete_cols(3) # Delete column 3
# Add new sheet
new_sheet = wb.create_sheet('NewSheet')
new_sheet['A1'] = 'Data'
wb.save('modified.xlsx')
Excel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided scripts/recalc.py script to recalculate formulas:
python scripts/recalc.py <excel_file> [timeout_seconds]
Example:
python scripts/recalc.py output.xlsx 30
The script:
Quick checks to ensure formulas work correctly:
pd.notna()/ in formulas (#DIV/0!)The script returns JSON with error details:
{
"status": "success", // or "errors_found"
"total_errors": 0, // Total error count
"total_formulas": 42, // Number of formulas in file
"error_summary": { // Only present if errors found
"#REF!": {
"count": 2,
"locations": ["Sheet1!B5", "Sheet1!C10"]
}
}
}
data_only=True to read calculated values: load_workbook('file.xlsx', data_only=True)data_only=True and saved, formulas are replaced with values and permanently lostread_only=True for reading or write_only=True for writingpd.read_excel('file.xlsx', dtype={'id': str})pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])pd.read_excel('file.xlsx', parse_dates=['date_column'])from openpyxl import load_workbook
from openpyxl.pivot.table import PivotTable, TableStyleInfo
from openpyxl.pivot.fields import RowField, ColField, DataField
wb = load_workbook('data.xlsx')
ws = wb.active
# Define source data range
data_range = 'A1:D100'
# Create pivot table
pivot = PivotTable()
pivot.addRowField(RowField(sourceField=0)) # First column as rows
pivot.addColField(ColField(sourceField=1)) # Second column as columns
pivot.addDataField(DataField(sourceField=2, function='sum')) # Sum of third column
# Add to new sheet
pivot_sheet = wb.create_sheet('Pivot')
pivot_sheet.add_pivot_table(pivot, 'A1', data_range)
wb.save('output.xlsx')
from openpyxl.chart import BarChart, Reference
# Create chart with dynamic data range
chart = BarChart()
data = Reference(ws, min_col=2, min_row=1, max_col=3, max_row=ws.max_row)
categories = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row)
chart.add_data(data, titles_from_data=True)
chart.set_categories(categories)
chart.title = "Sales by Region"
chart.x_axis.title = "Region"
chart.y_axis.title = "Revenue"
ws.add_chart(chart, "E5")
# Chart with formula-based data source
ws['F1'] = '=SUM(B2:B10)'
chart_data = Reference(ws, min_col=6, min_row=1, max_row=1)
# Array formulas (CSE formulas)
ws['D2'] = '{=SUM(A2:A10*B2:B10)}' # Curly braces indicate array formula
# Named ranges for formulas
from openpyxl.workbook.defined_name import DefinedName
# Define named range
sales_range = DefinedName('SalesData', attr_text='Sheet1!$B$2:$B$100')
wb.defined_names.append(sales_range)
# Use in formula
ws['C1'] = '=SUM(SalesData)'
# Dynamic named range (expands automatically)
dynamic_range = DefinedName(
'DynamicSales',
attr_text='OFFSET(Sheet1!$B$2,0,0,COUNTA(Sheet1!$B:$B)-1,1)'
)
wb.defined_names.append(dynamic_range)
IMPORTANT: When generating Python code for Excel operations:
For Excel files themselves:
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer