01Read a whole table into a DataFrame with xl() in a =PY cellVerified
In a =PY cell, xl("TableName[#All]", headers=True) hands the whole table to Python as a pandas DataFrame with its headers. Two-dimensional ranges become DataFrames by default, so you can group and aggregate right away.
- Format the ledger as an Excel table and name it (for example, RequestLedger)
- Type =PY in a cell and pick PY to switch the cell into the Python editor
- Read the whole table with xl("RequestLedger[#All]", headers=True); [#All] covers the entire table and headers=True treats the first row as column names
- Aggregate the DataFrame with groupby; the value of the last expression is returned to the cell
- To read a plain range instead, pass its address, such as xl("B1:C4")
# Python in Excel cell (=PY). Table name: RequestLedger
df = xl("RequestLedger[#All]", headers=True)
# Count requests and total findings by document type
summary = (
df.groupby("種別")
.agg(件数=("依頼ID", "count"), 指摘件数計=("指摘件数", "sum"))
.sort_values("件数", ascending=False)
)
summaryOutput(2026-09-12)
件数 指摘件数計
種別
社内通知 11 42
プレスリリース 10 34
Web 記事 7 42
契約書 6 27
提案書 6 26
rows: 40 total: 40Write Python in Excel cell code that reads the RequestLedger table with xl() including headers, then lists the count of requests and the total findings per document type, sorted by count. Do not read files or use the network.
xl() reads cell values only; the code cannot see formulas, charts, or PivotTables in the workbook. Add [#All] to read the entire table. Calculation runs in the Microsoft Cloud, so an internet connection is required. Check that the totals add up to the row count of the source table.
Supporting passages from the sources
For a table with headers named MyTable, use xl("MyTable[#All]", headers=True). The [#All] specifier ensures that the entire table is analyzed in the Python formula, and headers=True ensures that the table headers are processed correctly.
Python in Excel uses a DataFrame as the default object for two-dimensional ranges.
The Python code doesn't have access to other properties in the workbook, such as formulas, charts, PivotTables, macros, or VBA code.
02Keep group labels as a column when returning a summary as Excel valuesVerified
A =PY result can come back as a Python object or as Excel values. When a DataFrame is returned as Excel values, its index column appears only under certain conditions, so groupby with as_index=False keeps the group labels as an ordinary column.
- Return intermediate results that later Python cells reuse as a Python object (the cell shows a card icon)
- Switch final results used by charts or conditional formatting to Excel values with the Python output menu in the formula bar
- Use groupby(..., as_index=False) so the group labels become a column instead of the index
- Keep the cells to the right and below empty; if the output range already holds data, the cell returns #SPILL!
# Python in Excel cell (=PY), output type: Excel value
df = xl("RequestLedger[#All]", headers=True)
by_dept = (
df.groupby("依頼部署", as_index=False) # department stays a column
.agg(件数=("依頼ID", "count"), 平均指摘=("指摘件数", "mean"))
.round({"平均指摘": 1})
)
by_deptOutput(2026-09-12)
依頼部署 件数 平均指摘
人事部 11 4.1
営業部 10 4.6
広報部 19 4.2
index is numeric: TrueWrite Python in Excel cell code that summarizes the RequestLedger table by department with the request count and the mean number of findings rounded to one decimal. The output will be Excel values, so keep the department names as a column, not the index.
Results converted to Excel values are translated to their closest Excel equivalent; keep a Python object when a later Python calculation needs it. A DataFrame whose index is not numeric (such as the output of describe()) also outputs its index column, so check the column layout.
Supporting passages from the sources
When the output type of a DataFrame is set to Excel values, the DataFrame only outputs the index column if one of the following conditions is met. If values of the index column are not numeric (like the result of describe() or group_by()). If the index column name has been set.
Return object with group labels as the index.
If you plan to reuse the result in a future Python calculation, it's recommended to return the result as a Python object.
03Place variables to match the row-major calculation order of Python cellsVerified
Python cells on a worksheet calculate in row-major order: across each row from column A, then down to the next row, and worksheet by worksheet. Put the cell that defines a variable above, or to the left of, every cell that uses it.
- Put the cell that loads the table and fixes data types (creating df) at the top left, returned as a Python object
- Put summary cells that use df in a later row or to its right
- When analysis spans several sheets, keep the data and variable cells on earlier sheets
- Keep import statements and settings on the first worksheet
- To pause recalculation while you work, use Partial or Manual calculation and press F9 to recalculate
# --- Cell A1 (=PY, Python object): load and clean once ---
df = xl("RequestLedger[#All]", headers=True)
df["依頼日"] = pd.to_datetime(df["依頼日"])
df["完了日"] = pd.to_datetime(df["完了日"])
df
# --- Cell A2 (=PY, Excel value): calculated after A1 (row-major order) ---
done = df[df["状態"] == "完了"].copy()
done["日数"] = (done["完了日"] - done["依頼日"]).dt.days
done.groupby("種別")["日数"].median()Output(2026-09-12)
日数
種別
Web 記事 6.0
プレスリリース 3.0
契約書 7.5
提案書 5.0
社内通知 12.0
completed rows: 14Write Python in Excel code split into two cells. The first reads the RequestLedger table and converts the request and completion dates to datetime. The second computes the median days to completion per document type for completed rows. Say which cell must come first on the sheet.
Referencing a variable defined in a lower row or a later sheet fails because it is calculated first. When a dependent value changes, all Python formulas recalculate in sequence. In Manual or Partial mode, stale values remain until you recalculate, so recalculate before reporting.
Supporting passages from the sources
But in a Python in Excel worksheet, Python cells calculate in row-major order. The cell calculations run across a row (from column A to column XFD), and then across each following row down the worksheet.
The row-major calculation order also applies across worksheets within a workbook and is based on the order of the worksheets within the workbook.
To ensure that your libraries are imported before your Python formulas run, enter your import statements and any settings on the first worksheet in your workbook.
04Check which libraries the runtime provides and keep imports up frontVerified
Python in Excel runs a curated set of libraries provided by Anaconda; packages installed in your local Python are not reflected. Import additional libraries in a cell, and use importlib to check whether a module is present before relying on it.
- Matplotlib, NumPy, pandas, seaborn, and statsmodels are imported by default under aliases such as np and pd
- Pass the import names you want to importlib.util.find_spec in a Python cell to check that they exist
- Import statements differ by library (for example, beautifulsoup4 uses from bs4 import BeautifulSoup)
- Keep your import statements in the Formulas > Initialization task pane or on the first worksheet
# Python in Excel cell (=PY): which optional libraries does this runtime provide?
import importlib.util
wanted = ["bs4", "sklearn", "scipy", "networkx"]
found = {name: importlib.util.find_spec(name) is not None for name in wanted}
pd.Series(found, name="available")Output(2026-09-12)
bs4 False
sklearn True
scipy True
networkx True
Name: availableWrite Python in Excel cell code that uses importlib to check whether bs4, sklearn, scipy, and networkx are available and returns a Series of names and True/False. Do not try to install anything.
Libraries cannot make network requests or reach files on your machine. The libraries page calls the Initialization task pane read-only, while the initialization settings page says you can add and edit imports there; check in your own Excel. Changing initialization settings also affects Copilot in Excel with Python.
Supporting passages from the sources
In addition to the core libraries, you can import additional libraries available through Anaconda.
If you have a local version of Python installed on your computer, any customizations you've made to that Python installation won't be reflected in Python in Excel calculations.
This task pane is currently read-only and shows the initialization settings for your Python in Excel runtime.
Changing initialization settings affects how Python behaves in your workbook. Any changes can impact both Python in Excel and Copilot in Excel with Python.
05Bring outside data in with Power Query and read it by query name with xl()Verified
Python in Excel code has no network or local file access, so pandas.read_csv or read_excel on an outside file will not work. Create a Power Query query instead and receive it as a DataFrame with xl("QueryName").
- Choose the source, such as a CSV file, under Data > Get Data
- In Load To..., choose Only Create Connection to create the query without loading it onto a sheet
- In a =PY cell, write xl("QueryName") to receive the data as a DataFrame
- Importing external data with Power Query for Python in Excel is not available in Excel on the web, so build the query in desktop Excel
# Python in Excel cell (=PY)
# "RequestsQuery" is a Power Query connection (Load To... > Only Create Connection).
# pd.read_csv("C:/...") would not work here: the code has no file or network access.
df = xl("RequestsQuery")
open_items = df[df["状態"] != "完了"]
open_items.groupby("担当者")["依頼ID"].count().rename("未完了件数")Output(2026-09-12)
担当者
担当A 10
担当B 7
担当C 3
担当D 6
Name: 未完了件数Write Python in Excel cell code that reads the Power Query connection RequestsQuery with xl() and counts requests that are not complete per assignee. Do not read files directly with pandas.read_csv or similar.
Power Query is the only way to import external data for Python in Excel. Python formulas in a workbook opened from the internet do not run in Protected View. Confirm whether the query source is current on the query side, not from the Python result.
Supporting passages from the sources
Power Query is the only way to import external data for use with Python in Excel.
The Python code doesn't have access to your computer, devices, or account. The Python code doesn't have network access.
To protect your security, common external data functions in Python, such as pandas.read_csv and pandas.read_excel, aren't compatible with Python in Excel.
Importing external data with Power Query to use with Python in Excel is not available for Excel on the web.
06List the code in Python cells with FORMULATEXT for reviewVerified
Behind every Python cell is a =PY(python_code, return_type) formula, and FORMULATEXT returns it as text. Listing that text on a review sheet makes the code easy to read side by side during review or handover.
- Create a review sheet and put the address of each Python cell in column A
- In column B, enter =FORMULATEXT(reference) to pull out the =PY(...) text
- A last argument of 1 means the cell returns a Python object; 0 means it returns an Excel value
- The PY function cannot be typed in the formula bar or combined with other functions, so use the review sheet for reading only
Review sheet (row 2; fill down for more cells)
A2: Sheet1!C1
B2: =FORMULATEXT(Sheet1!C1)
C2: =IF(RIGHT(B2,3)=",1)","Python object",IF(RIGHT(B2,3)=",0)","Excel value","check"))
Example of the text returned in B2 (syntax from the PY function reference):
=PY("xl(""Table1[#All]"", headers=True)",1)Write formulas for a review sheet that list the code of the Python cells in Sheet1!C1:C5 with FORMULATEXT and show whether each cell returns a Python object or an Excel value.
The column C check assumes the FORMULATEXT text ends in ,1) or ,0) as in the documented syntax; look at the text in your own workbook to confirm. People still need to read the code; FORMULATEXT says nothing about whether the result is right.
Supporting passages from the sources
The PY function syntax is primarily used by add-ins to directly insert or read Python formulas. It can also be seen when using the FORMULATEXT function on a cell containing a Python formula.
The PY function cannot be used with any other Excel functions. If used with other functions, a formula cannot be entered.
0 indicates Excel value. 1 indicates Python object.
07Read a ledger with openpyxl read_only and data_onlyVerified
When reading xlsx files in local Python, load_workbook(read_only=True) streams large files with little memory. data_only=True returns the value Excel last stored instead of the formula. openpyxl does not calculate formulas, so a formula never saved by Excel reads as None.
- Open a large ledger with load_workbook(..., read_only=True) and stream rows with iter_rows(values_only=True)
- Close a read-only workbook explicitly with close() when you are done
- Keep the default to get formula text, or open with data_only=True to get the values Excel stored
- A cell that returns None under data_only has no stored value until the file is opened and saved in Excel
from openpyxl import load_workbook
SRC = "samples/request_ledger.xlsx" # input, not modified
AFTER = "samples/excel_ledger_after.xlsx" # has a formula sheet saved by openpyxl
# 1) read_only: stream rows with low memory, then close explicitly
wb = load_workbook(SRC, read_only=True)
ws = wb.worksheets[0]
header = next(ws.iter_rows(max_row=1, values_only=True))
status_col = header.index("状態")
open_count = sum(1 for r in ws.iter_rows(min_row=2, values_only=True) if r[status_col] != "完了")
wb.close()
print("open requests:", open_count)
# 2) formula text vs stored value
formula = load_workbook(AFTER)["集計"]["B2"].value
stored = load_workbook(AFTER, data_only=True)["集計"]["B2"].value
print("formula:", formula)
print("stored value:", stored) # None: openpyxl wrote the formula but never calculated itOutput(2026-09-12)
open requests: 26
formula: =COUNTIF(依頼台帳!G:G,A2)
stored value: NoneWrite openpyxl code that opens request_ledger.xlsx in read_only mode, counts rows whose status is not complete, and closes it; then read a formula cell in another workbook with and without data_only. Do not modify any file.
openpyxl does not read every item in an Excel file, so shapes are lost if you open and save a file under the same name; never overwrite the source. Read-only workbooks return a different cell type and cannot be written. Check values against a file that Excel has recalculated and saved.
Supporting passages from the sources
data_only controls whether cells with formulae have either the formula (default) or the value stored the last time Excel read the sheet.
The workbook must be explicitly closed with the close() method.
shapes will be lost from existing files if they are opened and saved with the same name.
08Summarize a ledger with pandas and write several sheets to a new workbookVerified
In local Python, read the ledger with pandas.read_excel, aggregate it with groupby, and write several sheets to a new workbook through ExcelWriter. An existing file with the same name is overwritten, so always write to a new name.
- Read the first sheet into a DataFrame with read_excel(sheet_name=0)
- Derive a month column from the request date and use groupby for type-by-status and monthly counts
- Inside with pd.ExcelWriter(output), call to_excel once per sheet name
- Read the output back with read_excel(sheet_name=None) and check the sheet names and the total count
import pandas as pd
SRC = "samples/request_ledger.xlsx"
OUT = "out_ledger_summary.xlsx" # new file; the source is never overwritten
df = pd.read_excel(SRC, sheet_name=0)
df["依頼月"] = pd.to_datetime(df["依頼日"]).dt.strftime("%Y-%m")
by_type = df.groupby(["種別", "状態"])["依頼ID"].count().unstack(fill_value=0)
by_month = (df.groupby("依頼月", as_index=False)
.agg(件数=("依頼ID", "count"), 指摘件数計=("指摘件数", "sum")))
with pd.ExcelWriter(OUT, engine="openpyxl") as writer:
by_type.to_excel(writer, sheet_name="種別x状態")
by_month.to_excel(writer, sheet_name="月別", index=False)
# Read back and reconcile with the source
check = pd.read_excel(OUT, sheet_name=None)
print("sheets:", list(check))
print(by_month.to_string(index=False))
print("rows in source:", len(df), "| total in 月別:", int(check["月別"]["件数"].sum()))Output(2026-09-12)
sheets: ['種別x状態', '月別']
依頼月 件数 指摘件数計
2026-07 21 95
2026-08 19 76
rows in source: 40 | total in 月別: 40Write pandas code that reads request_ledger.xlsx and writes a type-by-status count table and a monthly table of counts and total findings to separate sheets of a new workbook, out_ledger_summary.xlsx. Do not overwrite the source, and read the output back to print the total count.
ExcelWriter defaults to write mode, so passing an existing file name overwrites it; never reuse the source name. The output holds values only, not Excel formulas or PivotTables. Check that the totals match the source row count.
Supporting passages from the sources
To write to multiple sheets it is necessary to create an ExcelWriter object with a target file name, and specify a sheet in the file to write to.
Note that creating an ExcelWriter object with a file name that already exists will overwrite the existing file because the default mode is write.
Read an Excel file into a DataFrame.