www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+xregdatagui/OutlierLine.m

    classdef OutlierLine < matlab.mixin.SetGet & matlab.mixin.Copyable
    %xregdatagui.OutlierLine class
    %    xregdatagui.OutlierLine properties:
    %       ManagedLines - Property is of type 'MATLAB array' (read only)
    %       OutlierLines - Property is of type 'MATLAB array' (read only)
    %       ManagedGuids - Property is of type 'MATLAB array' (read only)
    %       OutlierGuids - Property is of type 'MATLAB array'
    %       GuidsToHandles - Property is of type 'MATLAB array' (read only)
    %       OutlierIndices - Property is of type 'MATLAB array'
    %       AltClickCallback - Property is of type 'MATLAB array'
    %       Marker - Property is of type 'string'
    %       Color - Property is of type 'string'
    %       MarkerSize - Property is of type 'double'
    %       LineWidth - Property is of type 'double'
    %       Point - Property is of type 'mxArray'
    %       XData - Property is of type 'mxArray'
    %       YData - Property is of type 'mxArray'
    %       Box - Property is of type 'mxArray'
    %       BD - Property is of type 'mxArray'
    %       BD_indx - Property is of type 'mxArray'
    %       XLimMode - Property is of type 'string'
    %       YLimMode - Property is of type 'string'
    %
    %    xregdatagui.OutlierLine methods:
    %       add - Add handles to an outlierline
    %       clear - % OUTLIERLINE/CLEAR
    %       multiselect -  Start multiselection of outliers
    
    %  Copyright 2015-2015 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (Dependent,AbortSet, SetObservable)
        %OUTLIERGUIDS Property is of type 'MATLAB array'
        OutlierGuids = guidarray;
    end
    
    properties (AbortSet, SetObservable)
        %OUTLIERINDICES Property is of type 'MATLAB array'
        OutlierIndices = [];
        %ALTCLICKCALLBACK Property is of type 'MATLAB array'
        AltClickCallback = [];
        %MARKER Property is of type 'string'
        Marker = 'o';
        %COLOR Property is of type 'string'
        Color = 'r';
        %MARKERSIZE Property is of type 'double'
        MarkerSize = 10;
        %LINEWIDTH Property is of type 'double'
        LineWidth = 1.5;
        %POINT Property is of type 'mxArray'
        Point = [];
        %XDATA Property is of type 'mxArray'
        XData = [];
        %YDATA Property is of type 'mxArray'
        YData = [];
        %BOX Property is of type 'mxArray'
        Box = [];
        %BD Property is of type 'mxArray'
        BD = [];
        %BD_INDX Property is of type 'mxArray'
        BD_indx = [];
        %XLIMMODE Property is of type 'string'
        XLimMode = '';
        %YLIMMODE Property is of type 'string'
        YLimMode = '';
    end
    
    properties (Access=protected, AbortSet, SetObservable)
        %LISTENERS Property is of type 'handle vector'
        Listeners = [];
    end
    
    properties (SetAccess=protected, AbortSet, SetObservable)
        %MANAGEDLINES Property is of type 'MATLAB array' (read only)
        ManagedLines = gobjects( 0 );
        %OUTLIERLINES Property is of type 'MATLAB array' (read only)
        OutlierLines = gobjects( 0 );
        %MANAGEDGUIDS Property is of type 'MATLAB array' (read only)
        ManagedGuids = guidarray;
        %GUIDSTOHANDLES Property is of type 'MATLAB array' (read only)
        GuidsToHandles = [];
    end
    
    
    methods  % constructor block
        function obj = OutlierLine(lineHandles)
        %OutlierLine constructor
        %   L=OUTLIERLINE(lineHandle)
        %   L=OUTLIERLINE([lineHandles])
        %   L=OUTLIERLINE([lineHandles],'Property1',Value1,...)
        
        if nargin < 1
            lineHandles = [];
        end
        if  ~isempty(lineHandles)
            % add the input line handles to the outlierline
            add(obj,lineHandles);
        end
        end  % guidoutlierline
        
    end  % constructor block
    
    methods
        function value = get.OutlierGuids(obj)
        value = obj.ManagedGuids(obj.OutlierIndices);
        end
        function set.OutlierGuids(obj,value)
        if ~isa(value, 'guidarray')
            error(message('mbc:xregGui:guidoutlierline:InvalidProperty'));
        end
        % Which indices have been selected
        index = getIndices(obj.ManagedGuids, value);
        % Remove invalid selection
        index(index == 0) = [];
        % Set the internal outlierIndices
        obj.OutlierIndices = index;
        end
        
        function set.Marker(obj,Marker)
        obj.Marker = Marker;
        updateLine(obj);
        end
        
        function set.Color(obj,Color)
        obj.Color = Color;
        updateLine(obj);
        end
        
        function set.MarkerSize(obj,MarkerSize)
        obj.MarkerSize = MarkerSize;
        updateLine(obj);
        end
        
        function set.LineWidth(obj,LineWidth)
        obj.LineWidth = LineWidth;
        updateLine(obj);
        end
        
        function set.OutlierIndices(obj,OutlierIndices)
        obj.OutlierIndices = OutlierIndices;
        redraw(obj);
        end
        
        
    end   % set and get functions
    
    methods  % public methods
        %----------------------------------------
        function add(obj, lines, guids)
        %ADD Add handles to an outlierline
        %    ADD(OL, NEWHANDLES, GUIDS) checks NEWHANDLES are line handles and adds
        %    them to the outlierline OL
        %
        %    A series of handles are associated with the relevant parts of a single
        %    guid array. Hence an array of handles will index individually into the
        %    portions of the guid array. This function will throw an error if the guid
        %    array is shorter than the amount of data
        
        % Throw an error if we try to include something that isn't a handle
        if ~all(isgraphics(lines, 'line'))
            error(message('mbc:xregGui:guidoutlierline:InvalidArgument'));
        end
        
        % Only want truly new lines, so remove those we already have
        lines(ismember(lines, obj.ManagedLines)) = [];
        % Anything left?
        if isempty(lines)
            return
        end
        % Better check the number of points being indexed is the same as or more
        % than the length of the guid array
        data = get(lines, {'XData'});
        if length([data{:}]) < length(guids)
            error(message('mbc:xregGui:guidoutlierline:InvalidArgument1'));
        end
        
        % now set deletefcn and ButtonDownFcn for the new lines
        set(lines, 'ButtonDownFcn', {@i_lineClick, obj});
        
        newLineLengths = zeros(1, numel(lines));
        newLineIndex   = cell(1, numel(lines));
        % do the drawing on the new lines labelled by newH
        outlierLines = gobjects(1,numel(lines));
        for i = 1:numel(lines)
            thisLine = lines(i);
            % Create the outlier line for this managed line - note handle
            % visibility of the outlier line set to off. Users of outlier lines
            % should try to avoid deleteing them before the line they shadow,
            % otherwise we end up in trouble during deletion and holding invalid
            % handles to lines which doesn't seem to work in UDD.
            outlierLines(i) = line(...
                'Color', obj.Color,...
                'Marker', obj.Marker,...
                'LineStyle', 'none',...
                'Parent', thisLine.Parent,...
                'HitTest', 'off',...
                'MarkerSize', obj.MarkerSize,...
                'LineWidth', obj.LineWidth,...
                'HandleVisibility', 'off',...
                'Tag','Outliers',...
                'Visible', thisLine.Visible);
            mbcgui.hgclassesutil.setNotPickable(outlierLines(i));
            
            % Add a property to hold the listeners to the new outlier line
            mbcgui.hgclassesutil.addprop(thisLine, 'OL_Listeners');
            % === listen for line being destroyed, data changed, etc ===
            listeners = {...
                mbcgui.hgclassesutil.listener(thisLine, 'ObjectBeingDestroyed',  mbcutils.callback(@i_lineDestroyed, obj));...
                mbcgui.hgclassesutil.proplistener(thisLine, 'XData', 'PostSet',  mbcutils.callback(@i_dataChanged, obj));...
                mbcgui.hgclassesutil.proplistener(thisLine, 'YData', 'PostSet',  mbcutils.callback(@i_dataChanged, obj));...
                mbcgui.hgclassesutil.proplistener(thisLine, 'ZData', 'PostSet',  mbcutils.callback(@i_dataChanged, obj));...
                mbcgui.hgclassesutil.proplistener(thisLine, 'Visible', 'PostSet',  mbcutils.callback(@i_visibleChanged, outlierLines(i)));...
                };
            % Add the listeners to the line
            set(thisLine, 'OL_Listeners', listeners);
            % Remember how much data there is in each line
            newLineLengths(i) = length(get(thisLine, 'XData'));
            % Has the line reordered it's XData (see sweepset/plot..
            if isprop(thisLine, 'OriginalXDataIndex')
                newLineIndex{i} = get(thisLine, 'OriginalXDataIndex');
            else
                newLineIndex{i} = 1:newLineLengths(i);
            end
        end
        numLinesBefore = length(obj.ManagedLines);
        % Add new lines to the property fields
        obj.ManagedLines = [obj.ManagedLines ; lines(:) ];
        obj.OutlierLines = [obj.OutlierLines ; outlierLines(:) ];
        % Do these lines have any new guids?
        newGuids = guids(~ismember(guids, obj.ManagedGuids));
        % Add them to the ManagedGuids
        obj.ManagedGuids = [obj.ManagedGuids ; newGuids(:)];
        % Need to update the GuidsToHandles array - first resize by placing a zero
        % in the bottom right corner
        obj.GuidsToHandles(length(obj.ManagedGuids), length(obj.ManagedLines)) = 0;
        % Calculate the start and end points for the guidarray
        gStart = cumsum([1 newLineLengths]);
        gEnd   = cumsum(newLineLengths);
        tmpGuidsToHandles = obj.GuidsToHandles;
        tmpManagedGuids = obj.ManagedGuids;
        % Now indicate which line handles contain which guids
        for i = 1:length(newLineLengths)
            % Find the rows that hold these elements
            index = getIndices(tmpManagedGuids, guids(gStart(i):gEnd(i)));
            tmpGuidsToHandles(index, i + numLinesBefore) = newLineIndex{i}(:);
        end
        obj.GuidsToHandles = tmpGuidsToHandles;
        % Update the new lines
        obj.redraw([], lines);
        end  % add
        
        %----------------------------------------
        function clear(obj)
        %CLEAR clear outlier indices
        %   CLEAR(OBJ) 
        
        % clear the ol indices
        obj.OutlierIndices = [];
        
        end  % clear
        
        %----------------------------------------
        function multiselect(oL)
        %MULTISELECT  Start multiselection of outliers
        %    OBJ.MULTISELECT starts a multi-selection action in the GUI.
        
        % set up the button down fcn
        OK = isgraphics(oL.ManagedLines);
        oL.ManagedLines = oL.ManagedLines(OK);
        oL.OutlierLines = oL.OutlierLines(OK);
        
        lineParents = get(oL.ManagedLines,{'Parent'});
        lineParents = [lineParents{:}];
        allFigs = ancestor(oL.ManagedLines,'figure');
        if length(allFigs)>1
            allFigs = unique([allFigs{:}]);
        end
        ws = warning('off','mbc:mv_rotate3d:InvalidState1');
        restoreWarns = onCleanup(@() warning(ws));
        
        old_btn_down = get(allFigs, 'WindowButtonDownFcn');
        set(allFigs, 'WindowButtonDownFcn', @i_point, ...
            'Pointer', 'crosshair');
        xtickmode = [];
        ytickmode = [];
        MManager= [];
        
            function i_point(hFig, ~)
            % capture mouse click and get ready for dragging (or abort)
            set(allFigs, 'WindowButtonDownFcn', old_btn_down, ...
                'Pointer','arrow');
            set(hFig, 'Pointer','crosshair');
            
            axH = get(hFig, 'CurrentAxes');
            
            ind = ismember(lineParents, axH);
            SweepLines = oL.ManagedLines(ind);
            if isempty(SweepLines) || strcmp(get(axH, 'Visible'),'off');
                % abort
                set(hFig, 'Pointer','arrow');
                return
            end
            
            % check we clicked inside the axes?
            cp = get(hFig,'CurrentPoint');
            axpos = get(axH, 'Position');
            cp  = mbcgui.util.convertLocation(cp, axH);
            if cp(1)< 1 || cp(1)>axpos(3) ...
                    || cp(2)<1 || cp(2)>axpos(4)
                % abort
                set(hFig, 'Pointer','arrow');
                return
            end
            
            bm = xregGui.ButtonUpManager(hFig);
            bm.getNextEvent({@i_clean, oL, axH});
            MManager = MotionManager(hFig);
            MManager.MouseMoveFcn = {@i_motion, axH};
            MManager.EnableTree = false;
            
            % get the current axes_limmodes and tickmodes
            oL.XLimMode = get(axH,'XLimMode');
            oL.YLimMode = get(axH,'YLimMode');
            xtickmode = get(axH,'XTickMode');
            ytickmode = get(axH,'YTickMode');
            set(axH,'XLimMode','manual','YLimMode','manual', ...
                'XTickMode','manual','YTickMode','manual');
            
            cp = get(axH,'CurrentPoint');
            point = cp(1,1:2);
            xdata = zeros(1,5);
            ydata = zeros(1,5);
            xdata(:) = point(1);
            ydata(:) = point(2);
            
            oL.Point = point;
            oL.XData = xdata;
            oL.YData = ydata;
            
            % the stretchy box
            boxl = line('Parent',axH,...
                'LineStyle',':',...
                'XData',xdata,...
                'YData',ydata,...
                'Color','r',...
                'Tag','box');
            % the line marking points in the box
            oL.BD = line('Parent',axH,...
                'LineStyle','none',...
                'Marker','o',...
                'Color',[1 0 0],...
                'XData',NaN,...
                'YData',NaN,...
                'LineWidth',2,...
                'MarkerSize',12);
            
            oL.Box = boxl;
            % oL.BD_indx = false(1,oL.datasize);
            end
        
        
            function i_motion(~, ~, axH)
            cp = get(axH,'CurrentPoint');
            point = cp(1,1:2);
            box = oL.Box;
            xdata = oL.XData;
            ydata = oL.YData;
            
            xdata([2,3]) = point(1);
            ydata([3,4]) = point(2);
            
            % mark on the points in the stretchy box
            i_highlight(oL,xdata,ydata, axH,lineParents);
            % draw the stretchy box
            set(box,'XData',xdata,'YData',ydata);
            end
        
        
            function i_clean(bm, ~, oL, axH)
            set(bm.Figure, 'Pointer', 'arrow');
            MManager.MouseMoveFcn = '';
            MManager.EnableTree = true;
            
            % restore axes limits mode
            set(axH,'XLimMode',oL.XLimMode,'YLimMode',oL.YLimMode);
            %restore the tickmodes as well
            set(axH,'XTickMode',xtickmode,'YTickMode',ytickmode);
            
            % delete the red box...
            delete(oL.Box);
            % and the big red circles
            delete(oL.BD);
            % update the x and ydata in the outlier line.
            oL.OutlierIndices= union(oL.OutlierIndices,oL.BD_indx);
            end
        end
        
        
    end  % public methods
    
    
    methods (Hidden) % possibly private or hidden
        %----------------------------------------
        function click(obj, hLine)
        %CLICK click callback for outlier lines
        %   CLICK(obj, hLine)
        %   CLICK is the line callback from one of the OL lines.
        %   New outlier added or current outlier removed from all OL lines
        
        % Find the line in the list of handled lines
        lineIndex = find(hLine == obj.ManagedLines);
        % Is it one of ours?
        if isempty(lineIndex)
            return
        end
        % Find the point index in the data of the line that we have clicked on.
        ax = get(hLine, 'Parent');
        cp = get(ax, 'CurrentPoint');
        p1 = cp(1, :)';
        p2 = cp(2, :)';
        % Make some decisions
        SELECTION_IS_3D = ~isequal(p1(1:2), p2(1:2));
        DATA_IS_3D      = ~isempty(get(hLine, 'ZData'));
        % We are going to need to code everything by the axis limits and offset by
        % CurrentPoint(1,:)
        sX = diff(get(ax, 'XLim'));
        sY = diff(get(ax, 'YLim'));
        sZ = diff(get(ax, 'ZLim'));
        % Make the required data correctly
        if SELECTION_IS_3D
            if DATA_IS_3D
                data = [(get(hLine, 'XData') - p1(1))/sX ;...
                    (get(hLine, 'YData') - p1(2))/sY ;...
                    (get(hLine, 'ZData') - p1(3))/sZ ];
            else
                data = [(get(hLine, 'XData') - p1(1))/sX ;...
                    (get(hLine, 'YData') - p1(2))/sY ;...
                    (zeros(size(get(hLine, 'XData'))) - p1(3))/sZ ];
            end
        else
            data = [(get(hLine, 'XData') - p1(1))/sX ;...
                (get(hLine, 'YData') - p1(2))/sY ];
        end
        
        % Only bother with the 3D selection if the selection is in 3D
        if SELECTION_IS_3D
            % Get the vector that needs to be rotated to the z-axis
            v = (p2 - p1)./[sX ; sY ; sZ];
            % Create x, y and z from the vector
            x = v(1);y = v(2);z = v(3);
            % Find the rotation matrix - first need to az and el - Note that we
            % require a negative rotation around the z-axis but a positive rotation
            % around the y-axis - Hence p is positive and t is negative
            p = atan2(sqrt(x*x + y*y), z);
            t = -atan2(y, x);
            % Form cos and sin of p and t
            ct = cos(t);st = sin(t);cp = cos(p);sp = sin(p);
            % Form the matrix - But we don't care about z now, so ignore it
            M = [cp*ct -cp*st  -sp  ;...
                st     ct     0    ]; %;...
            %sp*ct  -sp*st cp     ];
            % Rotate and translate the data appropriately
            data = M * data;
            % % Try an alternative metric - Mark H's approach
            % q = [xdata ; ydata ; zdata];
            % fv = repmat(v, 1, size(q, 2));
            % % Try Marks approach
            % n = q - v * (dot(fv, q)/sum(v.^2));
            % nmetric = sqrt(sum(n.^2));
        end
        
        % Calculate a distance metric for the clicked point - NOTE it doesn't
        % matter what metric we use for closeness - using L-Inf
        metric = sqrt(sum(data.^2));
        [~, pointIndex] = min(metric);
        
        % OK - which guid was just clicked
        guidIndex = find(obj.GuidsToHandles(:, lineIndex) == pointIndex);
        % Did we find a valid guidIndex
        if isempty(guidIndex)
            return
        end
        obj.OutlierIndices = setxor(obj.OutlierIndices, guidIndex);
        % %% outlierIndices listener changes calls redraw callback
        
        end  % click
        
        %----------------------------------------
        function redraw(obj, ~, linesToUpdate)
        %REDRAW deletes then redraws all the current outlierlines of OL
        %    REDRAW(OL, ~, linesToUpdate)
        
        % Get a local copy of ManagedLines and GuidsToHandles
        managedLines = obj.ManagedLines;
        outlierLines = obj.OutlierLines;
        guidToHandle = obj.GuidsToHandles;
        outlierIndices = obj.OutlierIndices;
        
        % The lines requiring outlierlines to be drawn on them
        if nargin < 3
            indexToUpdate = 1:length(managedLines);
        else
            indexToUpdate = find(ismember(managedLines, linesToUpdate));
        end
        % Anything to update?
        if isempty(indexToUpdate)
            return
        end
        % Iterate over the lines that need updateing
        for i = indexToUpdate(:)'
            % Get this line and it's associated outlier line
            thisOutlierLine = outlierLines(i);
            thisManagedLine = managedLines(i);
            % Only bother attempting to redraw if the outlierLine is still valid
            if ~isgraphics(thisOutlierLine)
                continue
            end
            % Which indices for this line have been selected
            selectedLineIndex = guidToHandle(outlierIndices, i);
            % Remove any zeros that indicate that that guid is not present in this
            % line
            selectedLineIndex(selectedLineIndex == 0) = [];
            % Get the relevant data for the outlier line
            xdata = get(thisManagedLine,'XData');
            xdata = xdata(selectedLineIndex);
            ydata = get(thisManagedLine, 'YData');
            ydata = ydata(selectedLineIndex);
            % Possible that zdata isn't the same size as x and y
            if isempty(get(thisManagedLine, 'ZData'))
                set(outlierLines(i), 'XData', xdata, 'YData', ydata);
            else
                % Only include zdata if it is relevant
                zdata = get(thisManagedLine, 'ZData');
                zdata = zdata(selectedLineIndex);
                set(outlierLines(i), 'XData', xdata, 'YData', ydata, 'ZData', zdata);
            end
        end
        
        end  % redraw
        
        %----------------------------------------
        function remove(obj, lines)
        %REMOVE remove lines from OutlierLine
        %   REMOVE(OL, HNDS) check HNDS are current line handles of OL,
        %   delete their outlier lines and remove the line handles from the
        %   OL userdata
        %
        %   called by listner to ObjectBeingDestroyed of line on
        %   line/axes/figure delete.
        %   NOTE: all lines can be removed, the outlierindices persist
        
        % Check they are current OL line handles
        index = ismember(obj.ManagedLines, lines, 'legacy');
        % Did we find any?
        if any(index)
            set(obj.ManagedLines(index), 'ButtonDownFcn', '');
            % Which of the outlier lines need to be removed
            linesToDelete = obj.OutlierLines(index);
            % Are they still valid - i.e. has a figure deletion already got rid of
            % them
            delete(linesToDelete(isgraphics(linesToDelete)));
            
            % remove line handles etc from ud
            obj.ManagedLines = obj.ManagedLines(~index);
            obj.OutlierLines = obj.OutlierLines(~index);
            % Remove those line handles from the GuidsToHandles Array
            obj.GuidsToHandles = obj.GuidsToHandles(:, ~index);
            % Has this left some guids we are no longer managing
            validGuids = any(obj.GuidsToHandles, 2);
            % Need a logical outlierIndices array to correctly dereference
            lOutlierIndices = false(1, length(obj.ManagedGuids));
            lOutlierIndices(obj.OutlierIndices) = true;
            % Keep these valid guids
            obj.GuidsToHandles = obj.GuidsToHandles(validGuids, :);
            obj.ManagedGuids = obj.ManagedGuids(validGuids);
            % Convert the outlierIndices to a logical to remove, and then convert
            % back
            lOutlierIndices = lOutlierIndices(validGuids);
            obj.OutlierIndices = find(lOutlierIndices);
        end
        
        end  % remove
        
    end  % possibly private or hidden
    
