www.gusucode.com > datamanager 工具箱matlab源码程序 > datamanager/linkdata.m

    function [out] = linkdata(arg1,arg2)
%LINKED Automatically update graphs when variables change.
%  LINKDATA ON turns on linking for the current figure.
%  LINKDATA OFF turns it off.
%  LINKDATA by itself toggles the state.
%  LINKDATA(FIG,...) works on specified figure handle.
%
%  H = LINKDATA(FIG) returns a linkdata object with the following property: 
%
%        Enable  'on'|{'off'}
%        Specifies whether this figure is currently linked.
%
%  EXAMPLE: 
%
%  x = randn(10,1);
%  plot(x);
%  linkdata on
%
%  See also BRUSH.

%  Copyright 2007-2015 The MathWorks, Inc.

if isdeployed
    error(message('MATLAB:linkdata:nodeploy'));
end

if nargin==0
        fig = handle(gcf); % caller did not specify handle
        if nargout == 0
            state = locSetNewBooleanState(fig,'toggle');
        else
            if ~isempty(fig.findprop('LinkPlot'))
                if fig.LinkPlot
                    out = matlab.graphics.internal.LinkData('on');
                else
                    out = matlab.graphics.internal.LinkData('off');
                end
            else
                out = matlab.graphics.internal.LinkData('off');
            end
            return
        end
elseif nargin==1
    if isscalar(arg1) && ishghandle(arg1,'figure')
        fig = handle(arg1);
        if nargout == 0
            state = locSetNewBooleanState(fig,'toggle');
        else
            if ~isempty(fig.findprop('LinkPlot'))
                if fig.LinkPlot
                    out = matlab.graphics.internal.LinkData('on');
                else
                    out = matlab.graphics.internal.LinkData('off');
                end
            else
                 out = matlab.graphics.internal.LinkData('off');
            end
            return
        end     
    elseif ischar(arg1)
        fig = handle(gcf); % caller did not specify handle
        state = locSetNewBooleanState(fig,arg1);
        if nargout > 0
            out = state;
        end
    else
        error(message('MATLAB:linkdata:InvalidSingleArg'));
    end
elseif nargin==2   
    if nargout > 0
        error(message('MATLAB:linkdata:InvalidArgsForOutput'));
    end
    if ~ishghandle(arg1)
        error(message('MATLAB:linkdata:InvalidFigure'));
    end
    fig = handle(arg1);
    state = locSetNewBooleanState(fig,arg2);
end

% There can be latency between closing a figure and java calls
if ~ishghandle(fig) || isempty(get(fig,'Parent'))
    return
end

% Remove any de-linked plots from the LinkPlotManager
h = datamanager.linkplotmanager;
brushManager = datamanager.brushmanager;
if ~strcmp(state.Enable,'on')
    % Clear brushing on all objects with custom linked behavior
    customLinkedObj = findall(fig,'-and','-not',{'Behavior',struct},'-function',...
        @localHasLinkedBehavior);
    
    [mfile,fcnname] = datamanager.getWorkspace(1);
    for k=1:length(customLinkedObj)
        brushManager.clearLinked(fig,get(fig,'CurrentAxes'),mfile,fcnname);
    end
    
    fig.LinkPlot = false;
    h.rmFigure(handle(fig));
    localSetFigureState(fig,'off');

    return;
end

% Find graphic objects with empty x/y data sources
ls = findobj(fig ,'-property','XDataSource','-property','YDataSource',...
       'XDataSource','','YDataSource','','Visible','on','HandleVisibility','on');
%  Exclude those with non-empty zdatasources
zDataSrcObjects = findobj(ls,'-property','ZDataSource','-function',@(x) ~isempty(x.ZDataSource));
if ~isempty(zDataSrcObjects)    
    ls = setdiff(double(ls),double(zDataSrcObjects));
end
%  Exclude those disabled with behavior objects
lsBehaviorDisabled = findobj(ls,'-and','-not',{'Behavior',struct},'-function',...
       @localHasDisabledLinkedBehavior);

if ~isempty(lsBehaviorDisabled)
    ls = setdiff(ls,lsBehaviorDisabled);
end

