Trying to create levels at elevation from excel

Hello,

I am trying to create levels and views from excel file, but scripts fails and keeps running continuously without an error

Code below,

import clr

import os
from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from Microsoft.Office.Interop import Excel

Add reference to necessary Revit API libraries

clr.AddReference(“RevitAPI”)
clr.AddReference(“RevitServices”)

Import the Excel COM library

clr.AddReference(“Microsoft.Office.Interop.Excel”)
from Microsoft.Office.Interop import Excel

Access the active document in Revit

doc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument.Document

Function to read Level data from Excel

def read_levels_from_excel(excel_file_path):
levels_data =

# Create Excel application and open the file
excel_app = Excel.ApplicationClass()
excel_app.Visible = False  # Set to True if you want to see Excel
workbook = excel_app.Workbooks.Open(excel_file_path)
worksheet = workbook.Sheets[1]  # Assuming first sheet

# Read the Excel data starting from the second row
row = 2
while True:
    level_name = worksheet.Cells(row, 1).Value
    elevation = worksheet.Cells(row, 2).Value
    
    if not level_name or not elevation:
        break  # Exit if there is no more data
    
    levels_data.append((level_name, elevation))
    row += 1

# Clean up
workbook.Close(False)
excel_app.Quit()

return levels_data

Path to your Excel file (update this path accordingly)

excel_file_path = r"C:\Users\parikshitthombare\Desktop\Levels-Views & Sheets.xlsm"

Read the level data from Excel

levels_data = read_levels_from_excel(excel_file_path)

Start a transaction to create levels in Revit

with Transaction(doc, “Create Levels”) as trans:
trans.Start()

# Get all existing levels in the project to avoid duplicates
existing_levels = FilteredElementCollector(doc).OfClass(Level).ToElements()
existing_level_names = [level.Name for level in existing_levels]

# Iterate through the level data from Excel and create levels
for level_name, elevation in levels_data:
    if level_name not in existing_level_names:  # Check if the level already exists
        new_level = Level.Create(doc, elevation)
        new_level.Name = level_name     # Set the level name from Excel data

trans.Commit()

Hi Parikshit,

Not sure what your problem is, but I achieved your goal via the following code:

#Imports as usual
import pandas as pd

# ----------------------------------------------------------------
# GLOBAL VARIABLES
# ----------------------------------------------------------------

doc = DocumentManager.Instance.CurrentDBDocument
doc_name = doc.Title

target_path = fr"your_path_here"

# ----------------------------------------------------------------
# EXECUTE
# ----------------------------------------------------------------

# Create dataframe from excel path
df = pd.read_excel(target_path, sheet_name = "Sheet", header = 0, dtype = str) #Change values as necessary
# Convert the DataFrame to a dictionary
df_dict = df.set_index("LevelName")["Elevation"].astype(int).to_dict()

TransactionManager.Instance.EnsureInTransaction(doc)
for levelname, elevation in df_dict.items():
    new_level = Level.Create(doc, elevation)
    new_level.Name = levelname
TransactionManager.Instance.TransactionTaskDone()

target_path contains a simple table consisting of a column named “LevelName” and another named “Elevation”.

Hope that helps!

EDIT: I adjusted my answer above into a more detailed blog post, available here.

Hi @benjaminjamesrowley ,

I’m also trying to work with an Excel file, but it didn’t work for me since my PyRevit environment doesn’t have access to pandas, how did you overcome this?

Try either Interop or OpenXML.

1 Like

Hi @daan0827,

@aaronrumple’s idea may well work (I’ve never tried it). Someone with more coding experience than me may well raise their eyebrows at this, but I need so many external packages in my Revit scripts that I ended up finding another solution.

  1. I located the folder pyRevit is referencing for packages (C:\x\pyRevit-Master\site-packages)
  2. I located the folder in which pandas (or any other package) is saved by running “pip show pandas” in my console.
  3. I ran xcopy /E /I “current location of pandas” “C:\x\pyRevit-Master\site-packages” in the console to copy the contents of the former location into the latter. Whenever it asked me whether to overwrite duplicate files, I chose no.

At the end of this process, pyRevit had all the packages it needed to execute my scripts.

I have used a similar process with Dynamo, which also worked for me.

1 Like

Hi @aaronrumple , @benjaminjamesrowley ,

I haven’t tried OpenXML yet, I’ll try to see if that works for me.

The ‘problem’ which I would have when I would change these settings, is that every user of our PyRevit toolbar, would also have to perform these steps, which is far from ideal because we would like to have the least amount of overhead as possible, since most users are not that tech savvy.

Exactly the issue with using custom packages. You need a deployment plan. If you are an office with limited IT support, this can be time consuming. If everyone has Revit and Excel installed, then Interop and OpenXML area already installed and available. Interop is installed with Office. The OpenXML.dll is installed with Dynamo as well as with Office.