classdef app < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        UIFigure                       matlab.ui.Figure
        StatsTextAreaLabel             matlab.ui.control.Label
        SaveButton                     matlab.ui.control.Button
        savename                       matlab.ui.control.EditField
        Format                         matlab.ui.control.DropDown
        Sidebar                        matlab.ui.control.TextArea
        Image                          matlab.ui.control.Image
        PresetPanel                    matlab.ui.container.Panel
        StatusTextArea                 matlab.ui.control.TextArea
        StatusTextAreaLabel            matlab.ui.control.Label
        CustomSubplotsPanel            matlab.ui.container.Panel
        FilteringforsuddenspikesPanel  matlab.ui.container.Panel
        OnCheckBox                     matlab.ui.control.CheckBox
        PlotSwitch                     matlab.ui.control.Switch
        PlotSwitchLabel                matlab.ui.control.Label
        DeviationEditField             matlab.ui.control.NumericEditField
        DeviationEditFieldLabel        matlab.ui.control.Label
        NeighborsSpinner               matlab.ui.control.Spinner
        Button                         matlab.ui.control.Button
        NeighborsSpinnerLabel          matlab.ui.control.Label
        SearchEditFieldLabel           matlab.ui.control.Label
        ResetSubplotButton             matlab.ui.control.Button
        PlotSubplotButton              matlab.ui.control.Button
        ButtonGroup                    matlab.ui.container.ButtonGroup
        button_yaxis                   matlab.ui.control.ToggleButton
        button_plot                    matlab.ui.control.ToggleButton
        Panel_2                        matlab.ui.container.Panel
        Field_NoSP                     matlab.ui.control.NumericEditField
        textfield                      matlab.ui.control.EditField
        Field_SelectedSP               matlab.ui.control.NumericEditField
        SelectedSubplotEditFieldLabel  matlab.ui.control.Label
        FeaturesPanel                  matlab.ui.container.Panel
        SearchEditField_2Label         matlab.ui.control.Label
        SearchEditField_2              matlab.ui.control.EditField
        SelectDataforFeatureListBox    matlab.ui.control.ListBox
        SelectDataforFeatureListBoxLabel  matlab.ui.control.Label
        yAxisTitle_2                   matlab.ui.control.EditField
        Panel_3                        matlab.ui.container.Panel
        UpperEditField                 matlab.ui.control.NumericEditField
        UpperEditFieldLabel            matlab.ui.control.Label
        LowerEditField                 matlab.ui.control.NumericEditField
        SetLimitsCheckBox              matlab.ui.control.CheckBox
        LowerEditFieldLabel            matlab.ui.control.Label
        yAxisTitleLabel                matlab.ui.control.Label
        SelectDataListBox              matlab.ui.control.ListBox
        SearchEditField                matlab.ui.control.EditField
        LegendonCheckBox               matlab.ui.control.CheckBox
        SelectDataLabel                matlab.ui.control.Label
        yAxisTitle                     matlab.ui.control.EditField
        yAxisLabel                     matlab.ui.control.Label
        SubplotTitle                   matlab.ui.control.EditField
        SubplotTitleEditFieldLabel     matlab.ui.control.Label
        FigureTitleCheckBox            matlab.ui.control.CheckBox
        OverallTitleField              matlab.ui.control.EditField
        OverallTitleEditFieldLabel     matlab.ui.control.Label
        RowsEditField                  matlab.ui.control.NumericEditField
        ColumnsEditField               matlab.ui.control.NumericEditField
        ColumnsLabel                   matlab.ui.control.Label
        RowsLabel                      matlab.ui.control.Label
        SetTimestampsPanel             matlab.ui.container.Panel
        ToWorkspaceButton              matlab.ui.control.Button
        xAxisDropDownLabel             matlab.ui.control.Label
        ResetPanelButton               matlab.ui.control.Button
        LapsListBox                    matlab.ui.control.ListBox
        LapsListBoxLabel               matlab.ui.control.Label
        xAxisDropDown                  matlab.ui.control.DropDown
        UseCheckBox                    matlab.ui.control.CheckBox
        end_s                          matlab.ui.control.NumericEditField
        end_m                          matlab.ui.control.NumericEditField
        end_h                          matlab.ui.control.NumericEditField
        start_s                        matlab.ui.control.NumericEditField
        start_m                        matlab.ui.control.NumericEditField
        start_h                        matlab.ui.control.NumericEditField
        StopLabel                      matlab.ui.control.Label
        StartLabel                     matlab.ui.control.Label
        Label_4                        matlab.ui.control.Label
        Label_3                        matlab.ui.control.Label
        Label_2                        matlab.ui.control.Label
        Label                          matlab.ui.control.Label
        PlottypeLabel                  matlab.ui.control.Label
        PlotPresetsButton              matlab.ui.control.Button
        LoadPresetsButton              matlab.ui.control.Button
        Preset                         matlab.ui.control.DropDown
        PresetsDropDown                matlab.ui.control.DropDown
        LoadFastButton                 matlab.ui.control.Button
        EditField                      matlab.ui.control.EditField
        BrowseButton                   matlab.ui.control.Button
    end

    
    properties (Access = public)
        filepath_last = "none"; % Description
        filepath = "none";
        fig = [];
        laps_strArray = strings();
        time_dhms = datetime();
        timestamp_s = [];
        timestamp_hms = duration();
        timestamp_index = [];
        fns = "none";
        pltData = struct();
        pltstart = [];
        pltstop = [];
        presetflag = 0;
        tr = timerange();
        folder = 0;
        data = struct();
        data_filter = timetable();
    end
    
    methods (Access = private)

        % browse: choose file to load (place .mat file into data)
        function browse(app)
            f = figure('Renderer', 'painters', 'Position', [-100 -100 0 0]); %create a dummy figure so that uigetfile doesn't minimize our GUI
            [name, location] = uigetfile(...
                {'*.m;*.mat',...
                'MATLAB Files (*.m,*.mat)';
                '*.*',  'All Files (*.*)'}, ...
                "Select File","data\");
            app.filepath = append(location,name);
            app.EditField.Value = app.filepath;
            delete(f); %delete the dummy figure
        end
        
        function data = load_pdata(app, fn)
            % read data
            data = vector2timetable(app.filepath, fn{:});
            set_tr(app, data);
            data = data(app.tr,:);
        end

        function [time_s, time_hms] = xAxis_conv(app, data)
            % create time arrays in hh:mm:ss and just seconds
            date = dateshift(data.Time,'start','day');
            time_hms = data.Time-date;
            time_s = seconds(time_hms);
            tims_s = time_s - time_s(1);    % set beginning of session to 0
        end

        
        function search(app, changingValue, source)
            if isempty(changingValue) % If empty
                app.SelectDataListBox.Items = app.fns.'; % whole dataset
                app.SelectDataforFeatureListBox.Items = app.fns.'
            else
                if source == 2
                    idx = contains(app.SelectDataforFeatureListBox.Items, changingValue);
                    Filtered_Values = app.SelectDataforFeatureListBox.Items(idx);
                    app.SelectDataforFeatureListBox.Items = Filtered_Values;
                else
                    idx = contains(app.SelectDataListBox.Items, changingValue);
                    Filtered_Values = app.SelectDataListBox.Items(idx);
                    app.SelectDataListBox.Items = Filtered_Values;
                end
            end 
        end

        
    function data_ip = interpolate(app, data, start, stop)
        tr = linspace(start,stop+seconds(1),length(data.Time)+1);
        tr = tr(1:end-1);
        values = interp1(data.Time, data.(data.Properties.VariableNames{1}), tr);
        data_ip = timetable(tr, values);
        data_ip.Properties.DimensionNames{1} = 'Time';
        data_ip.Properties.VariableNames{1} = data.Properties.VariableNames{1};
    end
        
        
    function data_filter = medFil(app, data)
        data_filter = data;
        if app.OnCheckBox.Value == 1
            for i=1:width(data)
                    medianSignal = medfilt1(data.(data.Properties.VariableNames{i}), app.NeighborsSpinner.Value);
                    diffSignal = abs(data.(data.Properties.VariableNames{i}) - medianSignal);
                    spikes = diffSignal > app.DeviationEditField.Value;
                    % Replace
                    fixedSignal = data.(data.Properties.VariableNames{i}); % Initialize
                    fixedSignal(spikes) = medianSignal(spikes);
                    data_filter.(data_filter.Properties.VariableNames{i}) = fixedSignal;
                    if app.PlotSwitch.Value == "On"
                        figure(i+1)
                        subplot(3,1,1)
                        plot(data.Time, data.(data.Properties.VariableNames{i}))
                        title("Original");
                        hold on
                        subplot(3,1,2)
                        plot(data.Time, spikes, "x")
                        title("Index of changed values")
                        subplot(3,1,3)
                        plot(data.Time, fixedSignal)
                        title("New Data")
                    end
            end
        end
    end


end
    methods (Access = public)

        % startup function to set additional paths
        function startup(app)
            addpath("assets\");
            app.UIFigure.Icon = "FT_icon.png";
            pathing(app)
        end

        function pathing(app)
            default = ["FT25", "FT24", "FT23"];
            if app.folder ~= 0
                rmpath("season\"+default(app.folder));
                rmpath("season\"+default(app.folder) + "\plot_settings");
            end
            addpath("season\"+default(app.Preset.ValueIndex));
            addpath("season\"+default(app.Preset.ValueIndex) + "\plot_settings");
            app.folder = app.Preset.ValueIndex;
        end

        function preview_data(app)
            % check if data is already loaded
            if strcmp(app.filepath, app.filepath_last) == false
                % load data via vector2timetable (see podio)
                data_fn = load(app.filepath);
                % generate list of all avaible data
                app.fns = fieldnames(data_fn);
                app.SelectDataListBox.Items = app.fns.';
                app.SelectDataforFeatureListBox.Items = app.fns.';
            else
                msgbox("Data already loaded!");
            end
            app.filepath_last = app.filepath;
        end

        % load: loads data based on default configuration (ABX,Shunt,...)
        % and generates list of all data avaible (might need to change
        % according to season)
        function load_data_presets(app)
            preview_data(app);
            app.data = vector2timetable(app.filepath,"ABX*","Shunt*","AMS_Status*","INV*","XSens*");
            app.pltData = sortdata(app.data,1,length(app.data.Time));
        end

        function laptime(app)
            % load Laptime Counter
            data = vector2timetable(app.filepath, "ABX_Driver_ABX_Lapcounter", "AMS_In_Lap_Number");
            %get date / time
            date = dateshift(data.Time(1),'start','day');
            
            % get lapcounter / laptrigger
            laps_counter = data.(data.Properties.VariableNames{1});
            app.timestamp_hms(1) = data.Time(1) - date;
            app.timestamp_index(1) = 1;
            j = 2;
            for i = 2:length(laps_counter)
                if laps_counter(i) ~= laps_counter(i-1)
                    app.timestamp_hms(j) = data.Time(i) - date;
                    app.timestamp_index(j) = i;
                    j = j + 1;
                end
            end
        
            % calculate laptimes
            app.timestamp_s = seconds(app.timestamp_hms);
            for i = 1:length(app.timestamp_s)-1
                laps_s(i) = app.timestamp_s(i+1) - app.timestamp_s(i);
            end
            % if laps could be detected find fastest lap and create list of
            % laptimes, otherwise only "Entire stint" will be selectable
            app.laps_strArray(1) = sprintf("Entire stint");
            if (exist("laps_s","var") == true)
                % create list of laptimes
                for i = 1:length(laps_s)
                    if laps_s(i) == min(laps_s)
                        app.laps_strArray(i+1) = sprintf("Lap %d: %.3fs (best)",i,laps_s(i));
                    else
                        app.laps_strArray(i+1) = sprintf("Lap %d: %.3fs",i,laps_s(i));
                    end
                end
            end
            
            % create time arrays in hh:mm:ss and just seconds
            app.time_dhms = data.Time;
        end

        % set timerange for data either with custom, selected lap or entire stint
        function set_tr(app, data)
            if app.UseCheckBox.Value == 1 %custom % does not work on presets currently
                date = string(dateshift(data.Time(1),'start','day'));
                start = date + " " + string(app.start_h.Value) + ":" + string(app.start_m.Value) + ":"  + string(app.start_s.Value);
                stop = date + " " + string(app.end_h.Value) + ":"  + string(app.end_m.Value) + ":"  + string(app.end_s.Value);
                if app.presetflag == 1
                    app.pltstart = find(app.pltData.Time >= datetime(start),1,"first");
                    app.pltstop = find(app.pltData.Time <= stop,1,"last");
                end
                app.tr = timerange(start, stop);
            elseif app.LapsListBox.Value == 1 && app.UseCheckBox.Value == 0 % entire stint
                app.tr = timerange(data.Time(1), data.Time(end), "closed");
                app.pltstart = 1;
                app.pltstop = length(data.Time);
            else %selected lap
                start = app.time_dhms(app.LapsListBox.ItemsData(app.LapsListBox.ValueIndex-1));
                stop = app.time_dhms(app.LapsListBox.ItemsData(app.LapsListBox.ValueIndex));
                app.tr = timerange(start,stop,"closed");
                app.pltstart = app.LapsListBox.ItemsData(app.LapsListBox.ValueIndex-1);
                app.pltstop = app.LapsListBox.ItemsData(app.LapsListBox.ValueIndex);
            end
        end

        % adds subplots in fig[1], fig[2], ...
        function subplotting(app, fn_selected)
            data_selected = load_pdata(app, fn_selected);
            data_selected = medFil(app, data_selected);
            [time_s, time_hms] = xAxis_conv(app, data_selected);

            switch app.xAxisDropDown.Value
                case "Time [h:m:s + Date]"
                    xAxis = data_selected.Time;
                case "Time [h:m:s]"
                    xAxis = time_hms;
                case "Time [s]"
                    xAxis = time_s;
                otherwise
                    error("Error plotting")
            end

            figure(1)
            hold on
            for i=1:length(fn_selected)
                app.fig(app.Field_SelectedSP.Value) = subplot(app.ColumnsEditField.Value, app.RowsEditField.Value, app.Field_SelectedSP.Value)
                hold on
                plot(xAxis, data_selected.(fn_selected{i}));
            end
            ylabel(app.yAxisTitle.Value);
            title(app.SubplotTitle.Value);
            if app.LegendonCheckBox.Value == 1
                legend(fn_selected, 'Interpreter', 'none')
            end
            if app.FigureTitleCheckBox.Value == 1
                sgtitle(app.OverallTitleField.Value)
            end
            if app.SetLimitsCheckBox.Value == 1
                ylim([app.LowerEditField.Value app.UpperEditField.Value])
            end
        end

        % reads additional data from file
        function subplotting_y(app, fn_selected, fn_selected2)
            % load data according to the selected fields
            data_selected = load_pdata(app, fn_selected);
            data_selected2 = load_pdata(app, fn_selected2);
            data_selected = medFil(app, data_selected);
            data_selected2 = medFil(app, data_selected2);
            [time_s, time_hms] = xAxis_conv(app, data_selected);
            switch app.xAxisDropDown.Value
                case "Time [h:m:s + Date]"
                    xAxis = data_selected.Time;
                case "Time [h:m:s]"
                    xAxis = time_hms;
                case "Time [s]"
                    xAxis = time_s;
                otherwise
                    error("Error plotting")
            end
            % select subplotting field
            app.fig(app.Field_SelectedSP.Value) = subplot(app.ColumnsEditField.Value, app.RowsEditField.Value, app.Field_SelectedSP.Value);
            % plotting
            hold on
            % plot left axis
            for i=1:length(fn_selected)
                yyaxis left
                plot(xAxis, data_selected.(fn_selected{i}));
            end
            if app.SetLimitsCheckBox.Value == 1
                ylim([app.LowerEditField.Value app.UpperEditField.Value])
            end
            %plot right
            for i=1:length(fn_selected2)
                yyaxis right
                plot(xAxis, data_selected2.(fn_selected2{i}));
            end
            if app.SetLimitsCheckBox.Value == 1
                ylim([app.LowerEditField.Value app.UpperEditField.Value])
            end
            % label axis
            title(app.SubplotTitle.Value);
            yyaxis left
            ylabel(app.yAxisTitle.Value);
            yyaxis right
            ylabel(app.yAxisTitle_2.Value);
            if app.FigureTitleCheckBox.Value == 1
                sgtitle(app.OverallTitleField.Value)
            end
        end

        function sidebarlabel(app)
            app.Sidebar.Value = sprintf(...
                "Energy\n Used: %.2f kWh\n" + ...
                "  Regen: %.2f kWh\n" + ...
                "  Total: %.2f kWh\n" +...
                "\nPower:\n  Peak: %.1f kW\n"+ ...
                "  Peak (mean): %1.f kW\n"+ ...
                "\nDistance: %.2f km\n" + ...
                "\nTopspeed: %.1f km/h\n", ...
                app.pltData.energy_used_kwh, ...
                app.pltData.energy_regen_kwh, ...
                app.pltData.energy_kwh, ...
                app.pltData.peakPower_kw, ...
                app.pltData.peakPowerMean_kw, ...
                app.pltData.distanceTotal_km, ...
                app.pltData.maxSpeed_kph ...
                );
        end
        
        function [idx_start, idx_stop] = find_idx(app, data)
           tr_struct = struct(app.tr)
           idx_start = find(data >= tr_struct.first, 1, 'first');
           idx_stop = find(data <= tr_struct.last, 1, 'last');
        end
        
        function plot_median(app)
            
        end
    end
    

    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            startup(app);
        end

        % Button pushed function: BrowseButton
        function BrowseButtonPushed(app, event)
            browse(app);
        end

        % Button pushed function: LoadFastButton
        function LoadFastButtonPushed(app, event)
            app.StatusTextArea.Value = "Loading...";
            pause(0.01);
            preview_data(app);
            laptime(app);
            app.LapsListBox.Items = app.laps_strArray.';
            app.LapsListBox.ItemsData = app.timestamp_index;
            pause(0.01);
            app.StatusTextArea.Value = "Finished Loading";
            pause(0.01);
        end

        % Button pushed function: LoadPresetsButton
        function LoadPresetsButtonPushed(app, event)
            app.presetflag = 1;
            app.StatusTextArea.Value = "Loading at least 2 min...";
            pause(0.01);
            laptime(app);
            app.LapsListBox.Items = app.laps_strArray.';
            app.LapsListBox.ItemsData = app.timestamp_index;
            pause(0.01);
            load_data_presets(app);
            app.StatusTextArea.Value = "Finished Loading";
            pause(0.01);
            sidebarlabel(app);
            app.PlotPresetsButton.Enable = "on"
        end

        % Value changed function: SelectDataListBox
        function ItemsSelected(app, event)
            if app.SelectDataListBox.Value ~= "none"
                value = app.SelectDataListBox.Value;
            else
                value = "";
            end
        end

        % Button pushed function: PlotPresetsButton
        function PlotPresetsButtonPushed(app, event)
            % set timerange
            set_tr(app, app.pltData);

            % switch to selected x-Axis
            switch app.xAxisDropDown.Value
                case "Time [h:m:s + Date]"
                    app.pltData.xAxis = app.pltData.Time;
                case "Time [h:m:s]"
                    app.pltData.xAxis = app.pltData.time_hms;
                case "Time [s]"
                    app.pltData.xAxis = app.pltData.time_s;
                case "Distance [m]"
                    app.pltData.xAxis = app.pltData.distance;
                otherwise
                    error("Error plotting")
            end

            [start, stop] = find_idx(app, app.pltData.Time)

            switch app.PresetsDropDown.Value
                case "Accumulator"
                    plot_accumulator(app.PresetPanel, start, stop, app.pltData);
                case "Brakes"
                    plot_brakes(app.PresetPanel, start, stop, app.pltData);
                case "Driver - Braking"
                    plot_driver_braking(app.PresetPanel, start, stop, app.pltData);
                case "Driver - General"
                    plot_driver_general(app.PresetPanel, start, stop, app.pltData);
                case "Driver - Statistics"
                    plot_driver_statistics(app.PresetPanel, start, stop, app.pltData);
                case "Driver - Steering"
                    plot_driver_steering(app.PresetPanel, start, stop, app.pltData);
                case "Inverter"
                    plot_inverter(app.PresetPanel, start, stop, app.pltData);
                case "Powertrain"
                    plot_powertrain(app.PresetPanel, start, stop, app.pltData);
                case "Suspension - Histogram"
                    plot_suspension_histogram(app.PresetPanel, start, stop, app.pltData);
                case "Suspension - Positions"
                    plot_suspension_positions(app.PresetPanel, start, stop, app.pltData);
                case "Suspension - Velocities"
                    plot_suspension_velocities(app.PresetPanel, start, stop, app.pltData);
                case "Tires - Friction Circle"
                    plot_tires_firctionCircle(app.PresetPanel, start, stop, app.pltData);
                case "Tires - Temperatures"
                    plot_tires_temperatures(app.PresetPanel, start, stop, app.pltData);
                case "Custom"
                    plot_custom(app.PresetPanel, start, stop, app.pltData);
                otherwise
                    error("Error plotting")
            end
        end

        % Button pushed function: PlotSubplotButton
        function PlotSubplotButtonPushed(app, event)
            if app.button_plot.Value == true
                app.StatusTextArea.Value = "Loading...";
                pause(0.01);
                subplotting(app, app.SelectDataListBox.Value);
                app.StatusTextArea.Value = "Finished Loading";
                pause(0.01);
            elseif app.button_yaxis.Value == true
                app.StatusTextArea.Value = "Loading...";
                pause(0.01);
                subplotting_y(app, app.SelectDataListBox.Value, app.SelectDataforFeatureListBox.Value);
                app.StatusTextArea.Value = "Finished Loading";
                pause(0.01);
            elseif app.button_math.Value == true
                app.StatusTextArea.Value = "Loading...";
                pause(0.01);
                subplotting_y(app, app.SelectDataListBox.Value, app.SelectDataforFeatureListBox.Value);
                app.StatusTextArea.Value = "Finished Loading";
                pause(0.01);
            else
                app.StatusTextArea.Value = "Loading...";
                pause(0.01);
                subplotting(app, app.SelectDataListBox.Value);
                app.StatusTextArea.Value = "Finished Loading";
                pause(0.01);
            end
                
        end

        % Button pushed function: ResetSubplotButton
        function ResetSubplotButtonPushed(app, event)
            delete(app.fig(app.Field_SelectedSP.Value));
        end

        % Value changed function: FigureTitleCheckBox
        function FigureTitleCheckBoxValueChanged(app, event)
            app.OverallTitleField.Enable = app.FigureTitleCheckBox.Value;
        end

        % Value changed function: ColumnsEditField, RowsEditField
        function NumSP(app, event)
            rows = app.RowsEditField.Value;
            cols = app.ColumnsEditField.Value;
            app.Field_NoSP.Value = rows * cols;
        end

        % Button pushed function: SaveButton
        function SaveButtonPushed(app, event)
            path = "exports\" + app.savename.Value;
            app.StatusTextArea.Value = "exporting...";
            savePlot(app.PresetPanel.Children, path, app.Format.Value);
            app.StatusTextArea.Value = "saved";
        end

        % Button pushed function: ToWorkspaceButton
        function ToWorkspaceButtonPushed(app, event)
            assignin("base", "pltData", app.pltData);
            assignin("base", "data_tr", app.data(app.tr,:))
            assignin("base", "start", app.pltstart);
            assignin("base", "stop", app.pltstop);
            assignin("base", "data_filter", app.data_filter(app.tr,:))
        end

        % Button pushed function: ResetPanelButton
        function ResetPanelButtonPushed(app, event)
            delete(app.PresetPanel.Children);
        end

        % Value changed function: Preset
        function PresetValueChanged(app, event)
            pathing(app)
        end

        % Callback function: SearchEditField, SearchEditField, 
        % ...and 2 other components
        function SearchEditFieldValueChanging(app, event)
            changingValue = event.Value;
            if event.Source.Tag == "search2"
                source = 2;
            else
                source = 1;
            end
            search(app, changingValue, source)
        end

        % Button pushed function: Button
        function ButtonPushed(app, event)
            msgbox("Neigbors: Looks at the number of numbers to compare it to, orient yourself at the sampling frequency. Keep empty to not use it. \n Deviation: Expected deviation to filter");
        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Get the file path for locating images
            pathToMLAPP = fileparts(mfilename('fullpath'));

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Position = [100 100 1305 617];
            app.UIFigure.Name = 'MATLAB App';
            app.UIFigure.Scrollable = 'on';

            % Create BrowseButton
            app.BrowseButton = uibutton(app.UIFigure, 'push');
            app.BrowseButton.ButtonPushedFcn = createCallbackFcn(app, @BrowseButtonPushed, true);
            app.BrowseButton.Position = [11 583 111 23];
            app.BrowseButton.Text = 'Browse';

            % Create EditField
            app.EditField = uieditfield(app.UIFigure, 'text');
            app.EditField.Position = [129 583 407 22];
            app.EditField.Value = '/data';

            % Create LoadFastButton
            app.LoadFastButton = uibutton(app.UIFigure, 'push');
            app.LoadFastButton.ButtonPushedFcn = createCallbackFcn(app, @LoadFastButtonPushed, true);
            app.LoadFastButton.Position = [552 583 114 23];
            app.LoadFastButton.Text = 'Load (Fast)';

            % Create PresetsDropDown
            app.PresetsDropDown = uidropdown(app.UIFigure);
            app.PresetsDropDown.Items = {'Driver - General', 'Driver - Steering', 'Driver - Braking', 'Driver - Statistics', 'Powertrain', 'Brakes', 'Accumulator', 'Inverter', 'Suspension - Positions', 'Suspension - Velocities', 'Suspension - Histogram', 'Tires - Temperatures', 'Tires - Friction Circle', 'Custom'};
            app.PresetsDropDown.Position = [131 550 405 22];
            app.PresetsDropDown.Value = 'Driver - General';

            % Create Preset
            app.Preset = uidropdown(app.UIFigure);
            app.Preset.Items = {'FT25 Presets', 'FT24 Presets', 'FT23 Presets'};
            app.Preset.ValueChangedFcn = createCallbackFcn(app, @PresetValueChanged, true);
            app.Preset.Position = [552 549 114 23];
            app.Preset.Value = 'FT25 Presets';

            % Create LoadPresetsButton
            app.LoadPresetsButton = uibutton(app.UIFigure, 'push');
            app.LoadPresetsButton.ButtonPushedFcn = createCallbackFcn(app, @LoadPresetsButtonPushed, true);
            app.LoadPresetsButton.Position = [675 583 119 23];
            app.LoadPresetsButton.Text = 'Load (Presets)';

            % Create PlotPresetsButton
            app.PlotPresetsButton = uibutton(app.UIFigure, 'push');
            app.PlotPresetsButton.ButtonPushedFcn = createCallbackFcn(app, @PlotPresetsButtonPushed, true);
            app.PlotPresetsButton.Enable = 'off';
            app.PlotPresetsButton.Position = [675 549 119 23];
            app.PlotPresetsButton.Text = 'Plot Presets';

            % Create PlottypeLabel
            app.PlottypeLabel = uilabel(app.UIFigure);
            app.PlottypeLabel.HorizontalAlignment = 'right';
            app.PlottypeLabel.Position = [73 550 46 22];
            app.PlottypeLabel.Text = 'Presets';

            % Create SetTimestampsPanel
            app.SetTimestampsPanel = uipanel(app.UIFigure);
            app.SetTimestampsPanel.Title = 'Set Timestamps';
            app.SetTimestampsPanel.Position = [11 59 241 476];

            % Create Label
            app.Label = uilabel(app.SetTimestampsPanel);
            app.Label.HorizontalAlignment = 'center';
            app.Label.Position = [90 425 10 22];
            app.Label.Text = ':';

            % Create Label_2
            app.Label_2 = uilabel(app.SetTimestampsPanel);
            app.Label_2.HorizontalAlignment = 'center';
            app.Label_2.Position = [131 425 10 22];
            app.Label_2.Text = ':';

            % Create Label_3
            app.Label_3 = uilabel(app.SetTimestampsPanel);
            app.Label_3.HorizontalAlignment = 'center';
            app.Label_3.Position = [90 396 10 22];
            app.Label_3.Text = ':';

            % Create Label_4
            app.Label_4 = uilabel(app.SetTimestampsPanel);
            app.Label_4.HorizontalAlignment = 'center';
            app.Label_4.Position = [131 396 10 22];
            app.Label_4.Text = ':';

            % Create StartLabel
            app.StartLabel = uilabel(app.SetTimestampsPanel);
            app.StartLabel.Position = [15 425 37 22];
            app.StartLabel.Text = 'Start';

            % Create StopLabel
            app.StopLabel = uilabel(app.SetTimestampsPanel);
            app.StopLabel.Position = [15 396 37 22];
            app.StopLabel.Text = 'Stop';

            % Create start_h
            app.start_h = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.start_h.Limits = [0 23];
            app.start_h.ValueDisplayFormat = '%02.0f';
            app.start_h.Position = [60 425 30 22];

            % Create start_m
            app.start_m = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.start_m.Limits = [0 59];
            app.start_m.ValueDisplayFormat = '%02.0f';
            app.start_m.Position = [101 425 30 22];

            % Create start_s
            app.start_s = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.start_s.Limits = [0 59];
            app.start_s.ValueDisplayFormat = '%02.0f';
            app.start_s.Position = [141 425 32 22];

            % Create end_h
            app.end_h = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.end_h.Limits = [0 23];
            app.end_h.ValueDisplayFormat = '%02.0f';
            app.end_h.Position = [60 396 30 22];

            % Create end_m
            app.end_m = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.end_m.Limits = [0 59];
            app.end_m.ValueDisplayFormat = '%02.0f';
            app.end_m.Position = [101 396 30 22];

            % Create end_s
            app.end_s = uieditfield(app.SetTimestampsPanel, 'numeric');
            app.end_s.Limits = [0 59];
            app.end_s.ValueDisplayFormat = '%02.0f';
            app.end_s.Position = [141 396 32 22];

            % Create UseCheckBox
            app.UseCheckBox = uicheckbox(app.SetTimestampsPanel);
            app.UseCheckBox.Text = 'Use';
            app.UseCheckBox.Position = [191 412 45 22];

            % Create xAxisDropDown
            app.xAxisDropDown = uidropdown(app.SetTimestampsPanel);
            app.xAxisDropDown.Items = {'Time [h:m:s + Date]', 'Time [h:m:s]', 'Time [s]', 'Distance [m]'};
            app.xAxisDropDown.Position = [74 364 146 22];
            app.xAxisDropDown.Value = 'Time [h:m:s + Date]';

            % Create LapsListBoxLabel
            app.LapsListBoxLabel = uilabel(app.SetTimestampsPanel);
            app.LapsListBoxLabel.Position = [7 338 31 22];
            app.LapsListBoxLabel.Text = 'Laps';

            % Create LapsListBox
            app.LapsListBox = uilistbox(app.SetTimestampsPanel);
            app.LapsListBox.Items = {'Entire Stint'};
            app.LapsListBox.Position = [5 36 231 300];
            app.LapsListBox.Value = 'Entire Stint';

            % Create ResetPanelButton
            app.ResetPanelButton = uibutton(app.SetTimestampsPanel, 'push');
            app.ResetPanelButton.ButtonPushedFcn = createCallbackFcn(app, @ResetPanelButtonPushed, true);
            app.ResetPanelButton.Position = [15 6 100 23];
            app.ResetPanelButton.Text = 'Reset Panel';

            % Create xAxisDropDownLabel
            app.xAxisDropDownLabel = uilabel(app.SetTimestampsPanel);
            app.xAxisDropDownLabel.HorizontalAlignment = 'right';
            app.xAxisDropDownLabel.Position = [21 364 38 22];
            app.xAxisDropDownLabel.Text = 'x-Axis';

            % Create ToWorkspaceButton
            app.ToWorkspaceButton = uibutton(app.SetTimestampsPanel, 'push');
            app.ToWorkspaceButton.ButtonPushedFcn = createCallbackFcn(app, @ToWorkspaceButtonPushed, true);
            app.ToWorkspaceButton.Position = [131 6 100 23];
            app.ToWorkspaceButton.Text = 'To Workspace';

            % Create CustomSubplotsPanel
            app.CustomSubplotsPanel = uipanel(app.UIFigure);
            app.CustomSubplotsPanel.TitlePosition = 'centertop';
            app.CustomSubplotsPanel.Title = 'Custom Subplots';
            app.CustomSubplotsPanel.Position = [262 81 531 454];

            % Create RowsLabel
            app.RowsLabel = uilabel(app.CustomSubplotsPanel);
            app.RowsLabel.HorizontalAlignment = 'right';
            app.RowsLabel.Position = [135 401 35 22];
            app.RowsLabel.Text = 'Rows';

            % Create ColumnsLabel
            app.ColumnsLabel = uilabel(app.CustomSubplotsPanel);
            app.ColumnsLabel.HorizontalAlignment = 'right';
            app.ColumnsLabel.Position = [11 401 52 22];
            app.ColumnsLabel.Text = 'Columns';

            % Create ColumnsEditField
            app.ColumnsEditField = uieditfield(app.CustomSubplotsPanel, 'numeric');
            app.ColumnsEditField.Limits = [1 9];
            app.ColumnsEditField.ValueChangedFcn = createCallbackFcn(app, @NumSP, true);
            app.ColumnsEditField.Position = [81 401 45 22];
            app.ColumnsEditField.Value = 1;

            % Create RowsEditField
            app.RowsEditField = uieditfield(app.CustomSubplotsPanel, 'numeric');
            app.RowsEditField.Limits = [1 9];
            app.RowsEditField.ValueChangedFcn = createCallbackFcn(app, @NumSP, true);
            app.RowsEditField.Position = [194 401 43 22];
            app.RowsEditField.Value = 1;

            % Create OverallTitleEditFieldLabel
            app.OverallTitleEditFieldLabel = uilabel(app.CustomSubplotsPanel);
            app.OverallTitleEditFieldLabel.HorizontalAlignment = 'right';
            app.OverallTitleEditFieldLabel.Enable = 'off';
            app.OverallTitleEditFieldLabel.Position = [11 370 68 22];
            app.OverallTitleEditFieldLabel.Text = 'Overall Title';

            % Create OverallTitleField
            app.OverallTitleField = uieditfield(app.CustomSubplotsPanel, 'text');
            app.OverallTitleField.Enable = 'off';
            app.OverallTitleField.Position = [93 370 144 22];

            % Create FigureTitleCheckBox
            app.FigureTitleCheckBox = uicheckbox(app.CustomSubplotsPanel);
            app.FigureTitleCheckBox.ValueChangedFcn = createCallbackFcn(app, @FigureTitleCheckBoxValueChanged, true);
            app.FigureTitleCheckBox.Text = '';
            app.FigureTitleCheckBox.Position = [244 370 16 22];

            % Create SubplotTitleEditFieldLabel
            app.SubplotTitleEditFieldLabel = uilabel(app.CustomSubplotsPanel);
            app.SubplotTitleEditFieldLabel.HorizontalAlignment = 'right';
            app.SubplotTitleEditFieldLabel.Position = [8 342 71 22];
            app.SubplotTitleEditFieldLabel.Text = 'Subplot Title';

            % Create SubplotTitle
            app.SubplotTitle = uieditfield(app.CustomSubplotsPanel, 'text');
            app.SubplotTitle.Position = [93 342 144 22];

            % Create yAxisLabel
            app.yAxisLabel = uilabel(app.CustomSubplotsPanel);
            app.yAxisLabel.HorizontalAlignment = 'right';
            app.yAxisLabel.Position = [41 315 38 22];
            app.yAxisLabel.Text = 'y-Axis';

            % Create yAxisTitle
            app.yAxisTitle = uieditfield(app.CustomSubplotsPanel, 'text');
            app.yAxisTitle.Position = [93 315 144 22];

            % Create SelectDataLabel
            app.SelectDataLabel = uilabel(app.CustomSubplotsPanel);
            app.SelectDataLabel.Position = [7 289 67 22];
            app.SelectDataLabel.Text = 'Select Data';

            % Create LegendonCheckBox
            app.LegendonCheckBox = uicheckbox(app.CustomSubplotsPanel);
            app.LegendonCheckBox.Text = 'Legend on';
            app.LegendonCheckBox.Position = [181 289 79 22];

            % Create SearchEditField
            app.SearchEditField = uieditfield(app.CustomSubplotsPanel, 'text');
            app.SearchEditField.ValueChangedFcn = createCallbackFcn(app, @SearchEditFieldValueChanging, true);
            app.SearchEditField.ValueChangingFcn = createCallbackFcn(app, @SearchEditFieldValueChanging, true);
            app.SearchEditField.Tag = 'search1';
            app.SearchEditField.Position = [67 150 193 22];

            % Create SelectDataListBox
            app.SelectDataListBox = uilistbox(app.CustomSubplotsPanel);
            app.SelectDataListBox.Multiselect = 'on';
            app.SelectDataListBox.ValueChangedFcn = createCallbackFcn(app, @ItemsSelected, true);
            app.SelectDataListBox.Position = [6 176 261 107];
            app.SelectDataListBox.Value = {'Item 1'};

            % Create FeaturesPanel
            app.FeaturesPanel = uipanel(app.CustomSubplotsPanel);
            app.FeaturesPanel.TitlePosition = 'centertop';
            app.FeaturesPanel.Title = 'Features';
            app.FeaturesPanel.Position = [272 146 258 288];

            % Create yAxisTitleLabel
            app.yAxisTitleLabel = uilabel(app.FeaturesPanel);
            app.yAxisTitleLabel.HorizontalAlignment = 'right';
            app.yAxisTitleLabel.Position = [9 175 61 22];
            app.yAxisTitleLabel.Text = '2nd y-Axis ';

            % Create Panel_3
            app.Panel_3 = uipanel(app.FeaturesPanel);
            app.Panel_3.Position = [10 206 234 59];

            % Create LowerEditFieldLabel
            app.LowerEditFieldLabel = uilabel(app.Panel_3);
            app.LowerEditFieldLabel.HorizontalAlignment = 'right';
            app.LowerEditFieldLabel.Position = [121 30 38 22];
            app.LowerEditFieldLabel.Text = 'Lower';

            % Create SetLimitsCheckBox
            app.SetLimitsCheckBox = uicheckbox(app.Panel_3);
            app.SetLimitsCheckBox.Text = 'Set Limits';
            app.SetLimitsCheckBox.Position = [18 19 75 22];

            % Create LowerEditField
            app.LowerEditField = uieditfield(app.Panel_3, 'numeric');
            app.LowerEditField.Position = [174 30 53 22];

            % Create UpperEditFieldLabel
            app.UpperEditFieldLabel = uilabel(app.Panel_3);
            app.UpperEditFieldLabel.HorizontalAlignment = 'right';
            app.UpperEditFieldLabel.Position = [121 3 38 22];
            app.UpperEditFieldLabel.Text = 'Upper';

            % Create UpperEditField
            app.UpperEditField = uieditfield(app.Panel_3, 'numeric');
            app.UpperEditField.Position = [174 3 53 22];

            % Create yAxisTitle_2
            app.yAxisTitle_2 = uieditfield(app.FeaturesPanel, 'text');
            app.yAxisTitle_2.Position = [73 175 171 22];

            % Create SelectDataforFeatureListBoxLabel
            app.SelectDataforFeatureListBoxLabel = uilabel(app.FeaturesPanel);
            app.SelectDataforFeatureListBoxLabel.Position = [6 143 129 22];
            app.SelectDataforFeatureListBoxLabel.Text = 'Select Data for Feature';

            % Create SelectDataforFeatureListBox
            app.SelectDataforFeatureListBox = uilistbox(app.FeaturesPanel);
            app.SelectDataforFeatureListBox.Multiselect = 'on';
            app.SelectDataforFeatureListBox.Position = [5 29 248 108];
            app.SelectDataforFeatureListBox.Value = {'Item 1'};

            % Create SearchEditField_2
            app.SearchEditField_2 = uieditfield(app.FeaturesPanel, 'text');
            app.SearchEditField_2.ValueChangedFcn = createCallbackFcn(app, @SearchEditFieldValueChanging, true);
            app.SearchEditField_2.ValueChangingFcn = createCallbackFcn(app, @SearchEditFieldValueChanging, true);
            app.SearchEditField_2.Tag = 'search2';
            app.SearchEditField_2.Position = [55 4 193 22];

            % Create SearchEditField_2Label
            app.SearchEditField_2Label = uilabel(app.FeaturesPanel);
            app.SearchEditField_2Label.HorizontalAlignment = 'right';
            app.SearchEditField_2Label.Position = [6 4 43 22];
            app.SearchEditField_2Label.Text = 'Search';

            % Create Panel_2
            app.Panel_2 = uipanel(app.CustomSubplotsPanel);
            app.Panel_2.Position = [7 14 238 42];

            % Create SelectedSubplotEditFieldLabel
            app.SelectedSubplotEditFieldLabel = uilabel(app.Panel_2);
            app.SelectedSubplotEditFieldLabel.HorizontalAlignment = 'right';
            app.SelectedSubplotEditFieldLabel.FontSize = 18;
            app.SelectedSubplotEditFieldLabel.Position = [5 3 141 36];
            app.SelectedSubplotEditFieldLabel.Text = 'Selected Subplot';

            % Create Field_SelectedSP
            app.Field_SelectedSP = uieditfield(app.Panel_2, 'numeric');
            app.Field_SelectedSP.Limits = [1 81];
            app.Field_SelectedSP.HorizontalAlignment = 'center';
            app.Field_SelectedSP.FontSize = 18;
            app.Field_SelectedSP.Position = [149 9 30 24];
            app.Field_SelectedSP.Value = 1;

            % Create textfield
            app.textfield = uieditfield(app.Panel_2, 'text');
            app.textfield.Editable = 'off';
            app.textfield.Enable = 'off';
            app.textfield.Position = [184 10 13 22];
            app.textfield.Value = '/';

            % Create Field_NoSP
            app.Field_NoSP = uieditfield(app.Panel_2, 'numeric');
            app.Field_NoSP.Editable = 'off';
            app.Field_NoSP.HorizontalAlignment = 'center';
            app.Field_NoSP.FontSize = 18;
            app.Field_NoSP.Position = [201 9 30 24];
            app.Field_NoSP.Value = 1;

            % Create ButtonGroup
            app.ButtonGroup = uibuttongroup(app.CustomSubplotsPanel);
            app.ButtonGroup.Position = [258 11 123 49];

            % Create button_plot
            app.button_plot = uitogglebutton(app.ButtonGroup);
            app.button_plot.Text = 'Standard Plot';
            app.button_plot.Position = [7 24 109 23];
            app.button_plot.Value = true;

            % Create button_yaxis
            app.button_yaxis = uitogglebutton(app.ButtonGroup);
            app.button_yaxis.Text = 'Plot with 2nd Axis';
            app.button_yaxis.Position = [7 1 109 23];

            % Create PlotSubplotButton
            app.PlotSubplotButton = uibutton(app.CustomSubplotsPanel, 'push');
            app.PlotSubplotButton.ButtonPushedFcn = createCallbackFcn(app, @PlotSubplotButtonPushed, true);
            app.PlotSubplotButton.FontSize = 18;
            app.PlotSubplotButton.FontWeight = 'bold';
            app.PlotSubplotButton.Position = [394 34 121 28];
            app.PlotSubplotButton.Text = 'Plot Subplot';

            % Create ResetSubplotButton
            app.ResetSubplotButton = uibutton(app.CustomSubplotsPanel, 'push');
            app.ResetSubplotButton.ButtonPushedFcn = createCallbackFcn(app, @ResetSubplotButtonPushed, true);
            app.ResetSubplotButton.Position = [412 4 84 23];
            app.ResetSubplotButton.Text = 'Reset Subplot';

            % Create SearchEditFieldLabel
            app.SearchEditFieldLabel = uilabel(app.CustomSubplotsPanel);
            app.SearchEditFieldLabel.HorizontalAlignment = 'right';
            app.SearchEditFieldLabel.Position = [18 150 43 22];
            app.SearchEditFieldLabel.Text = 'Search';

            % Create FilteringforsuddenspikesPanel
            app.FilteringforsuddenspikesPanel = uipanel(app.CustomSubplotsPanel);
            app.FilteringforsuddenspikesPanel.Title = 'Filtering for sudden spikes';
            app.FilteringforsuddenspikesPanel.Position = [6 61 239 86];

            % Create NeighborsSpinnerLabel
            app.NeighborsSpinnerLabel = uilabel(app.FilteringforsuddenspikesPanel);
            app.NeighborsSpinnerLabel.HorizontalAlignment = 'right';
            app.NeighborsSpinnerLabel.Position = [5 37 60 22];
            app.NeighborsSpinnerLabel.Text = 'Neighbors';

            % Create Button
            app.Button = uibutton(app.FilteringforsuddenspikesPanel, 'push');
            app.Button.ButtonPushedFcn = createCallbackFcn(app, @ButtonPushed, true);
            app.Button.FontSize = 8;
            app.Button.FontWeight = 'bold';
            app.Button.Position = [219 68 17 17];
            app.Button.Text = '?';

            % Create NeighborsSpinner
            app.NeighborsSpinner = uispinner(app.FilteringforsuddenspikesPanel);
            app.NeighborsSpinner.Limits = [3 Inf];
            app.NeighborsSpinner.Position = [72 37 58 22];
            app.NeighborsSpinner.Value = 3;

            % Create DeviationEditFieldLabel
            app.DeviationEditFieldLabel = uilabel(app.FilteringforsuddenspikesPanel);
            app.DeviationEditFieldLabel.HorizontalAlignment = 'right';
            app.DeviationEditFieldLabel.Position = [6 6 55 22];
            app.DeviationEditFieldLabel.Text = 'Deviation';

            % Create DeviationEditField
            app.DeviationEditField = uieditfield(app.FilteringforsuddenspikesPanel, 'numeric');
            app.DeviationEditField.Position = [72 6 58 22];

            % Create PlotSwitchLabel
            app.PlotSwitchLabel = uilabel(app.FilteringforsuddenspikesPanel);
            app.PlotSwitchLabel.HorizontalAlignment = 'center';
            app.PlotSwitchLabel.Position = [174 6 26 22];
            app.PlotSwitchLabel.Text = 'Plot';

            % Create PlotSwitch
            app.PlotSwitch = uiswitch(app.FilteringforsuddenspikesPanel, 'slider');
            app.PlotSwitch.Position = [164 37 47 21];

            % Create OnCheckBox
            app.OnCheckBox = uicheckbox(app.FilteringforsuddenspikesPanel);
            app.OnCheckBox.Text = 'On';
            app.OnCheckBox.Position = [180 64 38 22];

            % Create StatusTextAreaLabel
            app.StatusTextAreaLabel = uilabel(app.UIFigure);
            app.StatusTextAreaLabel.FontColor = [1 0 0];
            app.StatusTextAreaLabel.Position = [129 32 39 22];
            app.StatusTextAreaLabel.Text = 'Status';

            % Create StatusTextArea
            app.StatusTextArea = uitextarea(app.UIFigure);
            app.StatusTextArea.Editable = 'off';
            app.StatusTextArea.FontColor = [1 0 0];
            app.StatusTextArea.Position = [169 8 135 46];

            % Create PresetPanel
            app.PresetPanel = uipanel(app.UIFigure);
            app.PresetPanel.Title = 'Preset';
            app.PresetPanel.Position = [801 59 486 551];

            % Create Image
            app.Image = uiimage(app.UIFigure);
            app.Image.Enable = 'off';
            app.Image.Position = [11 7 99 52];
            app.Image.ImageSource = fullfile(pathToMLAPP, 'assets', 'FT_logo.png');

            % Create Sidebar
            app.Sidebar = uitextarea(app.UIFigure);
            app.Sidebar.Position = [309 8 483 67];

            % Create Format
            app.Format = uidropdown(app.UIFigure);
            app.Format.Items = {'png', 'pdf', 'fig', 'm'};
            app.Format.Position = [801 22 100 22];
            app.Format.Value = 'png';

            % Create savename
            app.savename = uieditfield(app.UIFigure, 'text');
            app.savename.Position = [909 22 279 22];
            app.savename.Value = 'plot1';

            % Create SaveButton
            app.SaveButton = uibutton(app.UIFigure, 'push');
            app.SaveButton.ButtonPushedFcn = createCallbackFcn(app, @SaveButtonPushed, true);
            app.SaveButton.Position = [1196 21 100 23];
            app.SaveButton.Text = 'Save';

            % Create StatsTextAreaLabel
            app.StatsTextAreaLabel = uilabel(app.UIFigure);
            app.StatsTextAreaLabel.HorizontalAlignment = 'right';
            app.StatsTextAreaLabel.Position = [262 59 32 16];
            app.StatsTextAreaLabel.Text = 'Stats';

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = app

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end
end