end  % classdef

function updateLine(obj)
% Need to update the properties of the outlier lines
if isgraphics(obj.OutlierLines)
    set(obj.OutlierLines, ...
        'Marker', obj.Marker,...
        'Color', obj.Color,...
        'MarkerSize', obj.MarkerSize,...
        'LineWidth', obj.LineWidth);
end
end  % i_redraw

function i_lineDestroyed(src, ~, obj)
% Need to ensure that we still exist
if isvalid(obj)
    remove(obj, src);
end
end  % i_lineDestroyed

% ------------------------------------------------------------------------------
function i_visibleChanged(~, event, outlierLine)
% Replicate the visibility in the outlier line
set(outlierLine, 'Visible', get(event.AffectedObject, 'Visible'));
end  % i_visibleChanged

% ------------------------------------------------------------------------------
function i_dataChanged(src, event, obj)
% Which outlier line needs it's data updateing
obj.redraw(event, src);
end  % i_dataChanged

% ------------------------------------------------------------------------------
function i_lineClick(lineH, event, obj)
% function handle call
clicktype = get(gcbf,'SelectionType');
switch clicktype
    case 'alt'
        xregcallback(obj.AltClickCallback, lineH, event);
    otherwise
        click(obj, lineH);
end
end  % i_lineClick

