Export linear measurements as a table

I am trying to take multiple linear measurements from a bone using the markups tool, then export the lengths (distances) as a table. This has proven to be incredibly complicated, with posts discussing creating a database in excel from json files, or using python scripts. I can export a single measurement, but I don’t know how to export a table of measurements. I would be content with copy/paste if I could get the lengths in a single table. Again, I don’t need coordinates, points, or anything else, just the measurement name and the length value. Am I missing something really obvious?
Thanks!

Measurements are saved in the json file. I am not sure if there is a readily available way to export a bunch of measurements from different line Markups. You can use chatGPT or other LLMs to help you create a simple script to do it.

1 Like

As Murat noted, you can try something along the following line:

# === Markups → CSV: Node name + numeric value + units ===
# Paste into Slicer's Python console.

import os, csv, datetime
import slicer

# --- Choose output file ---
def pick_save_path(default_name):
    try:
        import qt
        dlg = qt.QFileDialog()
        dlg.setAcceptMode(qt.QFileDialog.AcceptSave)
        dlg.setNameFilter("CSV (*.csv)")
        dlg.selectFile(default_name)
        if dlg.exec():
            return dlg.selectedFiles()[0]
    except:
        pass
    return os.path.join(slicer.app.temporaryPath, default_name)

ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
out_path = pick_save_path(f"markups_values_units_{ts}.csv")

# --- Collect Markups nodes ---
markups_nodes = slicer.util.getNodesByClass("vtkMRMLMarkupsNode")

# --- CSV output ---
header = ["NodeName", "Value", "Units"]
rows = []

for node in markups_nodes:
    name = node.GetName() or ""
    mcount = node.GetNumberOfMeasurements()

    if mcount == 0:
        rows.append([name, "", ""])
        continue

    for i in range(mcount):
        m = node.GetNthMeasurement(i)

        try:
            value = m.GetValue()
        except:
            value = ""

        units = m.GetUnits() or ""

        rows.append([name, value, units])

# --- Write CSV ---
os.makedirs(os.path.dirname(out_path), exist_ok=True)
with open(out_path, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(header)
    writer.writerows(rows)

print(f"[Markups → CSV] {len(rows)} rows written to:\n{out_path}")
slicer.util.delayDisplay(f"Export complete:\n{out_path}", 1500)

2 Likes

This works beautifully, thanks for the help!