www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+mbcmodelview/+global/MessageService.m

    classdef MessageService < mbcmodelview.ModelMessageService
    %MessageService one-stage and response feature MessageService
    
    %  Copyright 2015-2015 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (SetAccess=private)
        %CurrentNode selected node in model tree
        CurrentNode
    end
    properties(Dependent,SetAccess=private)
        %Title standard title is the name of the response
        Title
        %NumChildren number of children
        NumChildren        
        CurrentIndex
    end    
    
    
    methods
        function obj = MessageService
        %MessageService constructor
        
        % create an OutlierLine for sharing among users
        obj@mbcmodelview.ModelMessageService
        % create actions for model
        obj.Actions = mbcmodelview.global.NodeActions(obj);
        % right click on main line for a plot of sweep data in response
        % feature model plots
        obj.OutlierLine.AltClickCallBack = @obj.onPlotSweep;

        end
        
        function s = get.Title(obj)
        s = varname(obj.Model);
        end
        
        function n = get.NumChildren(obj)
        n = numChildren(info(obj.CurrentNode));
        end        
        
        function Index = get.CurrentIndex(obj)
        Index = find(obj.Pointer==children(info(obj.CurrentNode)));
        end
    end
    
    methods
        
        function updateNode(obj,p,pCurrent,ForceReset)
        %updateNode update selected node in MessageService
        %   updateNode(obj,p,pCurrent,ForceReset)
        %     p : main node (parent of alternatives, or tree node)
        %     pCurrent : main node (selected alternative)
        
        
        if nargin<2
            p=obj.Pointer;
        end
        if nargin>2
           obj.CurrentNode = pCurrent; 
        end
        
        if nargin<4
            ForceReset = false;
        end
        
        NodeChanged = ForceReset || p~=obj.Pointer;
        
        p.InitModel;
        obj.Pointer = p;
        if isempty(obj.CurrentNode)
           obj.CurrentNode = p; 
        end                
        update(obj,NodeChanged)
        if NodeChanged
            fireNodeChanged(obj)
        end
        end
        
        function update(obj,NodeReset)
        %update main update method for MessageService
        %  update(obj,NodeChanged)
        
        if nargin<2
            NodeReset = false;
        end
        
        % store fit data
        mdev = info(obj.Pointer);
        [obj.XData,obj.YData,obj.DataOK]= FitData(mdev);
        
        obj.Model = model(mdev);
        % store boundary model
        obj.BoundaryModel = BoundaryModel(mdevtestplan(obj.ModelDev),obj.Model); 
        
        % validation data store
        if isRespFeat(mdev);
            % no validation data for response feature nodes
            XValData = [];
            YValData = [];
        else
            [XValData,YValData]= getValidationData(mdev);
        end
        obj.ValidationXData= XValData;
        obj.ValidationYData = YValData;

        % store diagnostics statistics
        [obj.Diagnostics,obj.DiagnosticFactors,olIndex] = diagnosticStats(obj);

        % clear outlierlines and update with new default outliers
        clear(obj.OutlierLine);
        obj.OutlierLine.OutlierIndices = olIndex;
        % enable actions
        enable(obj.Actions);
        % send appropriate events
        if NodeReset 
            fireNodeReset(obj)
        end
        fireNodeUpdated(obj)
        end
        
        function setupModel(obj,NewModel)
        %setupModel setup new model
        
        mdev = obj.ModelDev;
        try
            OldModel = obj.Model;
            OldName = name(OldModel);
            if  any(  strncmp( OldName,name( mdev ),length(OldName) ) ) &&  ~strcmp(name(NewModel),OldName)
                % using default model and node used model name so rename
                mdev = name(mdev,name(NewModel));
            end
            %set new model and fit
            mdev = model(mdev,NewModel);
            fitmodel(mdev);
            % update everything, and fire node changed to broadcast that
            % model has changed
            update(obj)
            fireNodeChanged(obj)
        catch ME
            xregerror('Model Fit Error',ME.message);
            xregpointer(mdev);
        end
        
        end
        
        function refit(ms)
        %refit refit model
        
        refit(ms.ModelDev);
        update(ms);
        end
        
        function [mainString,shortString]= transformStrings(obj)
        %transformStrings strings to display transform at in desciptor
        %    [mainString,shortString]= transformStrings(obj)
        
        bxcx=get(obj.Model,'boxcox');
        if bxcx~=1
            mainString = sprintf('Box-Cox = %g', bxcx);
            shortString = sprintf('%g', bxcx);
        else
            mainString = '';
            shortString = '';
        end
        
        end

        function restoreOutliers(obj,olindex)
        %restoreOutliers restore removed data
        
        if nargin<2
            [olindex,OK]=restoreoutlierdlg(obj.ModelDev);
            OK = OK && ~isempty(olindex);
        else
            OK = ~isempty(olindex);
        end        
        
        if OK
            restoreoutliers(obj.ModelDev,'single',olindex);
            % only a view required if status is the same
            update(obj)
        end

        end
        
        function addOutliers(obj,olindex)
        %addOutliers add new outliers
        
        % Apply the outliers
        addoutliers(obj.ModelDev,olindex);

        % only a view required if status is the same
        update(obj)
        
        end
        
        function [data,factors] = validationDiagnostics(ms)
        %validationDiagnostics validation diagnostics for ValidationData view
        
        if isempty(ms.ValidationXData)
            factors = {};
            data = [];
        else
            % get new stats
            yhat = ms.Model(ms.ValidationXData);
            
            data = [(1:length(yhat))' double(ms.ValidationYData)-yhat yhat double(ms.ValidationYData) double(ms.ValidationXData) ];
            
            inputNames = InputLabels(ms.Model);
            outputName = ResponseLabel(ms.Model);
            % make it a row
            inputNames= inputNames(:)';
            
            output= getOutput(ms.Model);
            if ~isempty(output.Units)
                % add units to residuals
                units = sprintf(' [%s]',output.Units);
            else
                units = '';
            end
            factors=[{'Obs. number',...
                ['Residuals',units],...
                ['Predicted ',outputName],...
                outputName},...
                inputNames];
        end
        
        end
        
        function [data,factors,olIndex]= diagnosticStats(obj)
        %diagnosticStats scatterplot diagnostics and default outliers
        %    [data,factors,olIndex]= diagnosticStats(obj)
        
        [data,factors,~,olIndex]= diagnosticStats(obj.ModelDev);
        
        end
        
        function showTestNumbers(obj,ax)
        %showTestNumbers show test numbers in axes
        %    showTestNumbers(obj,ax)
        
        % delete any current test numbers
        txtH=findobj(ax,'Type','text',...
            'Tag','TestNumText');
        delete(txtH);
        if obj.ShowTestNumbers && obj.Status
            ShowTestNum(obj.ModelDev,ax);
        end
        end
        
        function [lineh,legLabels] = legendLabels(obj,AxHand)
        %legendLabels legend labels for axes
        
        tags = {'main line','BDPts','localfit','free knot line','rbf center mark','valdata'};
        
        Types = InputFactorTypes(obj.Model);
        if length(find(Types==1)) > 1
            % global model has >1 input factors
            allLabels = {'Data','Removed data','Predicted = Observed','Knot position','RBF center','Validation predictions'};
        else
            % global model has only 1 input and we show the model fit
            allLabels = {'Data','Removed data','Model fit','Knot position','RBF center','Validation predictions'};
        end
        
        % Throw out empty lines
        lineh = []; legLabels = {};
        for i = 1:length(tags)
            h = findobj(AxHand,'Type','line','Tag',tags{i});
            if ~isempty(h) && isgraphics(h) && ~isempty(get(h,'XData'))
                lineh = [lineh, h]; %#ok<AGROW>
                legLabels = [legLabels, allLabels(i)]; %#ok<AGROW>
            end
        end
        end
        
        function buildModels(obj)
        %buildmodels build models works on tree node not selected
        %alternative
        OK = buildmodels(info(obj.CurrentNode));
        if OK
            % select the new best model and update
            obj.Pointer = bestmdev(obj.ModelDev);
            update(obj);
            % broadcast that model has changed
            fireNodeChanged(obj)
        end
        end        
        
        function assignBest(obj)
        %assignBest assign node to best
        if obj.Status
            p= obj.CurrentNode;
            p.BestModel(obj.Pointer);
            update(obj);
        end
        end
        
        function selectAlternative(obj,Index,AssignBest)
        %selectAlternative select alternative model
        
        if ~isempty(Index)
            mdev = info(obj.CurrentNode);
            NewNode = children(mdev,Index);
            
            if nargin>2 && AssignBest && obj.Status
                % set best model
                p = obj.CurrentNode;
                p.BestModel(NewNode);
            end
            
            if NewNode~=obj.Pointer && closeSubFigures(obj)
                % may need to close sub figures
                
                % need to change selection
                mdev=info(NewNode);
                % model must be initialised
                InitModel(mdev);
                mdev= info(mdev);
                
                % model fit has been deferred - can we refit now
                [Deferred,~,CanUpdate]=isDeferred(mdev);
                if Deferred && CanUpdate
                    % refit model
                    refit(mdev);
                end
                
                % make sure new node is selected in list
                obj.Pointer = NewNode;
                update(obj);
                fireNodeChanged(obj)
            else
                % just update
                update(obj)
            end
            
        end
        end
        
        
        function [Data,Icons,ColHead] = childstats(ms)
        %childstats statistics for listview
        %    [Data,Icons,ColHead] = childstats(ms)
        
        mdev = info(ms.CurrentNode);
        if numChildren(mdev)>0 && ~isa(mdev,'mdevmlerf')
            [s,ColHead]= childstats(mdev);
            ColHead = [{'Name'},ColHead, {'Best Model'}];
            Icons = children(mdev,@iconfile)';
            Data = [ children(mdev,@name)' num2cell(s) num2cell(children(mdev)==bestmdev(mdev))' ];
        else
           Data = [];
           Icons = {};
           ColHead = {};
        end
        
        end
        
        function [description,ic] = listHeader(ms) %#ok<MANU>
        %listHeader header for lisview
        %    [description,ic] = listHeader(ms)
        
        ic = 'gloreg.bmp';
        description = 'Alternative Models';
        
        end
        
        function plotSweep(obj,XGlobal,YObserved,DataIndex)
        %plotSweep plot sweep data for response feature
        
        m= obj.Model;
        yhat= EvalModel(m,XGlobal);
        
        plocal= obj.Pointer.Parent;
        while plocal~=0 && ~isa(plocal.model,'localmod')
            % find local modeldev node
            plocal= plocal.Parent;
        end
        
        if plocal==0
            return
        end
        
        presp= plocal.Parent;
        
        [XData,YData,DataOK]= plocal.FitData(DataIndex);
        XG= obj.XData;
        YData(~DataOK,1)= NaN;
        Xg = XG{DataIndex};
        Xgc= code(m,Xg);
        fh= figure('NumberTitle','off',...
            'Name',fullname(obj.ModelDev),...
            'Tag','DisplayPlots');
        ax= axes('Parent',fh);
        
        plot(XData(:,1),YData,'o','bd','Parent',ax);
        
        set(get(ax,'Title'),...
            'String',['Test ',sprintf('%3d',testnum(XData))],...
            'FontWeight','Bold')
        set(get(ax,'YLabel'),...
            'Interpreter','none',...
            'String',presp.name);
        
        % Display Experimental Point (Natural and Code values)
        dispstr= [char(get(m,'symbol')) blanks(size(XG,2))' num2str(Xg','%10.4g')...
            blanks(size(XG,2))' num2str(Xgc','%5.2f')];
        str1=num2str(YObserved,'%7.3f');
        str2=num2str(yhat,'%5.3f');
        strn=char(str1,str2);
        s1=['Observed  : ';'Predicted : '];
        dispstr=char([s1,strn],'',dispstr);
        th=text('Parent',ax,...
            'Units','norm','Position',[0.95,0.02],...
            'String',dispstr,....
            'FontName','Courier New',...
            'FontSize',9,...
            'Interpreter','none',...
            'HorizontalAlignment','right','VerticalAlignment','bottom');
        tpos= get(th,'Extent');
        
        Note= plocal.SweepNotes(DataIndex);
        lineLength = 30;
        if ~isempty(Note)
            % add sweep note if appropriate
            if size(Note,1)==1 && length(Note)>lineLength  
                % note is one long line
                Note = [Note, blanks(lineLength-rem(length(Note),lineLength))];
                Note = reshape(Note,lineLength,length(Note)/lineLength);
                Note=Note';
            end
            text('Parent',ax,...
                'Units','norm','Position',[0.95,0.04+tpos(4)],...
                'String',Note,....
                'FontName','Courier New',...
                'FontSize',9,...
                'Interpreter','none',...
                'HorizontalAlignment','right','VerticalAlignment','bottom');
        end
        
        end
        
        function msg = selectModelFigure(obj)
        %selectModelFigure
        
        p= obj.CurrentNode;
        
        pbest= children(info(p),@bestmdev);
        pbest=[pbest{:}];
        if any(pbest==0)
            unvalmdev=children(info(p),find(pbest==0),@name);
            msg = char('You must select a best model for all sub-models ',...
                'before selecting a best model. ',...
                'The following sub-models do not have a best model:',...
                unvalmdev{:});
        else
            % dependence on Model Browser
            hFig= get(MBrowser,'Figure');
            hSelectionFig= Validate_OneStage('create',p,hFig);
            if isgraphics(hSelectionFig)
                % register figure with message service
                % need to update when done
                list = event.listener(hSelectionFig,'ObjectBeingDestroyed',@(h,evt) obj.update);
                setappdata(hSelectionFig,'MBCSelectionClosed',list)
                
                obj.registerSubFigure(hSelectionFig);
            end

            msg = '';
        end

        end

    end
    
    methods (Access=private)
        function onPlotSweep(obj,hLine,~)
        %onPlotSweep right click callback to plot sweep 
        
        ax= get(hLine,'Parent');

        % find the point in the line that we have clicked on.
        pos=get(ax,'CurrentPoint');
        pos=pos(1,1:2);
        xdata=get(hLine,'XData');
        ydata=get(hLine,'YData');
        metric=((xdata-pos(1))./diff(get(ax,'XLim'))).^2 + ...
            ((ydata-pos(2))./diff(get(ax,'YLim'))).^2;
        [~,SelectedPoint]=min(metric);
        if ~isempty(SelectedPoint)
            % find index to data point
            indices = find(obj.DataOK);
            DataIndex = indices(SelectedPoint);
            % observed y data
            yobs= double(obj.YData(obj.DataOK));
            yobs= yobs(DataIndex);
            % predicted y
            x=double(obj.XData);
            xp= x(obj.DataOK,:);
            xp= xp(DataIndex,:);
            % plot sweep
            plotSweep(obj,xp,yobs,DataIndex);
        end
        end
    end
    
end