showSourceResolutionDlg = false;
wsVars = evalin('caller','whos');
for k=1:length(ls)
    xmatchingVarCount = 0;
    ymatchingVarCount = 0;
    zmatchingVarCount = 0;
    xdataSourceString = '';
    ydataSourceString = '';
    zdataSourceString = '';
    ydata = get(ls(k),'YData_I');
    if ~isempty(findprop(handle(ls(k)),'XDataMode')) && strcmp(get(ls(k),'XDataMode'),'auto')        
        xdata = [];
    else
        xdata = get(ls(k),'XData_I');
    end
    if ~isempty(findprop(handle(ls(k)),'ZData_I')) && ~isempty(get(ls(k),'ZData_I'))
        zdata = get(ls(k),'ZData_I');
    else
        zdata = [];
    end

    xdataSourceArray = {};
    ydataSourceArray = {};
    zdataSourceArray = {};
    
    % Note if the line is in a plotyy axes. If so, don't try to match the
    % xdata to a variable because when the plot is brushed the x,y1, and y2
    % variables will all be brushed with the result that the interaction
    % between brushed variables can produce correct but hard to explain results.
        
    lineIsInPlotYY = false;
    axloc = ancestor(ls(k),'axes');    
    if ~isempty(axloc)
        lineIsInPlotYY = isappdata(axloc,'graphicsPlotyyPeer') && ...
            ishghandle(getappdata(axloc,'graphicsPlotyyPeer'));
    end
    
    for j=1:length(wsVars)
        % Look for match vectors in the current workspace
        varData = [];

        % For xdata, check is wsVars(j) is a matrix with matching column sizes
        % or is a row vector of matching size
        if ~lineIsInPlotYY && ~isempty(xdata) && ...
                (wsVars(j).size(1)==length(xdata) || (length(wsVars(j).size)==2 && ...
                wsVars(j).size(1)==1 && wsVars(j).size(2)==length(xdata)))
             varData = evalin('caller',wsVars(j).name);
             if isTypeSupported(varData) && ndims(varData)<=2
                 if isvector(varData)
                      if isequaln(varData(:),xdata(:))
                          xdataSourceString = wsVars(j).name;
                          xmatchingVarCount = xmatchingVarCount+1;
                          xdataSourceArray{xmatchingVarCount} = xdataSourceString; %#ok<AGROW>
                      end
                 else
                     formatStr = '%s(:,%d)';
                     I = localCompareCols(varData,xdata(:)*ones(1,size(varData,2)));
                     for kk=1:length(I)
                         xdataSourceString = sprintf(formatStr,wsVars(j).name,I(kk));
                         xmatchingVarCount = xmatchingVarCount+1;
                         xdataSourceArray{xmatchingVarCount} = xdataSourceString; %#ok<AGROW>
                     end 
                 end
             end
        end
        if ~isempty(ydata) && (wsVars(j).size(1)==length(ydata) || (length(wsVars(j).size)==2 && ...
                wsVars(j).size(1)==1 && wsVars(j).size(2)==length(ydata)))
             if isempty(varData)
                 varData = evalin('caller',wsVars(j).name);
             end
             if isTypeSupported(varData) && ndims(varData)<=2
                 if isvector(varData)
                      if isequaln(varData(:),ydata(:))
                          ydataSourceString = wsVars(j).name;
                          ymatchingVarCount = ymatchingVarCount+1;
                          ydataSourceArray{ymatchingVarCount} = ydataSourceString; %#ok<AGROW>
                      end
                 else
                     formatStr = '%s(:,%d)';
                     I = localCompareCols(varData,ydata(:)*ones(1,size(varData,2)));
                     for kk=1:length(I)
                         ydataSourceString = sprintf(formatStr,wsVars(j).name,I(kk));
                         ymatchingVarCount = ymatchingVarCount+1;
                         ydataSourceArray{ymatchingVarCount} = ydataSourceString; %#ok<AGROW>
                     end 
                 end
             end
        end
        if isvector(zdata) && (wsVars(j).size(1)==length(zdata) || (length(wsVars(j).size)==2 && ...
                wsVars(j).size(1)==1 && wsVars(j).size(2)==length(zdata)))
             if isempty(varData)
                 varData = evalin('caller',wsVars(j).name);
             end
             if isTypeSupported(varData) && ndims(varData)<=2
                 if isvector(varData)
                      if isequaln(varData(:),zdata(:))
                          zdataSourceString = wsVars(j).name;
                          zmatchingVarCount = zmatchingVarCount+1;
                          zdataSourceArray{zmatchingVarCount} = zdataSourceString; %#ok<AGROW>
                      end
                 else
                     formatStr = '%s(:,%d)';
                     I = find(all(varData-zdata(:)*ones(1,size(varData,2))==0));
                     if ~isempty(I)
                         zdataSourceString = sprintf(formatStr,wsVars(j).name,I(1));
                         zmatchingVarCount = zmatchingVarCount+1;
                         zdataSourceArray{zmatchingVarCount} = zdataSourceString; %#ok<AGROW>
                     end 
                 end
             end

        elseif ~isempty(zdata) && isequal(wsVars(j).size,size(zdata))
             if isempty(varData)
                 varData = evalin('caller',wsVars(j).name);
             end
             if isTypeSupported(varData)  && ndims(varData)<=2
                   if isequaln(varData,zdata)
                       zdataSourceString = wsVars(j).name;
                       zmatchingVarCount = zmatchingVarCount+1;
                       zdataSourceArray{zmatchingVarCount} = zdataSourceString; %#ok<AGROW>
                   end
             end
        end           
    end

    % Update the x/y data source if there is an unambiguous match
    displayName = '';

    
    if zmatchingVarCount==1
        set(ls(k),'ZDataSource_I',zdataSourceString);
        setappdata(double(ls(k)),'ZDataSourceOptions',zdataSourceArray);
        displayName = zdataSourceString;
    elseif zmatchingVarCount>1
        setappdata(double(ls(k)),'ZDataSourceOptions',zdataSourceArray);
        showSourceResolutionDlg = true;
    end
    if ymatchingVarCount==1
        set(ls(k),'YDataSource_I',ydataSourceString);
        setappdata(double(ls(k)),'YDataSourceOptions',ydataSourceArray);
        if ~isempty(displayName)
            displayName = [displayName ' vs. ' ydataSourceString];  %#ok<AGROW>
        else
            displayName = ydataSourceString;
        end      
    elseif ymatchingVarCount>1
        setappdata(double(ls(k)),'YDataSourceOptions',ydataSourceArray);
        showSourceResolutionDlg = true;
    end
    if xmatchingVarCount==1
        set(ls(k),'XDataSource_I',xdataSourceString);
        setappdata(double(ls(k)),'XDataSourceOptions',xdataSourceArray);
        if ~isempty(displayName)
            displayName = [displayName ' vs. ' xdataSourceString];  %#ok<AGROW>
        else
            displayName = xdataSourceString;
        end
    elseif xmatchingVarCount>1
        setappdata(double(ls(k)),'XDataSourceOptions',xdataSourceArray);
        showSourceResolutionDlg = true;
    end
    if ~isempty(displayName) && isempty(get(ls(k),'DisplayName'))
        set(ls(k),'DisplayName',displayName);
    end
