<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">"""

IN PROGRESS

Description:
This script was written to manually extract tissue thicknesses for the MULTIS in vivo and in vitro experimentation.
Anatomical and indentation trials are analyzed differently.
    Anatomical - All frames between the first and last pulse, arranges from minimum to maximum normal force
    Indentation - Frames from start of indentation to peak normal force of indentation

Getting started:
The user may either hard code the path to the subjectID folder or choose to open a file dialog to browse for the
folder.
The accepted trials are then loaded into a listbox.
Select the trial you would like to analyze by 'double-clicking' the name.
The first frame will appear for analysis.
Move the four red dots to the appropriate locations
    Superficial skin
    Skin/Fat boundary
    Fat/Muscle boundary
    Muscle/Bone boundary
To save results, press 'Enter' on the keyboard (Forces, moments, and thicknesses for that frame are saved to an xml
file)
The 'Next Image' button will take you to the next frame for analysis
When you are finished with analysis you can close the program one of two ways
    'Close Program' button in the lower right corner will close the windows and pretty print the newly created xml file
    The 'X' in the upper right corner will close all windows (without pretty printing the xml file)

    Original Author:
        Erica Morrill
        Department of Biomedical Engineering
        Lerner Research Institute
        Cleveland Clinic
        Cleveland, OH
        morrile2@ccf.org

