<jupyter_start><jupyter_text>PyESAPI: Example*By Michael.Folk<EMAIL>*<jupyter_code>import pyesapi
from matplotlib import pyplot as plt
import numpy as np
from time import time
import atexit
#load app only once
app = pyesapi.CustomScriptExecutable.CreateApplication('python_demo')  # script name is used for logging
# setup clean exit
atexit.register(app.Dispose);
import pandas as pd
print(
    "Patients:\n",
    pd.DataFrame(
        [(p.Id, p.LastName, p.FirstName) for p in app.PatientSummaries], # pythonnet treats collections as iterables
        columns = ['Id', 'Last Name', 'First Name']
    )
)
patient = app.OpenPatientById('TestUpperBody')
for plan in patient.CoursesLot(0).PlanSetups:
    print(plan.Id)
# shortcut for patient.Courses.ElementAt(0).PlanSetups.FirstOrDefault(lambda x: x.Id == 'IMRT' )
plan = patient.CoursesLot(0).PlanSetupsLot('IMRT')

# normal indexing works too
structures = patient.StructureSetsLot()[0].StructuresLot()

# lot.Select takes a function and returns a lot
lungs = structures.Select(lambda s: 'Lun' in s.Id)
print("Lungs:",[(f.Id,f.Volume) for f in lungs])

body1 = patient.StructureSetsLot()[0].StructuresLot('BODY')
body = structures['BODY']  # another shortcut for FirstOrDefault on Id field
assert body == body1  # same object

voxels = plan.Dose.np_voxel_locations()  # a pyesapi extension!
print(voxels[0,0,0])
#voxels = plan.StructureSet.Image.np_voxel_locations()  # a pyesapi extension!
# let's grab some structure masks using pysapi extension method
# this is actually a little slow, but worth the wait... (better impemented in c++ and added to ESAPI)
structures_of_interest = [_.Id for _ in plan.StructureSet.Structures]
masks = {}
tic = time()
for s in structures:
    if s.Id in structures_of_interest:
        print("Creating mask for {} at Dose grid resolution...            ".format(s.Id),end='\r')
        masks[s.Id] = plan.Dose.np_structure_mask(s)  # pysapi extension!
        #print("Creating mask for {} at CT Image resolution...            ".format(s.Id),end='\r')
        #masks[s.Id] = plan.StructureSet.Image.np_structure_mask(s)  # pysapi extension!
print("Creating structure masks took {:0.2f} s                   ".format(time()-tic))

tic = time()
dose = plan.Dose.np_array_like()  # pysapi extension! (Dose at Dose grid resolution, default)
#dose = plan.Dose.np_array_like(plan.StructureSet.Image)  # pysapi extension! (Dose at CT Image resolution)
print("Extracting dose took {:0.2f} s".format(time()-tic))
# plot a dose slice ...
assert plan.DoseValuePresentation == pyesapi.DoseValuePresentation.Relative, "dose not in relative units"
slice_idx = 50
slice_z_mm = voxels[0,0,slice_idx][2]  # a 3D array of 3D points of locations for each voxel
print(dose.shape)
plt.imshow(dose[:,:,slice_idx].T,interpolation=None,cmap='jet')  # indexed as [x,y,z], transpose needed for imshow
plt.axis('off')
plt.colorbar()
plt.title("Rx Relative Dose (Z = {:.1f})".format(slice_z_mm))
plt.show()
# plot masked dose ...
all_masks = np.zeros_like(masks['BODY'])
for k,mask in masks.items():
    if k == 'BODY':
        continue
    all_masks = np.logical_or(all_masks,mask)

plt.imshow((dose*all_masks)[:,:,slice_idx].T,interpolation=None,cmap='jet')  # mask is indexed same as dose grid
plt.axis('off')
plt.colorbar()
plt.title("")
plt.show()
# let's compute some DVH "by hand" and compare to Eclipse

plt.figure(figsize=(10,7))
for sId in structures_of_interest:
    mask_idx = np.where(masks[sId])
    tot_vox = np.ones_like(dose)[mask_idx].sum()
    hist,bins = np.histogram(dose[mask_idx].flatten(),bins=1000,range=(0,dose.max()))

    plt.plot(bins[:-1],100.-hist.cumsum()*100.0/tot_vox,label=sId)
    dvh = plan.GetDVHCumulativeData(
        structures[sId],
        pyesapi.DoseValuePresentation.Relative,
        pyesapi.VolumePresentation.Relative,
        .01
    )
    pts = np.array([[p.DoseValue.Dose,p.Volume] for p in dvh.CurveData])
    plt.plot(pts[:,0],pts[:,1],'k--',alpha=.33)

plt.legend(loc=0)
plt.title("Mask-Calculated DVH vs. Eclipse DVH (gray dashed lines)")
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1414240274039638, 'fraction_numerical': 0.011010521164668462, 'mean_word_length': 4.4361702127659575, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '466618', 'license': 'MIT', 'n_tokens_mistral': 1505, 'n_tokens_neox': 1423, 'n_words': 344, 'path': 'examples/example.ipynb', 'repo_name': 'jazb83/PyESAPI', 'size': '4095'}