Studio Matrx Monthly · Volume 1 · Issue 3 · August 2026
Amogh N P
 In loving memory of Amogh N P — Architect · Designer · Visionary 
Schedules, BOQs and SpreadsheetsLesson 4.3
PSD for Architecture, Planning & Urban Design/Module 4 · Working with Design Data

Lesson 4.3 · Working with Design Data

Schedules, BOQs and Spreadsheets

The paperwork of practice, scripted - read a room schedule or bill of quantities, compute the areas, quantities and costs, and write the finished sheet back to Excel

13 min Interactive lessonFree · open lessonByAmogh N P· Architect & interior designer
The hook

The schedule, the BOQ, the FF&E sheet - the documents that eat your evenings are exactly the ones a script produces best.

Every project runs on spreadsheets that someone maintains by hand: a room schedule with areas, a bill of quantities with rates and costs, a finishes list with subtotals. They are recomputed and re-issued every revision, and the recomputing is where the errors and the late nights live.

This lesson closes the loop. You read the real file in, use everything from the last two lessons to compute and summarise it, and then - the new move - write the finished result back out to Excel or CSV, formatted, with subtotals, ready for a colleague to open. When the quantities change next week, you do not redo the sheet; you re-run the script. This is the moment pandas stops being a tutorial and becomes a tool that produces your actual deliverables.

read_excel (verify!) -> compute + groupby -> to_excel(index=False). ExcelWriter for many tabs. The script IS the schedule.

Reading the real thing - a room schedule

Start from a file that already exists: a room schedule someone keeps in Excel, with a room name, a length and a width per row. Reading it is one line, but a real workbook has quirks - the data is on a named sheet, maybe with a title row above the headers - so read_excel gives you arguments to cope:

python
import pandas as pd

rooms = pd.read_excel(
    "project.xlsx",
    sheet_name="Rooms",   # the sheet, by name
    header=0,             # which row holds the column names
)
print(rooms.head())
print(rooms.info())

The head() and info() reflex matters even more here than with a clean CSV, because Excel is where mixed types hide - a length column with one cell reading approx 3.5 comes in as text, and every area you compute from it will fail silently. info() shows you that length_m is object (text) rather than float64 (number) before you trust it. If a column that should be numeric is not, pd.to_numeric(rooms["length_m"], errors="coerce") converts what it can and marks the rest as missing, so you can find and fix the offending cells. Reading is easy; reading and verifying is the professional habit, because a schedule built on a mistyped column is worse than no schedule at all - it looks authoritative and is wrong.

Real workbooks bring a few other quirks worth naming so they do not surprise you. Merged cells - common in hand-built schedules where someone merged the header across two columns - come into pandas as a value in the top-left cell and NaN in the rest, so a merged title row usually needs a skiprows or a manual clean. Trailing empty rows and a totals row at the bottom will be read as data, so it is common to slice them off or filter them out after loading. And the column names themselves often arrive with trailing spaces or inconsistent capitalisation - Area (SqM) versus area_sqm - which is why renaming to clean, predictable names right after the read pays for itself across the rest of the script. None of this is hard; it is just the reality of files made by people, and a minute spent tidying the structure up front saves an hour of confusion later.

READ - COMPUTE - WRITEREADproject.xlsxread_excel + verifyCOMPUTEarea = L * Wamount = qty * rategroupby subtotalsWRITEto_excel, index=FalseRooms + By-floor tabsThe finished workbook is the output of a script - re-run it and every number updates from the new source.openpyxl is the helper pandas uses to read and write .xlsx underneath.
Zoom
The schedule-and-BOQ workflow as a pipeline: read the source workbook, verify and clean the columns, compute areas and costs and group into subtotals, then write a finished multi-tab workbook back out. The whole deliverable becomes one script you re-run every revision.

Computing the numbers a schedule reports

With clean columns in hand, the calculations are the whole-column arithmetic from the last lesson, now doing real work. A room schedule wants area per room and a running total; a BOQ wants cost per line and a grand total:

python
rooms["area_sqm"] = rooms["length_m"] * rooms["width_m"]
rooms["area_sqm"] = rooms["area_sqm"].round(2)

total_area = rooms["area_sqm"].sum()
print(f"Total area: {total_area:.2f} sqm")

Each line operates on the entire column, so it does not matter whether the schedule has eight rooms or eight hundred. round(2) keeps the areas to a sensible two decimals - a small courtesy that stops a schedule showing 23.999999 square metres. For a bill of quantities the same shape gives you cost, and groupby gives you the subtotals a BOQ is organised around:

