Studio Matrx Monthly · Volume 1 · Issue 3 · August 2026
Amogh N P
 In loving memory of Amogh N P — Architect · Designer · Visionary 
Extracting & Editing Model DataLesson 7.4
PSD for Architecture, Planning & Urban Design/Module 7 · Scripting Revit & Dynamo

Lesson 7.4 · Scripting Revit & Dynamo

Extracting & Editing Model Data

Round-tripping the model - pull a schedule to CSV, edit it in a spreadsheet or pandas, and push it back, keyed by ElementId

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

Editing a hundred parameters is miserable in Revit and pleasant in a spreadsheet. So take the data out, edit it there, and push it back - matched to the right elements by their id.

Revit is a wonderful place to build a model and a clumsy place to bulk-edit data. Retyping a parameter across a hundred elements, cell by cell in a schedule, is slow and error-prone. A spreadsheet - or a few lines of pandas - is the opposite: filtering, find-and-replace, formulas and a second pair of eyes all come naturally there.

So the professional move is a round-trip: extract the elements and parameters you care about to a CSV, edit that file wherever editing is easiest, then read it back and write the changes into the model. The one idea that makes it safe is the ElementId - the stable numeric key you carry in every row so that, on the way back, each value lands on exactly the element it came from. This lesson builds that loop end to end, and it is where Module 7 shakes hands with the data skills from Module 4.

Model -> CSV -> edit -> CSV -> model. ElementId is the ticket that gets each value home.

Extracting: model to CSV

Extraction is a read-only collect-and-loop that builds rows of data and writes them to a file. Collect the elements, and for each one gather the fields you want into a list - crucially starting with the ElementId, which is your key for the trip home. Then write it with Python's csv module:

python
import csv

rows = []
for w in walls:
    comments = w.LookupParameter("Comments")
    rows.append([
        w.Id.IntegerValue,                  # the key - keep it first
        w.Name,                             # wall type, for the human reader
        comments.AsString() if comments else "",
    ])