function i_highlight(oL,xcoords,ycoords, axH,lineParents)
%i_highlight(oL,xcoords,ycoords, axH,lineParents)

% find all lines on these axes (axH)
ind = ismember(lineParents, axH);
SweepLines=oL.ManagedLines(ind);

% find the indices of all datapoints in the box
bd_xdata=[];
bd_ydata = [];
for i = 1:length(SweepLines)
    lineIndex = SweepLines(i) == oL.ManagedLines;
    
    xdata=get(SweepLines(i),'XData');
    ydata=get(SweepLines(i),'YData');
    
    xindx=xdata>min(xcoords)&xdata<max(xcoords);
    yindx=ydata>min(ycoords)&ydata<max(ycoords);
    thisIndx=find(xindx & yindx);
    
    guidIndex = find( ismember(oL.GuidsToHandles(:, lineIndex),thisIndx ));
    
    if i==1
        totalIndx = guidIndex;
    else
        totalIndx = union(guidIndex, totalIndx);
    end
    bd_xdata = [bd_xdata, xdata(thisIndx)]; %#ok<AGROW>
    bd_ydata = [bd_ydata, ydata(thisIndx)];     %#ok<AGROW>
    
end

oL.BD_indx=totalIndx;
bd_hnd=oL.BD;
if isgraphics(bd_hnd)
    set(bd_hnd,'XData',bd_xdata,...
        'YData',bd_ydata);
end
end