python
boq = pd.read_excel("project.xlsx", sheet_name="BOQ")
boq["amount"] = (boq["qty"] * boq["rate"]).round(2)
by_trade = boq.groupby("trade")["amount"].sum().round(2)
grand_total = boq["amount"].sum().round(2)

That is a complete quantity roll-up: a per-line amount, a subtotal per trade, and a grand total - the three numbers every bill of quantities exists to state. The point is not that any one calculation is hard; it is that all of them are now written down, so the schedule and the BOQ are computed the same way every time, and a rate change propagates through every dependent number the instant you re-run.

This is also where a designer's judgement stays firmly in charge. The script computes carpet area, but which walls and voids to deduct, whether balconies count at half, how to treat a double-height space - those are decisions you encode, and encoding them in code makes them explicit and reviewable rather than buried in a spreadsheet formula nobody remembers writing. A useful habit is to keep the raw source columns and add your computed ones alongside, never overwriting the inputs, so anyone can trace a final number back to where it came from. When a QS or an authority queries a figure, you can point at the exact line of code that produced it - a level of traceability a hand-built spreadsheet rarely offers, and one that quietly builds trust in your numbers.

A BOQ: COMPUTE THEN SUBTOTALamount = qty * rateitemqtyrateamountrcc slab208000160000rcc beam6900054000plaster12025030000rcc: 214000plaster: 30000groupby(trade).sum()Per-line amount (computed column) + per-trade subtotal (groupby) = the numbers a BOQ exists to state.Write both tabs to one workbook with ExcelWriter and the deliverable is done.
Zoom
A bill of quantities with its computed column and subtotal. The qty and rate columns come from the source file; the amount column is computed once across the whole table with qty times rate, and groupby by trade produces the subtotal rows a BOQ is organised around.

Writing it back - the sheet your team opens

A calculation nobody can open is not a deliverable. The move that makes this lesson practical is writing your finished DataFrame back out to a file colleagues use. pandas does it with one method each way:

python
rooms.to_csv("room_schedule_out.csv", index=False)
rooms.to_excel("room_schedule_out.xlsx", sheet_name="Rooms", index=False)

index=False is the argument to remember: without it, pandas writes its 0,1,2 row index as an extra unlabelled column that confuses everyone who opens the sheet. To write several tables into one workbook - the schedule on one tab, the trade subtotals on another - use an ExcelWriter:

python
with pd.ExcelWriter("deliverable.xlsx") as writer:
    rooms.to_excel(writer, sheet_name="Rooms", index=False)
    by_trade.to_frame("amount").to_excel(writer, sheet_name="By trade")
    boq.to_excel(writer, sheet_name="BOQ", index=False)

The with block opens the file, writes each tab, and closes it cleanly. Underneath, pandas uses openpyxl to speak Excel's format - the helper you installed in lesson 4.1 - and for finer control (bold headers, column widths, number formats) you can reach into openpyxl directly on the same workbook. But for most deliverables, to_excel with sensible sheet names and index=False produces a clean, openable file. The full arc - read the source, compute, summarise, write the result - is now a single script, and that script is your schedule.

A couple of practical cautions make writing files safe. First, to_excel overwrites the target file without asking, so never write back onto the source workbook you read from - always write to a new, clearly-named output file so a bad run cannot destroy your input. Second, if the output file is already open in Excel when your script runs, the write will fail with a permission error; close it first. And when you want the styled, branded look a practice expects, the cleanest pattern is to keep a formatted template workbook - headers, fonts, column widths and a logo already set - and have the script fill only the data cells, leaving the presentation untouched. That separation keeps the calculation logic in pandas and the visual polish in a file a non-coder on your team can maintain.

READ - COMPUTE - WRITEREADproject.xlsxread_excel + verifyCOMPUTEarea = L * Wamount = qty * rategroupby subtotalsWRITEto_excel, index=FalseRooms + By-floor tabsThe finished workbook is the output of a script - re-run it and every number updates from the new source.openpyxl is the helper pandas uses to read and write .xlsx underneath.
Zoom
The schedule-and-BOQ workflow as a pipeline: read the source workbook, verify and clean the columns, compute areas and costs and group into subtotals, then write a finished multi-tab workbook back out. The whole deliverable becomes one script you re-run every revision.

index=False or you ship a stray 0,1,2 column. ExcelWriter puts many tables in one workbook.

The end-to-end script - your deliverable as code

Put the three moves together and you have a small program that turns a source file into a finished, multi-tab workbook. Written one clear step at a time, it reads like the process it automates:

python
import pandas as pd

