Main Content

Create Simple Live Editor Task

This example shows how to create a simple custom Live Editor task and add it to a live script.

Define Live Editor Task Subclass

Define a class called NormalizeVectorData that creates a custom Live Editor task for normalizing vector data.

To define the class, create a file called NormalizeVectorData.m that contains the NormalizeVectorData class definition with these features:

  • State and Summary public properties that store the current state of the task and a dynamic summary of what the task does.

  • Private properties that store the drop-down lists, spinners, checkboxes, and grid layout managers for selecting input data and specifying parameters.

  • A setup method that initializes the task.

  • A generateCode method that updates the generated code for the task.

  • get.Summary, get.State, and set.State methods for getting and setting the summary and state of the task.

  • An updateComponents method that updates the task when a user selects input data or changes parameters.

  • A reset method that resets the state of the task.

NormalizeVectorData Class Definition

classdef NormalizeVectorData < matlab.task.LiveTask
    properties(Access = private,Transient)
        InputDataDropDown               matlab.ui.control.DropDown
        MethodDropDown                  matlab.ui.control.DropDown
        ZscoreGrid                      matlab.ui.container.GridLayout
        ZscoreDropDown                  matlab.ui.control.DropDown
        RangeGrid                       matlab.ui.container.GridLayout
        LeftRangeSpinner                matlab.ui.control.Spinner
        RightRangeSpinner               matlab.ui.control.Spinner
        InputDataCheckBox               matlab.ui.control.CheckBox
        NormalizedDataCheckBox          matlab.ui.control.CheckBox
    end

    properties(Dependent)
        State
        Summary
    end

    methods(Access = private)
        function createComponents(task)
            g = uigridlayout(task.LayoutManager,[1,1]);
            g.RowHeight = ["fit" "fit" "fit" "fit" "fit" "fit"];
            g.ColumnWidth = "fit";

            % Row 1: Select data section label
            uilabel(g,Text="Select data",FontWeight="bold");

            % Row 2: Select data section components
            inputgrid = uigridlayout(g,RowHeight="fit", ...
                ColumnWidth=["fit","fit"],Padding=0);
            uilabel(inputgrid,Text="Input data");
            task.InputDataDropDown = uidropdown(inputgrid, ...
                ValueChangedFcn=@task.updateComponents, ...
                DropDownOpeningFcn=@task.populateWSDropdownItems);
            task.populateWSDropdownItems(task.InputDataDropDown);

            % Row 3: Specify method section label
            uilabel(g,Text="Specify method",FontWeight="bold");

            % Row 4: Method section components
            methodgrid = uigridlayout(g,RowHeight="fit", ...
                ColumnWidth=["fit","fit","fit"],Padding=0);
            uilabel(methodgrid,Text="Normalization method");
            task.MethodDropDown = uidropdown(methodgrid, ...
                ValueChangedFcn=@task.updateComponents);
            task.MethodDropDown.Items = ["Z-score" "2-Norm" ...
                "Scale by standard deviation" "Scale to new range" ...
                "Center to mean 0"];
            task.MethodDropDown.ItemsData = ["zscore" "norm" "scale" ...
                "range" "center"];

            % Subgrid 1 in method section
            task.ZscoreGrid = uigridlayout(methodgrid,RowHeight="fit", ...
                ColumnWidth=["fit","fit"],Padding=0);
            uilabel(task.ZscoreGrid,Text="Deviation type");
            task.ZscoreDropDown = uidropdown(task.ZscoreGrid, ...
                ValueChangedFcn=@task.updateComponents, ...
                Items=["Standard" "Median absolute"], ...
                ItemsData=["std" "robust"], ...
                Tooltip="Center data to 0 and scale to deviation 1");

            % Subgrid 2 in method section
            task.RangeGrid = uigridlayout(methodgrid,RowHeight="fit", ...
                ColumnWidth={"fit" 50 50},Padding=0);
            task.RangeGrid.Layout.Row = 1;
            task.RangeGrid.Layout.Column = 3;
            uilabel(task.RangeGrid,Text="Range edges");
            task.LeftRangeSpinner = uispinner(task.RangeGrid, ...
                ValueChangedFcn=@task.updateComponents, ...
                Tag="LeftRangeSpinner", ...
                Tooltip="Left edge of new range");

            task.RightRangeSpinner = uispinner(task.RangeGrid, ...
                ValueChangedFcn=@task.updateComponents, ...
                Tag="RightRangeSpinner", ...
                Tooltip="Right edge of new range");

            % Row 5: Display results section label
            uilabel(g,Text="Display results",FontWeight="bold");

            % Row 6: Display results section components
            displaygrid = uigridlayout(g,RowHeight="fit", ...
                ColumnWidth=["fit","fit"],Padding=0);
            task.InputDataCheckBox = uicheckbox(displaygrid, ...
                Text="Input data",ValueChangedFcn=@task.updateComponents);
            task.NormalizedDataCheckBox = uicheckbox(displaygrid, ...
                Text="Normalized data",ValueChangedFcn=@task.updateComponents);
        end

        function setComponentsToDefault(task)
            task.MethodDropDown.Value = "zscore";
            task.ZscoreDropDown.Value = "std";
            task.LeftRangeSpinner.Value = 0;
            task.RightRangeSpinner.Value = 1;
            task.InputDataCheckBox.Value = true;
            task.NormalizedDataCheckBox.Value = true;
        end

        function updateComponents(task,source,~)
            if nargin > 1
                if isequal(source.Tag,"LeftRangeSpinner")
                    if task.RightRangeSpinner.Value <= task.LeftRangeSpinner.Value
                        task.RightRangeSpinner.Value = task.LeftRangeSpinner.Value + 1;
                    end
                elseif isequal(source.Tag,"RightRangeSpinner")
                    if task.RightRangeSpinner.Value <= task.LeftRangeSpinner.Value
                        task.LeftRangeSpinner.Value = task.RightRangeSpinner.Value - 1;
                    end
                end
            end
            hasData = ~isequal(task.InputDataDropDown.Value,"select variable");
            task.MethodDropDown.Enable = hasData;
            task.ZscoreDropDown.Enable = hasData;
            task.LeftRangeSpinner.Enable = hasData;
            task.RightRangeSpinner.Enable = hasData;
            task.InputDataCheckBox.Enable = hasData;
            task.NormalizedDataCheckBox.Enable = hasData;
            % Show only relevant subgrids
            task.ZscoreGrid.Visible = isequal(task.MethodDropDown.Value,"zscore");
            task.RangeGrid.Visible = isequal(task.MethodDropDown.Value,"range");
            % Trigger the live editor to update the generated script
            notify(task,"StateChanged");
        end

        function populateWSDropdownItems(~,src,~)
            workspaceVariables = evalin("base","who");
            src.Items = ["select variable"; workspaceVariables];
        end
    end

    methods(Access = protected)
        function setup(task)
            createComponents(task);
            setComponentsToDefault(task);
            updateComponents(task);
        end
    end

    methods
        function [code,outputs] = generateCode(task)
            if isequal(task.InputDataDropDown.Value,"select variable")
                % Return empty values if there is not enough
                % information to generate code
                code = "";
                outputs = {};
                return
            end
            
            outputs = {'normalizedData'};
            
            inputdata = "`" + task.InputDataDropDown.Value + "`";
            if isequal(task.MethodDropDown.Value,"zscore") && ...
                    isequal(task.ZscoreDropDown.Value,"std")
                code = "normalizedData = normalize(" + inputdata + ");";    
            elseif isequal(task.MethodDropDown.Value,"zscore")
                    code = "normalizedData = normalize(" + inputdata + "," + ...
                        """zscore"",""" + task.ZscoreDropDown.Value + """);";
            elseif isequal(task.MethodDropDown.Value,"range")
                    if isequal(task.LeftRangeSpinner.Value,0) && ...
                            isequal(task.RightRangeSpinner.Value,1)
                        code = "normalizedData = normalize(" + inputdata + ...
                            ",""range"");";
                    else
                        code = "normalizedData = normalize(" + inputdata + ...
                            ",""range"",[" + task.LeftRangeSpinner.Value + "," + ...
                            task.RightRangeSpinner.Value + "]);";
                    end
            else
                code = "normalizedData = normalize(" + inputdata + ...
                    ",""" + task.MethodDropDown.Value + """);";
            end
            
            inputplotcode = "plot(" + inputdata + ",DisplayName=""Input data"")";
            outputplotcode = "plot(normalizedData,DisplayName=""Normalized data"")";
            
            if task.InputDataCheckBox.Value && task.NormalizedDataCheckBox.Value
                code = ["% Normalize data"; code; "% Display results"; ...
                    inputplotcode; "hold on"; outputplotcode; "hold off"; ...
                    "legend"];
            elseif task.InputDataCheckBox.Value
                code = ["% Normalize data"; code; "% Display results"; ...
                    inputplotcode; "legend"];
            elseif task.NormalizedDataCheckBox.Value
                code = ["% Normalize data"; code; "% Display results"; ...
                    outputplotcode; "legend"];
            else
                code = ["% Normalize data"; code];
            end                
        end
            
        function summary = get.Summary(task)
            if isequal(task.InputDataDropDown.Value,"select variable")
                summary = "Normalize vector data";
            else
                switch task.MethodDropDown.Value
                    case "zscore"
                        methodString = " using z-score";
                    case "norm"
                        methodString = " using 2-norm";
                    case "scale"
                        methodString = " using scaling by standard deviation";
                    case "range"
                        methodString = " by scaling to new range";
                    case "center"
                        methodString = " by centering the data to 0";
                end
                summary = "Normalized vector `" + task.InputDataDropDown.Value + ...
                    "`" + methodString;
            end
        end

        function state = get.State(task)
            state = struct;
            state.InputDataDropDownValue = task.InputDataDropDown.Value;
            state.MethodDropDownValue = task.MethodDropDown.Value;
            state.ZscoreDropDownValue = task.ZscoreDropDown.Value;
            state.LeftRangeSpinnerValue = task.LeftRangeSpinner.Value;
            state.RightRangeSpinnerValue = task.RightRangeSpinner.Value;
            state.InputDataCheckboxValue = task.InputDataCheckBox.Value;
            state.NormalizedDataCheckboxValue = task.NormalizedDataCheckBox.Value;
        end

        function set.State(task,state)
            value = state.InputDataDropDownValue;
            if ~ismember(value, task.InputDataDropDown.ItemsData)
                % In case the selected Input Data variable was cleared after
                % saving the mlx file and before reopening the mlx file
                task.InputDataDropDown.Items = [task.InputDataDropDown.Items value];
            end
            task.InputDataDropDown.Value = value;
            task.MethodDropDown.Value = state.MethodDropDownValue;
            task.ZscoreDropDown.Value = state.ZscoreDropDownValue;
            task.LeftRangeSpinner.Value = state.LeftRangeSpinnerValue;
            task.RightRangeSpinner.Value = state.RightRangeSpinnerValue;
            task.InputDataCheckBox.Value = state.InputDataCheckboxValue;
            task.NormalizedDataCheckBox.Value = state.NormalizedDataCheckboxValue;
            updateComponents(task);
        end
        
        function reset(task)
            setComponentsToDefault(task);
            updateComponents(task);
        end
    end
end

Configure Live Editor Task Metadata

To configure the task metadata, call the matlab.task.configureMetadata function and select the NormalizeVectorData.m file. The Task Metadata dialog box opens with all of the required task metadata details prepopulated.

Modify the prepopulated metadata details and click OK. MATLAB creates a folder named resources inside the folder containing your task class definition file. Inside the resources folder, MATLAB generates a file named liveTasks.json. Add the folder containing the task class definition file to the MATLAB path by calling the addpath function or using the Add Folder button in the Set Path dialog box.

Add Live Editor Task to Live Script

On a code line, type vector. MATLAB shows a list of suggested matches.

Select Normalize Vector Data from the list. MATLAB adds the Normalize Vector Data task to the live script.

See Also

| | |

Related Topics