with open(r"C:\\temp\\walls.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["Id", "Type", "Comments"])
    writer.writerows(rows)

That is the whole export: a header row, then one row per wall. Two design choices matter. Put the ElementId in every row and never edit it - it is what makes the round-trip possible, and a human editor should treat it as read-only. And include a couple of human-readable columns like the type name, even though you will not write them back, so whoever edits the file has context and is not staring at bare numbers. In Dynamo you can do the same with Data.ExportCSV or the Excel.WriteToFile nodes instead of the csv module, which is handy when the rest of your logic is a graph. Either way the output is a plain table anyone can open - and that portability is exactly the point.

One practical note on where the file goes. The open path in these examples is a Windows path because Revit runs on Windows, and the r"..." prefix makes it a raw string so the backslashes are taken literally rather than read as escape characters. Pick a location you control - a project folder or a temp directory - not somewhere buried, so the file is easy to find and hand to whoever edits it. And write a header row every time: it is what lets csv.DictReader read the file back by column name on the return trip, so the export and the import stay in step even if you add or reorder columns later.

THE DATA ROUND-TRIPRevit modelelementsCSVId + valueseditsheet /pandasmodelwrite backreadcleanSet(tx)Read is free; write-back needs a transaction. The Id column rides along the whole way.Revit builds - the spreadsheet edits - the API writes. Each tool does its best part.
Zoom
The round-trip pipeline. Read the model to a CSV (ElementId first), edit that file in a spreadsheet or with pandas where editing is easy, then write it back into the model inside a transaction. Revit builds, the spreadsheet edits, the API writes - each tool doing the part it is best at.

Editing where editing is easy - spreadsheet or pandas

Once the data is a CSV, you are out of Revit and into friendlier territory. For a colleague with no code, that means Excel or Google Sheets: sort, filter, find-and-replace, fill a column with a formula, and let someone review the change before it touches the model. For you, it means pandas - the library from Module 4 - which turns the same edits into a few auditable lines:

python
import pandas as pd

df = pd.read_csv("walls.csv")

# fill every blank Comments cell with a placeholder
df["Comments"] = df["Comments"].fillna("TBC")

# standardise a value everywhere it appears
df["Comments"] = df["Comments"].replace("chk", "Checked")

df.to_csv("walls_edited.csv", index=False)

This is the payoff of connecting BIM to the data course. Everything you learned about cleaning and transforming tabular data - filling missing values, standardising text, joining against a lookup table of, say, room numbers to finish codes - now applies directly to model data. A rule that would be fiddly to express against Revit elements ("set the finish code from this mapping, but only for rooms on level 2") is natural in pandas. The key discipline is simple: edit the value columns freely, but leave the `Id` column untouched. Whether the editing happens in a spreadsheet by hand or in pandas by code, the file that comes out the other side still carries the id that will steer each value back to its element.

Edit the value columns. Never touch the Id column - it is the ticket home.

Pushing back: CSV to model, by ElementId

The return trip reads the edited file and writes each value onto the element its id names - and because it changes the model, it happens inside a transaction. Build a lookup from the CSV, then loop, fetching each element by id with doc.GetElement(ElementId(...)):

python
import csv
from Autodesk.Revit.DB import ElementId, Transaction

edits = {}
with open(r"C:\\temp\\walls_edited.csv", newline="") as f:
    for row in csv.DictReader(f):
        edits[int(row["Id"])] = row["Comments"]

t = Transaction(doc, "Apply edited comments")
t.Start()
for eid, comment in edits.items():
    el = doc.GetElement(ElementId(eid))
    if el:
        p = el.LookupParameter("Comments")
        if p and not p.IsReadOnly:
            p.Set(comment)
t.Commit()

This reuses everything from the earlier lessons: parse the file, look each element up by its ElementId, guard for a missing element or parameter, and Set inside one transaction. The id is doing the heavy lifting - it is why row 47 in the spreadsheet updates the right wall and not some other. A few honest cautions keep the round-trip trustworthy. Do not sort or delete the Id column in the spreadsheet; if an id changes or vanishes, its value cannot get home. Match parameter types - a text column writes to a text parameter; numbers need to be in Revit's internal units. And test on a copy first: a round-trip touching a hundred elements is a hundred changes, all landing at once. Get the id discipline right, though, and you have a repeatable, reviewable pipeline between the model and the spreadsheet world.

Designing a good export, and keeping the file honest

A round-trip is only as reliable as the file in the middle, and a little care at export time prevents most of the trouble at write-back. The first decision is which columns to include. Always the ElementId as the key, then the value columns you actually intend to change - and, for the human editing the file, a few read-only context columns like the type name, level or room number so the data is legible. Mark those context columns clearly, or simply do not write them back, because the write-back step should touch only the parameters you meant to edit.

The second decision is types and units. A CSV is all text, so a number leaves the model as text and must be converted back on the way in - int(row["Count"]) or float(row["Area"]) - before it is Set. Lengths are the sharp edge again: the model stores them in internal feet, so if you export a raw AsDouble height the editor sees 9.84, not 3000. Either export with AsValueString for human-friendly values and convert carefully on the way back, or agree that a particular column is in internal units and say so in the header. Whatever you choose, be consistent, because a silent unit mismatch writes plausible-looking wrong numbers into the model.

Third, protect the key column. Tell anyone editing the file that Id is read-only, keep it first, and avoid spreadsheet habits that separate ids from their rows - a sort that reorders whole rows is fine because each id travels with its row, but deleting the column, editing an id, or pasting values across rows is not. On the way back, always guard with if el: after doc.GetElement, so a missing or mistyped id becomes a safely skipped row rather than a crash or a mis-write.

Finally, keep the files. The exported original and the edited version together are an audit trail: a quick diff shows exactly what changed, which is invaluable when a value is later questioned. Treat the CSV not as throwaway scratch but as a small, honest record of a model change. Get these habits right - clear columns, deliberate types, a protected key, and kept files - and the round-trip stops being fragile and becomes something you would trust on a real project, which is the whole point of moving data out of the model and back.

Id first and read-only; convert types and units deliberately; keep the files as an audit trail.

Why the round-trip is worth it

You might ask why bother with files at all when you could edit parameters directly in a script. Sometimes you should - a simple, rule-based bulk edit belongs in a single script with no spreadsheet in sight. The round-trip earns its extra step in three situations, and recognising them is the judgement here.

First, when a human needs to edit or review. Not everyone codes, but everyone can work a spreadsheet, so exporting lets a project architect correct fire ratings or a QS check quantities without touching Revit or Python - and the file is a reviewable record of what changed. Second, when the edit is data-shaped rather than rule-shaped: messy find-and-replace, joining against an external price list or a client's naming schedule, reconciling two sources - all of which are exactly what pandas and spreadsheets are built for and what raw API code is clumsy at. Third, when you want a paper trail: the exported and edited CSVs are an audit record you can diff, keep and hand over.

This is the quiet lesson of the whole module: BIM data is just data, and once it is in a CSV it obeys every skill from Module 4. Scripting Revit is not a separate island from the rest of your Python - it is the same points, lists, dictionaries and DataFrames, pointed at a building. The model becomes one more data source you can extract, transform and load, and the round-trip is the bridge that lets the friendliest tool for each step - Revit to build, a spreadsheet or pandas to edit, the API to write back - each do the part it is best at.

ELEMENTID = THE JOIN KEYCSV rows348921Checked3489442 hr348970TBCModel elementsWall Id 348921Wall Id 348944Wall Id 348970GetElement(ElementId(id))Same id both sides means each value lands on the right element. Edit the values, never the Id.
Zoom
The ElementId is the join key. Each CSV row carries the id of the element it came from, so on the way back doc.GetElement(ElementId(id)) matches row to element exactly - row 47 updates wall 348921 and no other. Edit the value columns freely; never touch the Id.
Tools & terms you'll meet in this lesson

csv module

Python's standard reader and writer for CSV files

csv.writer to export rows, csv.DictReader to read the edited file back by column name; from Module 3, no install needed.

ElementId as key

The stable id carried in every row to steer values home

Keep it in column one, never edit it; on the return trip doc.GetElement(ElementId(id)) fetches the exact element to update.

pandas DataFrame

The Module 4 table for cleaning and transforming the exported data

read_csv, fillna, replace, merge against a lookup - every data-cleaning skill now applies to model data.

round-trip (ETL)

Extract to a file, transform there, load back to the model

The same extract-transform-load idea as any data pipeline; worth it when a human edits, the change is messy, or you want an audit trail.

Hands-on workshop

Workshop - a comments round-trip

Run the whole loop once on safe, low-stakes data: export a Comments column, edit it outside Revit, and push it back keyed by ElementId. Do it on a copy of a model so a mistake costs nothing.

Revit with Dynamo or pyRevit, a COPY of a model with a few walls, and a spreadsheet app (or pandas). Never run your first round-trip on a live project file.

Given & goal
Goal: extract Comments to CSV, edit it, write it back by id
Inputs: a copy of a model with a few walls, in Dynamo or pyRevit
Time: ~40 minutes
  1. 1Collect the walls and export three columns - Id, Type, Comments - to a CSV with the csv module (or Dynamo's export node). Confirm the ElementId is column one.
  2. 2Open the CSV in a spreadsheet (or load it with pandas.read_csv). Fill the blank Comments with TBC and change one existing value. Save it, leaving the Id column exactly as it was.
  3. 3In a new script, read the edited CSV with csv.DictReader into a dictionary of {id: comment}.
  4. 4Inside a transaction, loop the dictionary: fetch each element with doc.GetElement(ElementId(id)), guard for None and IsReadOnly, and Set the Comments. Commit.
  5. 5Verify in Revit that the walls now show the edited comments - then deliberately delete an Id row, re-run, and observe that its wall is left untouched. That is the key doing its job.

You’ll walk away with
A working round-trip: a CSV exported from the model, edited outside Revit, and written back so each wall's Comments updates by ElementId - with a note on what happened when an id went missing.

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 round-trip lets non-coders on your team do the editing while code does the plumbing. Export a door or wall schedule, let the project architect correct fire ratings and marks in a spreadsheet they already know, then push it back keyed by ElementId - with the CSV standing as a reviewable record of exactly what changed. It also connects Revit to any external list: a consultant's data, a client's naming schedule, a price list, all joined in pandas before it lands in the model.

For the interior designerScripts for data, schedules & layouts

Your FF&E and finish data is happiest in a spreadsheet, and this is how you keep the model and the spreadsheet in sync. Pull every fixture with its product code and price to CSV, reconcile against a supplier list, fix and standardise there, and push the corrected values back - each row steered to the right family by its id. The tedious retyping in Revit schedules disappears, and your specifications stay accurate and reviewable.

For the studentA hireable computational skill

This lesson is where two courses meet, and that is exactly what makes it portfolio gold. Show a round-trip that extracts model data, cleans it in pandas, and writes it back keyed by ElementId, and you have demonstrated BIM automation and data handling in one artefact - the combination computational-design roles most want. It also proves the deeper point every employer looks for: that you see the model as data and can move it between the right tools.

Misconception check

Exporting to a spreadsheet and back is a hack - real automation edits the model directly in code.

Direct editing and the round-trip are both legitimate, and each fits different work. A clean, rule-based bulk edit - set this value on this category - genuinely belongs in a single script with no file in the loop. But the round-trip is a deliberate, professional pattern, not a shortcut, and it wins whenever a human needs to edit or review the data, when the change is messy and data-shaped rather than a tidy rule, or when you want an auditable record of what changed. Spreadsheets and pandas are simply the better tools for filtering, find-and-replace and joining against external lists, and exporting lets non-coders participate. The mark of skill is choosing the right pattern for the task - not insisting that everything be done inside one script.
Try it

Do it yourself

Trace the data home.

  1. 1Why must the ElementId be included in every exported row and never edited?
  2. 2Which step of the round-trip needs a transaction, and which two do not?
  3. 3Name one situation where a round-trip beats editing parameters directly in a script.
  4. 4How does csv.DictReader help you read the edited file back?
  5. 5What Module 4 skill would you use to fill blank cells before pushing the data back?
Take this with you

The one line to carry out

Extract the model to a CSV keyed by ElementId, edit it where editing is easy - a spreadsheet or pandas - and push it back inside a transaction, each value steered home by its id. BIM data is just data, and this round-trip is the bridge to every skill in Module 4.
Take it further
References & further reading

Peer-reviewed journals & authoritative standards

  1. 01Comma-separated valuesWikipedia, 2026.
  2. 02csv - CSV File Reading and WritingPython documentation, 2026.
  3. 03pandaspandas documentation, 2026.
  4. 04Autodesk RevitWikipedia, 2026.
Related lessons
Recap
The round-trip moves model data to where editing is pleasant and back safely. Extraction is a read-only loop that writes rows - ElementId first - to a CSV. Editing happens in a spreadsheet for non-coders or in pandas for you, touching the value columns but never the Id. Pushing back reads the file, fetches each element by its ElementId inside a transaction, and Sets the value, guarding for missing elements and matching types. It is worth the extra step when a human edits or reviews, the change is data-shaped, or you want an audit trail - and it proves BIM data is just data.
Carry forward →

That closes Module 7: you can script Revit through Dynamo and the API, automate its chores, and round-trip its data. Next, Module 8 turns the same instincts outward - automating files, images, spreadsheets and web data across your whole computer, not just the model.

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 →