# 1. read
rooms = pd.read_excel("project.xlsx", sheet_name="Rooms")
rooms["length_m"] = pd.to_numeric(rooms["length_m"], errors="coerce")
rooms = rooms.dropna(subset=["length_m", "width_m"])

# 2. compute
rooms["area_sqm"] = (rooms["length_m"] * rooms["width_m"]).round(2)
by_floor = rooms.groupby("floor")["area_sqm"].sum().round(2)

# 3. write
with pd.ExcelWriter("schedule_out.xlsx") as writer:
    rooms.to_excel(writer, sheet_name="Rooms", index=False)
    by_floor.to_frame("area_sqm").to_excel(writer, sheet_name="By floor")

print(f"Wrote {len(rooms)} rooms, total {rooms['area_sqm'].sum():.2f} sqm")

Run it and a clean workbook appears with a Rooms tab and a By-floor summary. Nothing here is new - it is read, clean, compute, group and write, the moves of this whole module assembled into one useful thing. What changed is the stance: you are no longer poking at data to learn, you are producing a document. The honest caveat is that not every sheet is worth scripting - a one-off, ten-row table is faster to type in Excel, and you should. The script earns its place when the sheet is large, recomputed often, or error-prone by hand. When it does, this pattern turns an evening of careful, fragile spreadsheet work into a command you run in a second, the same correct way every time.

There is a compounding benefit that only shows up over a project's life. The first time you script a schedule it may take longer than doing it by hand - you are debugging column names and chasing a mistyped cell. But a building project revises its schedules and quantities many times, and every revision after the first is nearly free: change the source, re-run, re-issue. Across a project that might mean twenty regenerations, the script wins many times over, and it wins on correctness as much as speed, because the twentieth revision is computed by exactly the same logic as the first, with no fresh chance for a dragged formula to break. The setup cost is paid once; the correctness is banked on every revision that follows, which is precisely the kind of steady, unglamorous return that makes scripting worth learning for real project work rather than for its own sake. That is the real argument for scripting your paperwork: not that it is clever, but that it makes a repeated, error-prone job both faster and more trustworthy every time it comes round again.

A BOQ: COMPUTE THEN SUBTOTALamount = qty * rateitemqtyrateamountrcc slab208000160000rcc beam6900054000plaster12025030000rcc: 214000plaster: 30000groupby(trade).sum()Per-line amount (computed column) + per-trade subtotal (groupby) = the numbers a BOQ exists to state.Write both tabs to one workbook with ExcelWriter and the deliverable is done.
Zoom
A bill of quantities with its computed column and subtotal. The qty and rate columns come from the source file; the amount column is computed once across the whole table with qty times rate, and groupby by trade produces the subtotal rows a BOQ is organised around.
Functions & tools you met in this lesson

pd.read_excel arguments

sheet_name, header, skiprows - cope with real workbooks that are not one clean sheet

Always follow with head() and info(). Excel is where numbers hide as text; verify types before you compute.

pd.to_numeric(errors=coerce)

Convert a text column to numbers, marking un-convertible cells as missing

The honest fix for a length or cost column that came in as text because of one stray value.

to_csv / to_excel (index=False)

Write a DataFrame back out to a file colleagues can open

index=False stops pandas writing its 0,1,2 row index as a mystery extra column.

pd.ExcelWriter + openpyxl

Write several tables into one multi-tab workbook; the engine that speaks .xlsx

Use a with-block so the file is closed cleanly. Reach into openpyxl for bold headers and number formats.

Hands-on workshop

Workshop - script a room schedule end to end

You will build the full read-compute-write arc: take an Excel room list, compute areas and a per-floor summary, and write a clean two-tab workbook - a deliverable produced entirely by script.

Python 3 with pandas and openpyxl installed (pip install pandas openpyxl), and Excel or a spreadsheet app to make and check the workbook.

Given & goal
Goal: read an Excel schedule, compute areas and subtotals, write a finished workbook
Inputs: a project.xlsx with a Rooms sheet holding room, floor, length_m, width_m
Time: ~45 minutes
  1. 1Make project.xlsx with a Rooms sheet of about eight rooms across two floors, with lengthm and widthm columns - deliberately type one length as text like 3.5m to create a mixed-type column.
  2. 2Read it with pd.readexcel("project.xlsx", sheetname="Rooms") and run info() - notice length_m is object type, not float, because of the text cell.
  3. 3Fix it with rooms["lengthm"] = pd.tonumeric(rooms["length_m"], errors="coerce"), then drop the now-missing row with dropna, and confirm the type is float64.
  4. 4Compute rooms["areasqm"] = (rooms["lengthm"] * rooms["widthm"]).round(2) and a summary byfloor = rooms.groupby("floor")["area_sqm"].sum().round(2).
  5. 5Write both to one workbook with an ExcelWriter block: the rooms table to a Rooms tab with index=False, and byfloor.toframe("area_sqm") to a By-floor tab.
  6. 6Open the output in Excel to confirm it is clean, then change a width in the source and re-run to watch the deliverable regenerate itself.

