i am working on creating a script with the idea being to show some sort of visual between terminal units (mechanical equipment) and thermostats (communication devices) that share the same ‘ID Instance’ text shared parameter". We use this instead of the Mark parameter. so essentially, when the user turns on the script, it shows an analytical line, like a duct system where Revit displays graphical warning markers and web lines, or something graphical that is temporary so that when the user exits the script, nothing is shown anymore.
I am essentially aiming to create a temporary graphical link (analytical line, similar visual cue, screen overlay, model line) between mechanical equipment and thermostats that share a custom ID Instance parameter.
i keep getting this message and i am not sure how to get around it.
“A transaction or sub-transaction was opened but not closed. All changes to the active document made by External Command will be discarded.”
this is what my script looks like so far
import clr
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
# Get document and active view
uidoc = __revit__.ActiveUIDocument
if uidoc is None:
TaskDialog.Show("Error", "No active Revit document open.")
raise Exception("No ActiveUIDocument found.")
doc = uidoc.Document
view = doc.ActiveView
# --- SETTINGS ---
ID_PARAM_NAME = 'ID Instance'
LINE_STYLE_NAME = '<Wide Lines>'
# --- HELPER: Get parameter value ---
def get_id_value(elem):
param = elem.LookupParameter(ID_PARAM_NAME)
if param and param.HasValue:
return param.AsString()
return None
# --- HELPER: Project point to 2D plane ---
def project_to_plane(pt, ref_z):
return XYZ(pt.X, pt.Y, ref_z)
# --- COLLECT ELEMENTS ---
mech_elems = FilteredElementCollector(doc)\
.OfCategory(BuiltInCategory.OST_MechanicalEquipment)\
.WhereElementIsNotElementType().ToElements()
thermo_elems = FilteredElementCollector(doc)\
.OfCategory(BuiltInCategory.OST_CommunicationDevices)\
.WhereElementIsNotElementType().ToElements()
# --- INDEX MECHANICAL EQUIPMENT BY ID ---
mech_by_id = {}
for m in mech_elems:
id_val = get_id_value(m)
if id_val:
mech_by_id.setdefault(id_val, []).append(m)
# --- ESTABLISH Z-PLANE REFERENCE ---
ref_z = 0.0
try:
if hasattr(view, 'SketchPlane') and view.SketchPlane:
ref_z = view.SketchPlane.GetPlane().Origin.Z
elif hasattr(view, 'Origin'):
ref_z = view.Origin.Z
except:
ref_z = 0.0
# --- CREATE LINES ---
lines_to_draw = []
for t in thermo_elems:
id_val = get_id_value(t)
if id_val and id_val in mech_by_id:
t_loc = t.Location
if not isinstance(t_loc, LocationPoint):
continue
t_point = project_to_plane(t_loc.Point, ref_z)
for m in mech_by_id[id_val]:
m_loc = m.Location
if not isinstance(m_loc, LocationPoint):
continue
m_point = project_to_plane(m_loc.Point, ref_z)
line = Line.CreateBound(t_point, m_point)
lines_to_draw.append(line)
# --- FIND <Wide Lines> STYLE ---
graphics_styles = FilteredElementCollector(doc).OfClass(GraphicsStyle).ToElements()
wide_line_style = None
for gs in graphics_styles:
if gs.GraphicsStyleCategory.Name == LINE_STYLE_NAME and gs.GraphicsStyleType == GraphicsStyleType.Projection:
wide_line_style = gs
break
if not wide_line_style:
TaskDialog.Show("Error", "Could not find line style: " + LINE_STYLE_NAME)
raise Exception("Missing graphics style.")
# --- DRAW TEMPORARY LINES ---
detail_lines = []
TransactionManager.Instance.EnsureInTransaction(doc)
for line in lines_to_draw:
try:
detail_line = doc.Create.NewDetailCurve(view, line)
detail_line.LineStyle = wide_line_style
detail_lines.append(detail_line)
except Exception as e:
print("Skipping line: {}".format(str(e)))
TransactionManager.Instance.TransactionTaskDone()
# --- SAFE OK-ONLY DIALOG (PREVENTS CANCEL) ---
td = TaskDialog("Links Drawn")
td.MainInstruction = "Temporary lines shown"
td.MainContent = "Click OK to remove them."
td.CommonButtons = TaskDialogCommonButtons.Ok
td.DefaultButton = TaskDialogResult.Ok
td.Show()
# --- REMOVE TEMPORARY LINES ---
TransactionManager.Instance.EnsureInTransaction(doc)
for dl in detail_lines:
doc.Delete(dl.Id)
TransactionManager.Instance.TransactionTaskDone()
any suggests on how to get this working? Code changes? I feel like it is 99% of the way there.