"""

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import matplotlib.pyplot as plt
from matplotlib import patches
import os
import dicom
import SimpleITK as sitk
import tkFileDialog
from Tkinter import *
import Tkinter as tk
import tkMessageBox
import tdsmParserMultis
import numpy as np
import peakutils
import xml.etree.ElementTree as ET
import lxml.etree as etree
import XMLparser
import math
import Plot_thicknessForce





class FileSelectionApp(tk.Tk):
    """Application to display all of the trials in a list"""

    def __init__(self):
        tk.Tk.__init__(self)

        self.mainApp = App(None)
        self.mainApp.getFiles()
        self.mainApp.ListBox = self

        self.title('Select Location for Analysis')

        self.lb = tk.Listbox()
        self.sb = tk.Scrollbar(orient=VERTICAL, command=self.lb.yview)
        self.lb.config(yscrollcommand=self.sb.set)

        self.lb.grid(column=0, row=0, sticky=(N, W, E, S))
        self.sb.grid(column=1, row=0, sticky=(N, S))
        self.lb.config(width=40, height=30)

        for item in self.mainApp.lstFilesTDMS:
            self.lb.insert("end", item[-30:-5])

        self.lb.bind("&lt;Double-Button-1&gt;", self.OnDouble)

    def OnDouble(self, event):
        """When a location name is specified using a double-click, the execute function begins analysis"""
        widget = event.widget
        selection = widget.curselection()
        value = map(int, selection)
        try:
            self.mainApp.main()
            self.withdraw()
            self.mainApp.execute(value[0])
        except:
            pass

    def yview(self, *args):
        apply(self.yview, args)


class DraggablePatch:
    # draggable rectangle with the animation blit techniques; see
    # http://www.scipy.org/Cookbook/Matplotlib/Animations

    # Modified slightly from matplotlib Advanced User's Guide
    # http://matplotlib.org/users/event_handling.html

    lock = None  # only one can be animated at a time

    def __init__(self, obj):
        self.obj = obj
        self.press = None
        self.background = None

    def connect(self):
        """connect to all the events we need"""
        self.cidpress = self.obj.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.cidrelease = self.obj.figure.canvas.mpl_connect('button_release_event', self.on_release)
        self.cidmotion = self.obj.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)

    def on_press(self, event):
        """on button press we will see if the mouse is over us and store some data"""
        if event.inaxes != self.obj.axes: return
        if DraggablePatch.lock is not None: return
        contains, attrd = self.obj.contains(event)
        if not contains: return

        x0, y0 = self.obj.center
        self.press = x0, y0, event.xdata, event.ydata

        DraggablePatch.lock = self

        # draw everything but the selected patch and store the pixel buffer
        canvas = self.obj.figure.canvas
        axes = self.obj.axes
        self.obj.set_animated(True)
        canvas.draw()
        self.background = canvas.copy_from_bbox(self.obj.axes.bbox)

        # now redraw just the patch
        axes.draw_artist(self.obj)

        # and blit just the redrawn area
        canvas.blit(axes.bbox)

    def on_motion(self, event):
        """on motion we will move the object if the mouse is over us"""
        if DraggablePatch.lock is not self:
            return
        if event.inaxes != self.obj.axes: return

        self.obj.center = (self.obj.center[0], event.ydata)

        canvas = self.obj.figure.canvas

        axes = self.obj.axes

        # restore the background region
        canvas.restore_region(self.background)

        # redraw just the current patch
        axes.draw_artist(self.obj)

        # blit just the redrawn area
        canvas.blit(axes.bbox)

    def on_release(self, event):
        """on release we reset the press data"""
        if DraggablePatch.lock is not self:
            return

        self.press = None
        DraggablePatch.lock = None

        # turn off the patch animation property and reset the background
        self.obj.set_animated(False)
        self.background = None

        # redraw the full figure
        self.obj.figure.canvas.draw()

    def disconnect(self):
        """disconnect all the stored connection ids"""
        self.obj.figure.canvas.mpl_disconnect(self.cidpress)
        self.obj.figure.canvas.mpl_disconnect(self.cidrelease)
        self.obj.figure.canvas.mpl_disconnect(self.cidmotion)

    def getlocation(self):
        return (self.obj.center[1])

class App(tk.Tk):

    def __init__(self,parent):
        tk.Tk.__init__(self,parent)
        self.withdraw()
        self.parent = parent
        self.mm = 0
        self.protocol("WM_DELETE_WINDOW", self.dest)
        # self.FileSelectionApp = FileSelectionApp()
        # self.getFiles()
        # self.main()

    def dest(self):
        self.destroy()
        sys.exit()

    def main(self):
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        self.rowconfigure(2, weight=1)
        self.rowconfigure(3, weight=1)
        self.minsize(600, 550)

        self.h = self.winfo_screenheight()

        self.fig = plt.figure()
        self.fig = plt.figure(figsize=(self.h/80, self.h/100))

        self.frame = tk.Frame(self)
        self.frame.grid(row=0, column=0)

        self.title("Select tissue type on right and then draw rectangle enclosing the respective tissue")

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)

        self.canvas.get_tk_widget().grid(row=0, column=0)

        self.canvas._tkcanvas.grid(row=0, column=0)

        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self)
        self.toolbar.update()
        self.toolbar.grid(row=1, column=0, sticky='ewns')

        # self.get_image(self.DCM_accepted[self.mm])

    def getFiles(self):
        """Get accepted trials for the selected subject, this includes the Ultrasound dicom images, Data tdms files,
        and the TimeSynchronization txt file. The program can either open a File Dialog box to search for the directory,
        or the user can hard code the directory"""

        # Hard code Subject Directory
        self.directoryname = '/home/morrile2/Documents/MULTIS_test/MULTIS001-1'

        self.lstFilesDCM = []  # create an empty list for DICOM files
        self.lstFilesTDMS = []  # create an empty list for TDMS files

        self.masterList, self.num_accept = XMLparser.getAcceptance(self.directoryname)

        #Find DICOM and TDMS files
        for dirName, subdirList, fileList in os.walk(self.directoryname):
            for filename in fileList:
                if ".ima" in filename.lower():  # check whether the file's DICOM
                    self.lstFilesDCM.append(os.path.join(dirName, filename))
                elif ".tdms" in filename.lower():  # check whether the file's TDMS
                    self.lstFilesTDMS.append(os.path.join(dirName, filename))

        # Sort variables by trial number
        self.lstFilesTDMS.sort()
        self.lstFilesDCM.sort()


    def execute(self, kk):
        """Initiate the main application to show the Ultrasound images and interactive GUI for the thickness measurements"""
        # global lstFilesDCM, lstFilesTDMS, mm, location, selectedFrames, conv_fact, data, app, masterList, DCM_img

        self.location = kk

        for x in self.masterList:
            if x[0] == self.lstFilesTDMS[self.location][-30:-27]:
                if x[1] == 1:
                    if self.mm == 0:
                        for DCM in self.lstFilesDCM:
                            if DCM[-65:-62] == self.lstFilesTDMS[self.location][-30:-27]:
                                self.DCM_img = DCM

                                print("Verify that file names correlations")
                                print(self.DCM_img)
                                print(self.lstFilesTDMS[self.location])

                                try:
                                    self.getFrames()
                                    # app.destroy()  # Closes list window because the file selection is complete

                                    if self.mm &lt; len(self.frames):
                                        self.showPlot()
                                except:
                                    tkMessageBox.showerror("Error",
                                                           "The trial you have selected does not have an associated "
                                                           "deltaT XML in the TimeSynchronization folder")
                                    self.ListBox.deiconify()
                else:
                    tkMessageBox.showerror("Error", "The trial you have selected is not an accepted trial")
                    self.ListBox.deiconify()

    def getFrames(self):
        """Get the frames to be analyzed and save the data for those frames. Different for indentation and anatomical
        trials. Indentation contains frames that start at indentation and go through the peak force of the indentation,
        while anatomical analyzes all frames between start and end pulses from minimum to maximum force"""

        #Find the xml file with delta_t
        self.analysis_path = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/TimeSynchronization'
        self.split_name = os.path.split(self.lstFilesTDMS[self.location])
        self.tail = self.split_name[1][0:25]+'_dT.xml'

        self.delta_t_file = self.find_file(self.tail, self.analysis_path)
        print(self.delta_t_file)

        if self.delta_t_file == None:
            return
        else:

            # Extract force information from TDMS file
            self.data = tdsmParserMultis.parseTDMSfile(self.lstFilesTDMS[self.mm])

            Fx = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load Fx'])
            Fy = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load Fy'])
            Fz = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load Fz'])
            Mx = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load Mx'])
            My = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load My'])
            Mz = np.array(self.data[u'State.6-DOF Load'][u'6-DOF Load Mz'])

            F_mag = []
            for f in range(len(Fx)):
                F_mag.append(math.sqrt(Fx[f]**2+Fy[f]**2+Fz[f]**2))

            pulse = np.array(self.data[u'Sensor.Run Number Pulse Train'][u'Run Number Pulse Train'])
            pulse = pulse[:]

            Peaks = peakutils.indexes(pulse, thres=0.5 * max(pulse), min_dist=100)

            doc1 = ET.parse(self.delta_t_file)
            root1 = doc1.getroot()
            loc1 = root1.find("Location")
            dT_str = loc1.find("dT").text
            self.dT = float(dT_str)

            # Read metadata from the dicom image
            self.RefDs = dicom.read_file(self.lstFilesDCM[self.location])
            self.frameTimeVector = self.RefDs.FrameTimeVector
            seq = self.RefDs.SequenceofUltrasoundRegions
            self.conv_fact = seq[0].PhysicalDeltaY * 10  # Extract conversion factor from dicom metadata (Original is in cm, convert
            # to mm)

            if self.lstFilesTDMS[self.location][-8:-7] == 'I':
                indentation = True
                anatomical = False
            elif self.lstFilesTDMS[self.location][-8:-7] == 'A':
                indentation = False
                anatomical = True

            force_list = list(F_mag)

            time = np.arange(len(F_mag))
            data_i = zip(time, Fx, Fy, Fz, Mx, My, Mz, F_mag)

            if indentation:
                # Indentation frames from start of indentation to peak force during indentation
                # Find indentation start time in TDMS timeline , denoted by tdms b/c used for tdms
                avg = self.createAverageFit(F_mag, 300)
                index_range = 200
                for items in range(len(avg[0:-index_range])):
                    if abs(avg[items + index_range] - avg[items]) &gt; 1.5:
                        time_start_tdms = items + index_range / 2
                        break

                time_max_tdms = force_list.index(max(force_list))  # note max and min reversed as Fx is negative force

                start_frame, start_frame_time_tdms = self.findFrame(time_start_tdms)
                max_frame, max_frame_time_tdms = self.findFrame(time_max_tdms)

                frame_lst_i = [start_frame]
                data_i_final = [data_i[start_frame_time_tdms]]

                for t in data_i[start_frame_time_tdms + 1:max_frame_time_tdms]:
                    inc_frame, inc_frame_time_tdms = self.findFrame(t[0])
                    if inc_frame not in frame_lst_i:
                        frame_lst_i.append(inc_frame)
                        data_i_final.append(data_i[inc_frame_time_tdms])

                self.frames = frame_lst_i
                self.DATA = data_i_final

            elif anatomical:
                # Anatomical frames from minimum to maximum normal force (Fx)
                time_preIndent_tdms = Peaks[0]  # 230 ms is location first pulse.
                time_postIndent_tdms = Peaks[-1]

                # Sort the data by the magnitude (F_mag) to get anatomical frame list from minimum to maximum
                data_a = zip(time, Fx, Fy, Fz, Mx, My, Mz, F_mag)
                data_a.sort(key=lambda t: abs(t[7]))

                frame_lst_a = []
                data_a_sort = []

                for t in data_a:
                    try:
                        min_frame, min_frame_time_tdms = self.findFrame(t[0])
                    except:
                        continue
                    if min_frame not in frame_lst_a:
                        if min_frame_time_tdms &gt; time_preIndent_tdms and min_frame_time_tdms &lt; time_postIndent_tdms:
                            frame_lst_a.append(min_frame)
                            data_a_sort.append(data_i[min_frame_time_tdms])

                final_a_sort = zip(frame_lst_a, data_a_sort)
                final_a_sort.sort(key=lambda t: abs(t[1][7]))

                # #Analyze the min, max, and middle force
                self.frames = [final_a_sort[0][0], final_a_sort[int(len(final_a_sort)/2)][0], final_a_sort[len(final_a_sort)-1][0]]
                self.DATA = [final_a_sort[0][1], final_a_sort[int(len(final_a_sort)/2)][1], final_a_sort[len(final_a_sort)-1][1]]


                # #Analyze from min to max
                # for d in final_a_sort:
                #     self.frames.append(d[0])
                #     self.DATA.append(d[1])



    def createAverageFit(self, Fx, avgThres):
        """Filter the tdms normal force data"""
        averagelist = []
        for items in range(len(Fx)):
            if Fx[items] != Fx[items - avgThres]:
                num2avg = Fx[items:(items + avgThres)]
                averagelist.append(np.average(num2avg))
            else:
                continue

        averagelist = [averagelist[0]] * (avgThres / 2) + averagelist[0:-(avgThres) / 2]
        return averagelist


    def find_file(self, name, path):
        for root, dirs, files in os.walk(path):
            if name in files:
                return os.path.join(root, name)


    def findFrame(self, initial_time):
        """Find the frame corresponding to the specified tdms time and return the adjusted tdms time to match the
        selected frame"""
        adjusted_time = self.dT + initial_time
        for f in range(len(self.frameTimeVector)):
            f += 1
            frame_time = sum(self.frameTimeVector[0:f])
            if adjusted_time &lt;= frame_time:
                timeDiff_up = frame_time - adjusted_time
                timeDiff_low = adjusted_time - sum(self.frameTimeVector[0:f - 1])
                if timeDiff_up &lt; timeDiff_low:
                    frame_frame = f
                    readjusted_time_tdms = frame_time - self.dT
                else:
                    frame_frame = f - 1
                    readjusted_time_tdms = sum(self.frameTimeVector[0:f - 1]) - self.dT
                break

        return frame_frame, int(readjusted_time_tdms)


    def showPlot(self):
        """Read and show the appropriate frame of the dicom image in tkinter GUI"""

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        self.minsize(600, 550)

        # Read dicom image
        if self.mm == 0:
            reader = sitk.ImageFileReader()
            reader.SetFileName(self.DCM_img)
            self.img_all = reader.Execute()
            self.deiconify()

        else:
            self.fig.clear()


        # Read in the appropriate dicom frame and set up plot title
        img = self.img_all[:, :, self.frames[self.mm]]
        nda = sitk.GetArrayFromImage(img)
        plt.imshow(nda[:, :, 0], cmap="gray")
        split_name = os.path.split(self.lstFilesTDMS[self.location])
        plt.title('\n'+split_name[1][0:25] + '  :  Frame = ' + str(self.frames[self.mm]) + '\n\n' + str(self.mm + 1) + '  of  ' + str(
            len(self.DATA)) + '\n')

        # Create four circles used to indicate tissue interfaces (Top of skin, skin/fat, fat/muscle, bottom of muscle)
        r = 7
        if self.mm == 0:
            y = [60, 90, 160, 360]
        else:
            y = self.y_new

        circs = [matplotlib.patches.Circle((512, y[0]), radius=r, alpha=0.5, fc='r'),
                 matplotlib.patches.Circle((512, y[1]), radius=r, alpha=0.5, fc='r'),
                 matplotlib.patches.Circle((512, y[2]), radius=r, alpha=0.5, facecolor='r'),
                 matplotlib.patches.Circle((512, y[3]), radius=r, alpha=0.5, facecolor='r')]

        self.drs = []

        # Create main GUI

        self.title("Drag points to tissue boundaries and hit 'Enter' to save")


        # text = Text(root_plot)
        # text.insert(INSERT, "TEST...")
        # text.grid(row=1, column=0, sticky="EW")

        self.ax = plt.gca()
        # Plot the four circles and make them draggable using the DraggablePatch Class
        for circ in circs:
            self.ax.add_patch(circ)
            dr = DraggablePatch(circ)
            dr.connect()
            self.drs.append(dr)

        self.btn1 = tk.Button(self, text="Next Image", command=self.next_image)
        self.btn1.grid(row=2, column=0)
        self.btn2 = tk.Button(self, text="Save and Quit", command=self.end_program)
        self.btn2.grid(row=2, column=0, sticky='e')

        # Press enter when you are happy with circle locations to calculate and record skin, fat, and muscle thicknesses
        cid = self.fig.canvas.mpl_connect('key_press_event',
                                     lambda event: self.on_key(event))

        self.canvas.draw()

    def next_image(self):
        """Gets next image for analysis - Triggered by 'Next Image' button"""
        # global location, mm, selectedFrames, root_plot, y_new
        self.mm += 1

        if self.mm &lt; len(self.frames):
            self.y_new = []
            for p in self.drs:
                self.y_new.append(p.getlocation())
            self.fig.clear()
            self.showPlot()
        elif self.mm == len(self.frames) - 1:
            self.btn1.config(state="disabled")


    def end_program(self):
        """Checks to see if there was an xml file created. If so, it is pretty printed to the filename and the program
        closes all windows. Triggered by the 'Close Program' button"""
        # global app, root_plot
        #
        split_name = os.path.split(self.lstFilesTDMS[self.location])
        xml_name = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/Analysis/' + split_name[1][0:25] + '_manThick.xml'

        if os.path.exists(xml_name):
            self.prettyPrintXml(xml_name)

        self.destroy()
        self.quit()


    def on_exit(self):
        """Closes all windows if the user selects okay, does not pretty print the xml file"""
        if tkMessageBox.askokcancel("Quit", "Do you want to quit without pretty-printing xml file and saving summary figure?"):
            self.destroy()
            app.quit()


    def prettyPrintXml(self, xmlFilePathToPrettyPrint):
        """Pretty print the xml file after all frames have been analyzed"""
        assert xmlFilePathToPrettyPrint is not None
        parser = etree.XMLParser(resolve_entities=False, strip_cdata=False)
        document = etree.parse(xmlFilePathToPrettyPrint, parser)
        document.write(xmlFilePathToPrettyPrint, pretty_print=True, encoding='utf-8')
        try:
            Plot_thicknessForce.PlotSum(xmlFilePathToPrettyPrint)
        except:
            tkMessageBox.showerror("Error", "The plots were not formed because only one data point was measured")


    def on_key(self, event):
        """Enter key was pressed, locations of each point (4) are found and sent to be calculated and saved to xml file"""
        if event.key == 'enter':
            self.coords = []
            for dr in self.drs:
                coord = dr.getlocation()
                self.coords.append(coord)
            self.calc_thicknesses()  # Calculate the skin, fat and muscle thicknesses
            self.create_xml()
            if self.mm == 0:
                self.save_first_image()


    def calc_thicknesses(self):
        """Calculate thicknesses of skin, fat and muscle layers (in pixels) and convert to mm"""
        self.coords.sort()  # Sort the coordinates from lowest to highest to adjust for point switching

        self.skin = (self.coords[1] - self.coords[0]) * self.conv_fact
        self.fat = (self.coords[2] - self.coords[1]) * self.conv_fact
        self.muscle = (self.coords[3] - self.coords[2]) * self.conv_fact

        print(' ')
        print('*****Thickness Calculations*****')
        print('Skin_thickness = %f mm' % self.skin)
        print('Fat_thickness = %f mm' % self.fat)
        print('Muscle_thickness = %f mm' % self.muscle)
        print(' ')


    def create_xml(self):
        """Create xml file with forces, moments, and thicknesses"""

        #Extract data for specific frame (i.e. 'mm')
        data = self.DATA[self.mm]
        fx = data[1]
        fy = data[2]
        fz = data[3]
        mx = data[4]
        my = data[5]
        mz = data[6]

        #Define path for the analysis folder
        split_name = os.path.split(self.lstFilesTDMS[self.location])
        analysis_path = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/Analysis'

        # Check for Analysis directory
        if not os.path.isdir(analysis_path):
            os.makedirs(analysis_path)

        # Name of the xml file
        xml_name = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/Analysis/' + split_name[1][0:25] + '_manThick.xml'

        # Check if an xml file exists for this image. If TRUE, edit the values and if FALSE, create a new one.
        if os.path.exists(xml_name):
            # print('Edit File')
            doc = ET.parse(xml_name)
            root = doc.getroot()
            loc_lst = []
            for loc in root.findall('Frame'):
                loc_lst.append(loc.get('value'))
            tail = str(self.frames[self.mm])

            if tail in loc_lst:
                # Over-write thicknesses: Forces and moments should be the same since the data for this frame has already
                # been recorded
                frm = root.find('Frame[@value="%s"]' %tail)
                Thick = frm.find("Thickness")
                Thick.find("Skin").text = str(self.skin)
                Thick.find("Fat").text = str(self.fat)
                Thick.find("Muscle").text = str(self.muscle)

                tree = ET.ElementTree(root)
                tree.write(xml_name, xml_declaration=True)

            else:
                #Add new child, because information for this frame is not yet in the xml file
                frm = ET.SubElement(root, 'Frame', value=str(self.frames[self.mm]))
                ET.SubElement(frm, "Time", value=str(sum(self.frameTimeVector[0:self.frames[self.mm]])), units="ms")
                Forces = ET.SubElement(frm, "Forces")
                ET.SubElement(Forces, "Fx", units="N").text = str(fx)
                ET.SubElement(Forces, "Fy", units="N").text = str(fy)
                ET.SubElement(Forces, "Fz", units="N").text = str(fz)

                Moments = ET.SubElement(frm, "Moments")
                ET.SubElement(Moments, "Mx", units="Nm").text = str(mx)
                ET.SubElement(Moments, "My", units="Nm").text = str(my)
                ET.SubElement(Moments, "Mz", units="Nm").text = str(mz)

                Thick = ET.SubElement(frm, "Thickness")
                ET.SubElement(Thick, "Skin", units="mm").text = str(self.skin)
                ET.SubElement(Thick, "Fat", units='mm').text = str(self.fat)
                ET.SubElement(Thick, "Muscle", units='mm').text = str(self.muscle)

                tree = ET.ElementTree(root)
                tree.write(xml_name, xml_declaration=True)

        else:
            # print('Make New File')

            TDMS_src = os.path.split(self.lstFilesTDMS[self.location])
            subID = os.path.split(os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])))
            root = ET.Element('Subject', attrib={"ID":subID[1]})
            root.append(ET.Element('Source', attrib={"Filename":TDMS_src[1]}))
            frm = ET.SubElement(root, 'Frame', value=str(self.frames[self.mm]))
            ET.SubElement(frm, "Time", value=str(sum(self.frameTimeVector[0:self.frames[self.mm]])), units="ms")

            Forces = ET.SubElement(frm, "Forces")
            ET.SubElement(Forces, "Fx", units="N").text = str(fx)
            ET.SubElement(Forces, "Fy", units="N").text = str(fy)
            ET.SubElement(Forces, "Fz", units="N").text = str(fz)

            Moments = ET.SubElement(frm, "Moments")
            ET.SubElement(Moments, "Mx", units="Nm").text = str(mx)
            ET.SubElement(Moments, "My", units="Nm").text = str(my)
            ET.SubElement(Moments, "Mz", units="Nm").text = str(mz)

            Thick = ET.SubElement(frm, "Thickness")
            ET.SubElement(Thick, "Skin", units="mm").text = str(self.skin)
            ET.SubElement(Thick, "Fat", units='mm').text = str(self.fat)
            ET.SubElement(Thick, "Muscle", units='mm').text = str(self.muscle)

            tree = ET.ElementTree(root)
            tree.write(xml_name, xml_declaration=True)


    def save_first_image(self):
        split_name = os.path.split(self.lstFilesTDMS[self.location])
        png_path = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/Analysis/PNG/'

        # Check for Analysis directory
        if not os.path.isdir(png_path):
            os.makedirs(png_path)

        png_name = os.path.dirname(os.path.dirname(self.lstFilesTDMS[self.location])) + '/Analysis/PNG/' + split_name[1][0:25] + '_manThick.png'
        self.fig.savefig(png_name)


if __name__ == "__main__":
    app = FileSelectionApp()
    app.mainloop()
</pre></body></html>