end

% If there is no ambiguity, clear Data Source App Data since it will
% not be needed by the disambiguation dialog.
if ~showSourceResolutionDlg
    for k=1:length(ls)
        if isappdata(double(ls(k)),'XDataSourceOptions')
             rmappdata(double(ls(k)),'XDataSourceOptions');
        end
        if isappdata(double(ls(k)),'YDataSourceOptions')
             rmappdata(double(ls(k)),'YDataSourceOptions');
        end
        if isappdata(double(ls(k)),'ZDataSourceOptions')
             rmappdata(double(ls(k)),'ZDataSourceOptions');
        end
    end
end

% Objects with linked data sources must have their DataSourceFcn evaluated
% in order to build any internal state which depends on the current
% DataSource.
customLinkedObj = findall(fig,'-and','-not',{'Behavior',struct},'-function',...
   @localHasLinkedBehavior);

for k=1:length(customLinkedObj)
    try
        linkBehavior = hggetbehavior(customLinkedObj(k),'linked');
        datalen = sum([linkBehavior.UsesXDataSource linkBehavior.UsesYDataSource linkBehavior.UsesZDataSource]);
        data = cell(1,datalen);
        count = 1;
        if linkBehavior.UsesXDataSource
            data{count} = evalin('caller',linkBehavior.XDataSource);
            count = count+1;
        end 
        if linkBehavior.UsesYDataSource
            data{count} = evalin('caller',linkBehavior.YDataSource);
            count = count+1;
        end 
        if linkBehavior.UsesZDataSource
            data{count} = evalin('caller',linkBehavior.ZDataSource);
        end
    catch me
        % If the linked behavior DrawFcn fails (e.g  attempting to link a
        % histogram for a non-vector matrix), abort the linking operation.
        errordlg(me.message, 'MATLAB', 'modal');
        linkdata('off')
        return
    end