You’ll walk away with
A script that reads project.xlsx, verifies and cleans the numeric columns, computes areas and a per-floor total, and writes a two-tab schedule_out.xlsx that opens cleanly in Excel.

The worked example

Three altitudes on the same idea

Read the band that fits you — or all three.

For the architectAutomate busywork & build custom tools

The area statement and the tender BOQ are your highest-value scripting targets. Read the model export, compute gross and carpet areas, group by floor and by use for the statutory statement, and write a clean workbook the authority and the QS can both open. Because the logic is written down, a late design change does not mean re-checking a spreadsheet by hand at midnight - it means re-running one command and re-issuing, with every subtotal guaranteed consistent.

For the interior designerScripts for data, schedules & layouts

Your FF&E budget is a read-compute-write loop waiting to be scripted. Pull the specification workbook in, compute line amounts from quantity and unit rate, group by room and by category for the subtotals a client reviews, and write it back to a tidy multi-tab Excel file with index=False so it opens clean. When a supplier revises rates, you change the source and re-run rather than re-totalling three hundred lines and hoping you caught them all.

For the studentA hireable computational skill

Being able to say you scripted a real BOQ or area statement is a genuinely strong portfolio line. Estimation, quantity surveying and BIM-data roles all value someone who can read a messy project spreadsheet, compute the numbers reliably and write a clean output. Practise on any real sheet you can find - a studio cost plan, a materials list - because the read, compute with groupby, write-to-Excel arc here is exactly the workflow those jobs run on every day.

Misconception check

Writing a schedule with code will lose all my Excel formatting, so it is not worth it for a real deliverable.

You do lose the formatting if you stop at to_excel with defaults - but that is a solved problem, not a dead end. pandas writes the correct data and structure; the formatting layer is a separate step, handled by openpyxl, which pandas already uses under the hood. Through it you can set bold headers, column widths, number formats and borders on the same workbook after pandas writes the data, or start from a formatted template file and let your script fill in the numbers. For many working deliverables clean default output with sensible sheet names is genuinely enough, and where presentation matters you keep a styled template and script only the data. The formatting is a finishing pass, not a reason to keep doing the whole schedule by hand.
Try it

Do it yourself

Trace the read-compute-write arc in your head before you run it.

  1. 1Which argument to to_excel stops pandas writing its row index as an extra column, and why does it matter?
  2. 2A cost column came in as text. Which function converts it to numbers and marks the bad cells as missing?
  3. 3What does an ExcelWriter with-block let you do that a single to_excel call does not?
  4. 4Name the three stages of the end-to-end script and one thing that happens in each.
  5. 5Give one case where scripting a schedule is not worth it, and say why.
Take this with you

The one line to carry out

Read the source workbook, verify and compute with whole-column arithmetic and groupby, then write the finished multi-tab file back out with to_excel and index=False. The deliverable becomes a script you re-run every revision, correct the same way every time - which is exactly when scripting a schedule is worth it.
Take it further
References & further reading

Peer-reviewed journals & authoritative standards

  1. 01pandas - Python Data Analysis Librarypandas.pydata.org, 2026.
  2. 02Comma-separated valuesWikipedia, 2026.
  3. 03pandas (software)Wikipedia, 2026.
  4. 04The Python Standard Librarydocs.python.org, 2026.
Related lessons
Recap
This is where the module pays off: the read-compute-write arc that produces a real deliverable. readexcel loads a real workbook - always verified with head() and info() and pd.tonumeric because Excel hides text in number columns - then whole-column arithmetic and groupby compute the areas, amounts and subtotals a schedule or BOQ reports. tocsv and toexcel, with index=False, write the result back to a file colleagues open, and ExcelWriter puts several tables in one workbook. The whole document becomes a script you re-run when the source changes, provided the sheet is big or repeated enough to be worth automating.
Carry forward →

You can now produce the numbers and the sheets. The last step of the module is to make those numbers legible at a glance - turning areas, costs and quantities into bar, line and pie charts with matplotlib, and saving them as images for a report or a board.

A

The author

Amogh N P

Architect, interior designer, and creative polymath. Studio Matrx began in his notebooks — his vision of design made honest, useful, and open to everyone. Its Academy is written and taught in his memory, and free, forever.

More about Amogh →