end

% If there are ambiguous matches give the user a chance to resolve them
if showSourceResolutionDlg
    datamanager.sourceDialogBuilder(handle(fig),'build',...
        {@localCompleteLinking h fig wsVars},{@localCompleteLinking h fig wsVars});
    return
end

[mfile,fcnname] = datamanager.getWorkspace(1);
localCompleteLinking(h,fig,wsVars,mfile,fcnname);


function result = isTypeSupported(varData)
result =  isnumeric(varData) || isdatetime(varData) || iscalendarduration(varData);
    


function localCompleteLinking(h,fig,whoStruc,mfile,fcnname)

fig.LinkPlot = true;

% Register live plot if valid graphics are found
if nargin<=3
    [mfile,fcnname] = datamanager.getWorkspace(1);
end

h.addFigure(handle(fig),mfile,fcnname);

% Synchronize the toolbar button
localSetFigureState(fig,'on');

% Update brushing manager in case some newly linked variables are not
% initialized. This meets the requirement that all linked variables
% have a brushing manager entry.
brushManager = datamanager.brushmanager;
brushManager.updateVars(whoStruc,mfile,fcnname);

liveplotbtn = uigettool(fig,'DataManager.Linking');
if ~isempty(liveplotbtn) && ~isempty(getappdata(liveplotbtn,'cursorCacheData'))
     set(double(fig),'Pointer',getappdata(liveplotbtn,'cursorCacheData'));
     setappdata(liveplotbtn,'cursorCacheData',[])
end

function linkState = locSetNewBooleanState(f,state)

if ~ischar(state)
    error(message('MATLAB:linkdata:InvalidState'));
end

% Add LinkPlot property
if isempty(f.findprop('LinkPlot'))
    p = addprop(f,'LinkPlot');
    p.Transient = true;
    % Need to initialize the new LinkPlot property since it is untyped.
    f.LinkPlot = false;
end
switch state
    case 'on'
        boolState = true;
    case 'off'
        boolState = false;
    case 'toggle'
        boolState = ~get(f,'LinkPlot');
    otherwise
        error(message('MATLAB:linkdata:InvalidState'));
end

if ~boolState
    datamanager.clearUndoRedo('include',f);
    linkState = matlab.graphics.internal.LinkData('off');
else
    linkState = matlab.graphics.internal.LinkData('on');
end



function matchingCols = localCompareCols(X,Y)

% Find equal columns with equal NaNs among two matrices 
matchingCols = false(1,size(X,2));
for col=1:size(X,2)
    matchingCols(col) = isequaln(X(:,col),Y(:,col));
end
matchingCols = find(matchingCols);

function localSetFigureState(fig,state)
if strcmp(fig.InPrint, 'off')
   % enable/disable print callback 
   localAdjustPrintCallback(fig, state);
end

liveplotbtn = uigettool(fig,'DataManager.Linking');
if ~isempty(liveplotbtn)
    set(liveplotbtn,'State',state,'Enable','on')
end
liveplotmenu = findall(fig,'tag','figLinked');
if ~isempty(liveplotmenu)
    set(liveplotmenu,'Checked',state);
end

function state = localHasLinkedBehavior(h)

state = false;
bobj = hggetbehavior(h,'linked','-peek');
if isempty(bobj)
   return
end
state = islinked(bobj);

function state = localHasDisabledLinkedBehavior(h)

state = false;
b = hggetbehavior(h,'linked','-peek');
if isempty(b)
    return
end
state = ~b.Enable;

function localAdjustPrintCallback(fig, state)
    % if enabling linkdata, setup print callback to hide link bar 
    % when generating output
    bh = hggetbehavior(fig, 'Print');
    if strcmp(state, 'on')
       set(bh, 'PrePrintCallback', @linkdataPrintCallback);
       set(bh, 'PostPrintCallback', @linkdataPrintCallback);
    else
       set(bh, 'PrePrintCallback', []);
       set(bh, 'PostPrintCallback', []);
    end

function linkdataPrintCallback(H, callbackName)
   if strcmpi('PrePrintCallback', callbackName) 
        com.mathworks.page.datamgr.linkedplots.LinkPlotPanel.setUseAnimation(false)
        linkdata(H, 'off') 
        drawnow        
   else
      linkdata(H, 'on') 
      drawnow 
      com.mathworks.page.datamgr.linkedplots.LinkPlotPanel.setUseAnimation(true)
   end