www.gusucode.com > mbcview 工具箱matlab源码程序 > mbcview/+cageview/+optimoutput/Values2dView.m
classdef Values2dView < mbcgui.multiview.View %cageview.optimoutput.Values2dView class % cageview.optimoutput.Values2dView extends mbcgui.multiview.View. % % cageview.optimoutput.Values2dView properties: % Parent - Property is of type 'MATLAB array' % Position - Property is of type 'rect' % Enable - Property is of type 'on/off' % Visible - Property is of type 'on/off' % UserData - Property is of type 'MATLAB array' % Tag - Property is of type 'string' % MessageService - Property is of type 'handle' % Options - Property is of type 'handle vector' % Actions - Property is of type 'handle vector' % UIContextMenu - Property is of type 'MATLAB array' % DisplayData - Property is of type 'ustring' % CanRotate - Property is of type 'bool' % % cageview.optimoutput.Values2dView methods: % createDefaultWindowContainer - Create an appropriate container for the view % gettitle - Return string to use as title for view % setDisplayFilter - Set the display filter % Copyright 2007-2015 The MathWorks, Inc. properties (AbortSet, SetObservable) %DISPLAYDATA Property is of type 'ustring' DisplayData = 'All'; %CANROTATE Property is of type 'bool' CanRotate = true; end properties (Access=protected, AbortSet) %OUTPUTVALUES Property is of type 'MATLAB array' OutputValues = struct( 'Data', [ ], 'bRedIdx', [ ], 'bOrangeIdx', [ ], 'bGreenIdx', [ ] ); %HSELECTOR Property is of type 'handle' hSelector = []; %HREDLINE Property is of type 'MATLAB array' hRedLine = []; %HORANGELINE Property is of type 'MATLAB array' hOrangeLine = []; %HGREENLINE Property is of type 'MATLAB array' hGreenLine = []; %HCURRENTPOINT Property is of type 'MATLAB array' hCurrentPoint = []; %HTEXT Property is of type 'MATLAB array' hText = []; %VIEWACTION Property is of type 'handle' ViewAction = []; end methods % constructor block function obj = Values2dView(varargin) %Values2dView Constructor for Values2dView % OBJ = Values2dView(PROP, VALUE) constructs a class that % displays the results of an optimization on a 3-d plot. % % Subclasses can additionally display extrapolations or fits through the % optimization results. % Call the inherited constructor obj@mbcgui.multiview.View(varargin{ : }); % converted super class constructor call % Create the factor selector object. This creates the axes. SC = xregGui.SystemColorsDbl; obj.hSelector = mbcwidgets.factorselector3d( ... 'Parent',obj.Parent, ... 'Visible', obj.Visible, ... 'BackgroundColor', SC.CTRL_BG, ... 'SelectionType', 'exclusive', ... 'HasAxes', true, ... 'UIContextMenu',obj.UIContextMenu,... 'FactorChangeCallback', {@i_inputschanged, obj}); % Set initial axes properties. set(obj.hSelector.Axes, 'Color', 'w', 'Box', 'on', ... 'XGrid', 'on', 'YGrid', 'on','ZGrid','on', ... 'ButtonDownFcn', @obj.axesClick); view(obj.hSelector.Axes, 3); % Deal with rotation % Create the lines for the solution points obj.hRedLine = line('Parent', obj.hSelector.Axes,... 'Tag', 'RedLine',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 'o', ... 'MarkerSize', 8, ... 'MarkerFaceColor', 'r', ... 'MarkerEdgeColor', 'k', ... 'Color', 'r', ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_redLineButtonDown, obj, false}); obj.hRedLine(2) = line('Parent', obj.hSelector.Axes,... 'Tag', 'RedLine_Accepted',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 'p', ... 'MarkerSize', 14, ... 'MarkerFaceColor', 'r', ... 'MarkerEdgeColor', 'k', ... 'Color', 'r', ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_redLineButtonDown, obj, true}); cOrange = [1 0.69 0.39]; obj.hOrangeLine = line('Parent', obj.hSelector.Axes,... 'Tag', 'OrangeLine',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', '^', ... 'MarkerSize', 10, ... 'MarkerFaceColor', cOrange, ... 'MarkerEdgeColor', 'k', ... 'Color', cOrange, ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_orangeLineButtonDown, obj, false}); obj.hOrangeLine(2) = line('Parent', obj.hSelector.Axes,... 'Tag', 'OrangeLine_Accepted',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 'p', ... 'MarkerSize', 14, ... 'MarkerFaceColor', cOrange, ... 'MarkerEdgeColor', 'k', ... 'Color', cOrange, ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_orangeLineButtonDown, obj, true}); obj.hGreenLine = line('Parent', obj.hSelector.Axes,... 'Tag', 'GreenLine',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 's', ... 'MarkerSize', 10, ... 'MarkerFaceColor', 'g', ... 'MarkerEdgeColor', 'k', ... 'Color', 'g', ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_greenLineButtonDown, obj, false}); obj.hGreenLine(2) = line('Parent', obj.hSelector.Axes,... 'Tag', 'GreenLine_NotAccepted',... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 'p', ... 'MarkerSize', 14, ... 'MarkerFaceColor', 'g', ... 'MarkerEdgeColor', 'k', ... 'Color', 'g', ... 'XData', [],... 'YData', [],... 'ZData', [],... 'ButtonDownFcn', {@i_greenLineButtonDown, obj, true}); % Current point obj.hCurrentPoint = line('Parent', obj.hSelector.Axes,... 'Visible',get(obj.hSelector.Axes, 'Visible'),... 'LineStyle', 'none', ... 'Marker', 'o', ... 'MarkerSize', 16, ... 'MarkerEdgeColor', 'k', ... 'MarkerFaceColor', 'w', ... 'LineWidth', 2.5, ... 'Color', 'w', ... 'XData', [],... 'YData', [],... 'ZData', [], ... 'Tag', 'CurrentPoint'); uistack(obj.hCurrentPoint, 'bottom'); % "No display" text obj.hText = text('Parent', obj.hSelector.Axes, ... 'Position', [.5 .5 .5], ... 'HorizontalAlignment', 'center', ... 'VerticalAlignment', 'middle', ... 'Clipping', 'on', ... 'Visible', 'off'); % Layout L = xreggridbaglayout(obj.Parent, ... 'Dimension', [1 1], ... 'position', obj.Position, ... 'elements', {obj.hSelector}); obj.ContentHandle = L; createActions(obj); % Hook up to the message service if it exists if ~isempty(obj.MessageService) obj.pPostSetMessageService; end end % Values2dView end % constructor block methods function set.DisplayData(obj,value) obj.DisplayData = i_setDisplayData(obj,value); end end % set and get functions methods % public methods %---------------------------------------- function hPane = createDefaultWindowContainer(obj,varargin) %CREATEDEFAULTWINDOWCONTAINER Create an appropriate container for the view % HCONAINER = CREATEDEFAULTWINDOWCONTAINER(OBJ) creates and returns a % handle to a ViewContainer that has been set up to contain OBJ. The % container should be appropriate for viewing OBJ in a standard % application window. The default implementation creates a % PanelTitleViewContainer. % Call the super class implementation hPane = createDefaultWindowContainer@mbcgui.multiview.View(obj,varargin{:}); % Ensure the background color is the window background SC = xregGui.SystemColorsDbl; hPane.BackgroundColor = SC.CTRL_BG; end % createDefaultWindowContainer %---------------------------------------- function str = gettitle(obj) %#ok<MANU> %GETTITLE Return string to use as title for view % STR = GETTITLE(OBJ) returns a string that should be used as a title for % the container the view sits in. str = 'Results 2d View'; end % gettitle %---------------------------------------- function setDisplayFilter(obj, DisplayData) %SETDISPLAYFILTER Set the display filter % OUT = SETDISPLAYFILTER(OBJ) sets the filter that is used to remove % points from the display. set(obj.ViewAction.Actions(1).Actions, 'Selected', false); obj.DisplayData = DisplayData; obj.pRefresh; obj.pRefreshCurrentPoint; DisplayActions = obj.ViewAction.Actions(1).Actions; switch obj.DisplayData case 'Acceptable' DisplayActions(2).Selected = true; case 'Green' DisplayActions(3).Selected = true; case 'Orange' DisplayActions(4).Selected = true; case 'Red' DisplayActions(5).Selected = true; otherwise DisplayActions(1).Selected = true; end end % setDisplayFilter end % public methods methods (Access=protected) %---------------------------------------- function ExportAx = pCopyLinesToPrintAxes(obj, ExportAx) %PCOPYLINESTOPRINTAXES Copy lines to the supplied printable axes % EXPORTAX = PCOPYLINESTOPRINTAXES(OBJ, EXPORTAX) copies the lines % containing the optimization results to the supplied printable axes. Any % button down functions on the lines are removed. % Get all the lines in the 2-d view lines = [obj.hCurrentPoint; obj.hRedLine(:); obj.hOrangeLine(:); ... obj.hGreenLine(:)]; % Set the buttondownfcns on the lines to be empty set(lines, 'ButtonDownFcn', ''); % Copy the visible optimization results to the new axes. newLines = xregGui.HGPlotCopy(lines, ExportAx); % Place the current point at the bottom of the uistack, so other lines are % plotted over it. if ~isempty(newLines) uistack(newLines(1), 'bottom'); end end % pCopyLinesToPrintAxes %---------------------------------------- function ExportAx = pCreatePrintableAxes(obj, fig, AxCopyProps) %PCREATEPRINTABLEAXES Create a printable copy of the axes % EXPORTAX = PCREATEPRINTABLEAXES(OBJ, FIG, AXCOPYPROPS) creates a % printable copy of the axes. The specified axes properties are copied % from OBJ to EXPORTAX. % Create new axes and position them in the standard location ExportAx = axes('Parent', fig, 'Units', 'Pixels'); % Copy settings from the view axes to the export ones AxCopyPropData = get(obj.pGetSelector.Axes, AxCopyProps); set(ExportAx, AxCopyProps, AxCopyPropData); end % pCreatePrintableAxes %---------------------------------------- function idxNearestPoint = pFindNearestPoint(obj, lineColor, acceptChanged) %PFINDNEARESTPOINT Find the nearest point to mouse click % OUT = PFINDNEARESTPOINT(OBJ, LINECOLOR, ACCEPTCHANGED) finds the index % amongst all the displayed points of the point nearest to the mouse % click. % Get the selected indices idxX = obj.hSelector.XFactor; idxY = obj.hSelector.YFactor; idxZ = obj.hSelector.ZFactor; % Get the current optimization output data [data, bRedIdx, bOrangeIdx, bGreenIdx] = pGetOutputData(obj); bAcceptableIdx = pGetUserOutputData(obj); data = pTransformDataForPoints(obj, data); % Retrieve display data for the line that has been clicked % Indices into red/orange/green lines switch lineColor case 'red' bIdx = bRedIdx; if acceptChanged bIdx(~bAcceptableIdx) = false; else bIdx(bAcceptableIdx) = false; end case 'orange' bIdx = bOrangeIdx; if acceptChanged bIdx(~bAcceptableIdx) = false; else bIdx(bAcceptableIdx) = false; end case 'green' bIdx = bGreenIdx; if acceptChanged bIdx(bAcceptableIdx) = false; else bIdx(~bAcceptableIdx) = false; end otherwise error(message('mbc:Values2dView:InvalidState')); end if strcmpi(obj.DisplayData, 'Acceptable') bIdx = bIdx & bAcceptableIdx; end xdata = data(bIdx, idxX); ydata = data(bIdx, idxY); zdata = data(bIdx, idxZ); % Current point ax = obj.hSelector.Axes; cp = get(ax, 'CurrentPoint'); % Scale current point and line data onto [0, 1] [xdata, ydata, zdata, cp] = i_scaleData(ax, xdata, ydata, zdata, cp); xb = cp(1, :); xf = cp(2, :); % Minimum distance between the points and the current point vector nPts = size(xdata, 1); vecToBackPoint = bsxfun(@minus, xb, [xdata,ydata,zdata]); cursorLine = repmat(xf - xb, nPts, 1); crossProd = cross(cursorLine, vecToBackPoint, 2); dmin = sqrt(dot(crossProd, crossProd, 2))/norm(xf-xb); % Minimum of the minimum distances [~, ptidx] = min(dmin); % Index is obtained into the filtered data. Need find the index in the raw % data. Note we are assuming that the line is visible here, i.e. at % least one element of bIdx is true. idxVisible = find(bIdx); idxNearestPoint = idxVisible(ptidx); end % pFindNearestPoint %---------------------------------------- function [Data, bRedIdx, bOrangeIdx, bGreenIdx] = pGetOutputData(obj) %PGETOUTPUTDATA Return the table data. % [DATA, BREDIDX, BORANGEIDX, BGREENIDX, BACCEPTABLEIDX] = % PGETOUTPUTDATA(OBJ) returns data for the 2-d view as a NPTS-by-NFACS % matrix. NPTS will be displayed in the view and the user will be able to % choose from one of NFACS factors. NPTS-by-1 boolean vectors are returned % to indicate whether a point has a negative exit flag (BREDIDX), zero % exit flag (BORANGEIDX) or a positive exit flag (BGREENIDX). % Initialisation Data = []; bRedIdx = []; bOrangeIdx = []; bGreenIdx = []; if obj.hasData % Retrieve optimization results from the cache Data = obj.OutputValues.Data; bRedIdx = obj.OutputValues.bRedIdx; bOrangeIdx = obj.OutputValues.bOrangeIdx; bGreenIdx = obj.OutputValues.bGreenIdx; end end % pGetOutputData %---------------------------------------- function len = pGetQuantityLength(obj) %PGETQUANTITYLENGTH Return the quantity length in the output % % LEN = PGETQUANTITYLENGTH(OBJ) returns the length of a quantity in the % output. This is defined to be the maximum length of the fixed/free % variables. if obj.hasData MS = obj.MessageService; out = MS.getOptimOutput; len = max([getNumFixedVariables(out), getNumFreeVariables(out)]); else len = 0; end end % pGetQuantityLength %---------------------------------------- function hSelector = pGetSelector(obj) %PGETSELECTOR Return axes selector % OUT = PGETSELECTOR(OBJ) returns OBJ.HSELECTOR. This method is not % intended for public consumption. hSelector = obj.hSelector; end % pGetSelector %---------------------------------------- function [bAcceptableIdx, CurrentIdx] = pGetUserOutputData(obj) %PGETUSEROUTPUTDATA Return the user changeable data. % [BACCEPTABLEIDX, CURRENTIDX] = PGETUSEROUTPUTDATA(OBJ) returns the % output data for the 2-d view that can be edited by the user. A NPTS-by-1 % boolean vector is returned to indicate the acceptibility of each point % and the index of the current point is returned as a double. % Initialisation bAcceptableIdx = []; CurrentIdx = []; if obj.hasData % Get the accceptable status for each point and determine the current % point out = obj.MessageService.getOptimOutput; RunIdx = obj.MessageService.getFocusRun; SolIdx = obj.MessageService.getFocusSolution; FocusPtIdx = obj.MessageService.getFocusPoint; nRunOptim = getNumRuns(out); if strcmp(obj.MessageService.CurrentSliceDirection, 'solution') % Display all runs at focussed solution selection if SolIdx>0 % Get acceptable indices bAcceptableIdx = isAcceptable(out, 1:nRunOptim, SolIdx)'; % Set current point index CurrentRunSolIdx = RunIdx; end elseif strcmp(obj.MessageService.CurrentSliceDirection, 'pareto') % Display all solutions at focussed run selection if RunIdx>0 % Get acceptable indices nSolOptim = getNumSolutions(out); bAcceptableIdx = isAcceptable(out, RunIdx, 1:nSolOptim); % Set current point index CurrentRunSolIdx = SolIdx; end elseif strcmp(obj.MessageService.CurrentSliceDirection, 'selectedsolution') % Display selected solution for each run if hasSelectedSolution(out) % Get acceptable indices bAcceptableIdx = isAcceptable(out, 1:nRunOptim, -1)'; % Set current point index CurrentRunSolIdx = RunIdx; end else % This object does not plot any data for the weighted solution % view. It will display a message instead - this is dealt with in % pCheckOutputData end if ~isempty(obj.OutputValues.Data) % At this point, the exit flag and acceptable indices are row % vectors, each element determining the status of each run/solution % in the data matrix. We need to repmat these vectors so that each % element of a solution has an exit flag and acceptable index % associated with it. maxLen = pGetQuantityLength(obj); bAcceptableIdx = repmat(bAcceptableIdx, maxLen, 1); bAcceptableIdx = bAcceptableIdx(:); % Return the index of the current point (not solution or run) % selected in the table if FocusPtIdx > maxLen % The current selected point does not have a free/fixed % variable associated with it. CurrentIdx = []; else CurrentIdx = maxLen*(CurrentRunSolIdx - 1) + FocusPtIdx; end end end end % pGetUserOutputData %---------------------------------------- function [nms, bIdx, defIdx] = pGetValidItems(obj) %PGETVALIDITEMS Returns the optimization items that can be plotted % [NMS, BIDX, DEFIDX] = PGETVALIDITEMS(OBJ) returns a cell array of the % items in the optimization results that can be plotted. A boolean index % is returned such that NMS = ALLNAMES(BIDX), where ALLNAMES is a list of % the column names returned from the output object with the % 'OutputContents' option set to 'cell' and 'OutputContents' set to % OutputContents = {'FixedVars', 'FreeVars', 'Objectives'}. DEFIDX % denotes the default X, Y and Z factors. This is a 1-by-3 index vector % into NMS, or empty if the number of factors is less than 3. if ~obj.hasData ... || strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') ... || ~obj.MessageService.hasFocusIndex nms = {}; bIdx = []; defIdx = []; else MS = obj.MessageService; out = MS.getOptimOutput; % Find the maximum length of the fixed and free variables maxLen = pGetQuantityLength(obj); % Eliminate the optimization results that do not have length either 1 % or maxLen. Base this test on the first solution in the optimization % results - it should exist for all optimizations. nms = getColumnNames(out, 'OutputFormat', 'cell', ... 'OutputContents', pOutputContents(obj)); lenSolData = [getNumFixedVariables(out), getNumFreeVariables(out), ... getNumObjectives(out)]; bIdx = (lenSolData == 1) | (lenSolData == maxLen); nms = nms(bIdx); if nargout > 2 % Return the default X, Y and Z factors. If possible, try to set the % first two fixed variables *that are not obj/con weights* as the X and % Y axis factor defaults. The first free variable is selected as % the Z-axis factor default. nFree = length(getNumFreeVariables(out)); [~, fixedNames] = getSolution(out, 1, 'OutputFormat', 'cell', ... 'OutputContents', 'FixedVars'); nFixed = length(fixedNames); cellIsWeight = regexp(fixedNames, '_weights'); idxFixedNotWeight = find(cellfun('isempty', cellIsWeight)); if length(nms) < 3 % Do not set a default if there are fewer than three valid items. defIdx = []; elseif length(idxFixedNotWeight) > 1 % More than one fixed variable that is not a weight. Can set the desired default. defIdx = [idxFixedNotWeight(1) idxFixedNotWeight(2) nFixed+1]; elseif length(idxFixedNotWeight) == 1 && nFree > 1 % Select the one fixed variable that is not a weight and the first % two free variables. defIdx = [idxFixedNotWeight(1) nFixed+1 nFixed+2]; elseif nFree > 1 % Any fixed variables are weights, at least two free variables. % Let's select the first three items after the fixed variables. defIdx = nFixed + (1:3); else % Select the first three items defIdx = 1:3; end else defIdx = []; end end end % pGetValidItems %---------------------------------------- function OutputContents = pOutputContents(obj) %#ok<MANU> %POUTPUTCONTENTS Valid value types for Values2dView. % OUTPUTCONTENTS = POUTPUTCONTENTS(OBJ) returns the valid value types % that can be displayed in Values2dView. The cell array, % OUTPUTCONTENTS, is used when querying the output object for % optimization results data. OutputContents = {'FixedVars', 'FreeVars', 'Objectives'}; end % pOutputContents %---------------------------------------- function pPostSetMessageService(obj) %PPOSTSETMESSAGESERVICE Method that is called when the message service is set % PPOSTSETMESSAGESERVICE(OBJ) is called in response to a new message % service being set in the object. pPostSetMessageService@mbcgui.multiview.View(obj) obj.addMessageServiceListener( {'ObjectChanged', 'SliceDirectionChanged'}, ... {@obj.redraw, @obj.redraw}); % Add custom redraw events for a single index changing obj.addMessageServiceListener( ... {'RunIndexChanged', 'SolutionIndexChanged'}, ... {{@i_runchange, obj}, {@i_solchange, obj}}); % Set the current point when the current focus or the focus point changes obj.addMessageServiceListener( {'FocusOrFocusPointChanged'}, ... {{@i_refreshcurrentpoint, obj}}); % Add custom redraw events for the selected solution changing obj.addMessageServiceListener( {'SelectedSolutionChanged'}, ... {{@i_targetedchange, obj, 'selectedsolution'}}); % Add custom redraws for the Acceptable status changing obj.addMessageServiceListener( {'AcceptableChanged'}, {{@i_acceptchange, obj}}); % Redraw now redraw(obj); end % pPostSetMessageService %---------------------------------------- function pRefresh(obj) %PREFRESH Refresh view % PREFRESH(OBJ) Refresh view in OBJ. if obj.hasData && size(obj.OutputValues.Data, 2) > 2 % Set the "no display" text invisible set(obj.hText, 'String', '', 'Visible', 'off'); % Get the selected indices idxX = obj.hSelector.XFactor; idxY = obj.hSelector.YFactor; idxZ = obj.hSelector.ZFactor; % Get the data for the current view [data, bRedIdx, bOrangeIdx, bGreenIdx] = pGetOutputData(obj); bAcceptableIdx = pGetUserOutputData(obj); % Update the boolean indices to reflect user selection [bRedIdx, bOrangeIdx, bGreenIdx, bRedAcceptIdx, bOrangeAcceptIdx, bGreenNotAcceptIdx] = ... pGetDisplayIndices(obj, bRedIdx, bOrangeIdx, bGreenIdx, bAcceptableIdx); % Make any required data transformations before plotting data = pTransformDataForPoints(obj, data); % Plot the data set(obj.hRedLine(1), 'XData', data(bRedIdx, idxX), ... 'YData', data(bRedIdx, idxY), 'ZData', data(bRedIdx, idxZ)); set(obj.hRedLine(2), 'XData', data(bRedAcceptIdx, idxX), ... 'YData', data(bRedAcceptIdx, idxY), 'ZData', data(bRedAcceptIdx, idxZ)); set(obj.hOrangeLine(1), 'XData', data(bOrangeIdx, idxX), ... 'YData', data(bOrangeIdx, idxY), 'ZData', data(bOrangeIdx, idxZ)); set(obj.hOrangeLine(2), 'XData', data(bOrangeAcceptIdx, idxX), ... 'YData', data(bOrangeAcceptIdx, idxY), 'ZData', data(bOrangeAcceptIdx, idxZ)); set(obj.hGreenLine(1), 'XData', data(bGreenIdx, idxX), ... 'YData', data(bGreenIdx, idxY), 'ZData', data(bGreenIdx, idxZ)); set(obj.hGreenLine(2), 'XData', data(bGreenNotAcceptIdx, idxX), ... 'YData', data(bGreenNotAcceptIdx, idxY), 'ZData', data(bGreenNotAcceptIdx, idxZ)); % Determine x, y axis limits from entire data - do not automatically % rescale on filtered data. Expand the axis range by 200*eps to ensure % any data on the axis limits gets plotted. xLim = mbcmakelimits(data(:, idxX)) + 100*[-eps eps]; yLim = mbcmakelimits(data(:, idxY)) + 100*[-eps eps]; % Determine z-axis limits from filtered data. Expand the axis range by % 200*eps to ensure any data on the axis limits gets plotted. bDisplayIdx = bRedIdx | bOrangeIdx | bGreenIdx | ... bRedAcceptIdx | bOrangeAcceptIdx | bGreenNotAcceptIdx; zLim = mbcmakelimits(data(bDisplayIdx, idxZ)) + 100*[-eps eps]; set(obj.hSelector.Axes, 'XLim', xLim, 'YLim', yLim, 'ZLim', zLim); else % Deal with unsupported cases. % Clear the plot set(obj.hRedLine, 'XData', [], 'YData', [], 'ZData', []); set(obj.hOrangeLine, 'XData', [], 'YData', [], 'ZData', []); set(obj.hGreenLine, 'XData', [], 'YData', [], 'ZData', []); % Set the axes ranges to [0, 1] set(obj.hSelector.Axes, 'XLim', [0, 1], 'YLim', [0, 1], 'ZLim', [0, 1]); % Inform the user of the problem if strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') msg = sprintf('%s\n%s', 'Cannot plot output values in the', ... 'weighted objectives view'); else % Catch all for any other problems - shouldn't get here. msg = 'Three or more valid factors are required for'; msg = sprintf('%s\n%s', msg, gettitle(obj)); end set(obj.hText, 'Visible', 'on', ... 'Units','normalized',... 'Position',[.5 .5 .5],... 'HorizontalAlignment','center',... 'VerticalAlignment','middle',... 'String', msg); end end % pRefresh %---------------------------------------- function pRefreshAcceptabilityMenu(obj, currIdx, isCurrPointDisplayed) %PREFRESHACCEPTABILITYMENU Update the acceptability menus % PREFRESHACCEPTABILITYMENU(OBJ, CURRIDX, ISCURRPOINTDISPLAYED) updates % the enabled state of the acceptability menus. % % PREFRESHACCEPTABILITYMENU(OBJ) sets the enabled state of both % acceptability menus to false. if nargin > 1 && obj.hasData && ... size(obj.OutputValues.Data, 2) > 2 && isCurrPointDisplayed bAcceptableIdx = pGetUserOutputData(obj); obj.ViewAction.Actions(2).Enabled = ~bAcceptableIdx(currIdx); obj.ViewAction.Actions(3).Enabled = bAcceptableIdx(currIdx); else obj.ViewAction.Actions(2).Enabled = false; obj.ViewAction.Actions(3).Enabled = false; end end % pRefreshAcceptabilityMenu %---------------------------------------- function pRefreshCurrentPoint(obj) %PREFRESHCURRENTPOINT Refresh the current point % % PREFRESHCURRENTPOINT(OBJ) refreshes the location of the current point % in OBJ. The marker style of the current point is dependent on the color % and acceptability of the current point. idxCurrPoint = []; colorCurrPoint = ''; xdata = []; ydata = []; zdata = []; currPointMarker = 'o'; currPointSize = 16; lineWidth = 2.5; if obj.hasData % Get the data for the current view [data, bRedIdx, bOrangeIdx, bGreenIdx] = pGetOutputData(obj); data = pTransformDataForPoints(obj, data); [bAcceptableIdx, idxCurrPoint] = pGetUserOutputData(obj); % Update the boolean indices to reflect user selection [bRedIdx, bOrangeIdx, bGreenIdx, bRedAcceptIdx, bOrangeAcceptIdx, bGreenNotAcceptIdx] = ... pGetDisplayIndices(obj, bRedIdx, bOrangeIdx, bGreenIdx, bAcceptableIdx); % Determine the color of the current point. if size(data, 2) < 3 || isempty(idxCurrPoint) colorCurrPoint = ''; elseif bRedIdx(idxCurrPoint) || bRedAcceptIdx(idxCurrPoint) colorCurrPoint = 'red'; elseif bOrangeIdx(idxCurrPoint) || bOrangeAcceptIdx(idxCurrPoint) colorCurrPoint = 'orange'; elseif bGreenIdx(idxCurrPoint) || bGreenNotAcceptIdx(idxCurrPoint) colorCurrPoint = 'green'; else colorCurrPoint = ''; end % If no color has been specified, then the current point is not visible if size(data, 2) > 2 && ~isempty(colorCurrPoint) % Get the coordinates of the current point idxX = obj.hSelector.XFactor; idxY = obj.hSelector.YFactor; idxZ = obj.hSelector.ZFactor; xdata = data(idxCurrPoint, idxX); ydata = data(idxCurrPoint, idxY); zdata = data(idxCurrPoint, idxZ); % Determine whether the current point's acceptability has been changed % by the user out = obj.MessageService.getOptimOutput; RunIdx = obj.MessageService.getFocusRun; SolIdx = obj.MessageService.getFocusSolution; isAcceptChanged = isAcceptableUserSet(out, RunIdx, SolIdx); % Refresh the current point marker if isAcceptChanged currPointMarker = 'p'; currPointSize = 24; lineWidth = 1.5; elseif strcmpi(colorCurrPoint, 'red') currPointMarker = 'o'; currPointSize = 16; lineWidth = 2.5; elseif strcmpi(colorCurrPoint, 'orange') currPointMarker = '^'; currPointSize = 18; lineWidth = 2.5; else currPointMarker = 's'; currPointSize = 18; lineWidth = 2.5; end end end set(obj.hCurrentPoint, 'XData', xdata, 'YData', ydata, 'ZData', zdata, ... 'Marker', currPointMarker, 'MarkerSize', currPointSize, ... 'LineWidth', lineWidth); % Update the acceptability menus obj.pRefreshAcceptabilityMenu(idxCurrPoint, ~isempty(colorCurrPoint)); end % pRefreshCurrentPoint %---------------------------------------- function pResetInputList(obj) %PRESETINPUTLIST Re-fill the list of optimization quantities % % PRESETINPUTLIST(OBJ) resets the list of available optimization % quantities. % Get the items that can be plotted [nms, ~, defIdx] = pGetValidItems(obj); % Handle to the factor selector hSel = obj.hSelector; % Only need to reset the input list if the factors have changed if ~isequal(nms(:), hSel.Factors(:)) % Set them as the factors in the selector. If there are less than three % valid items then set an empty cell array of factors in the selector. if length(nms) > 2 hSel.Factors = nms; else hSel.Factors = {}; defIdx = []; end % Set the default factors in the selector if ~isempty(defIdx) hSel.DefaultFactorIndices = defIdx; hSel.setFactorsToDefault; end end end % pResetInputList %---------------------------------------- function pSetFocusRunSolPt(obj, idxView) %PGETFOCUSRUNSOLPT Set the current run, solution and point % % PGETFOCUSRUNSOLPT(OBJ, IDXVIEW) sets the current optimization output % run, solution and point from the IDXVIEW-th point clicked in OBJ. % % See also PGETOUTPUTDATA if obj.hasData % Length of the quantities qLen = obj.pGetQuantityLength; % Current point idxCurrPt = rem(idxView-1, qLen) + 1; % Run or solution depends on slice direction ms = obj.MessageService; switch ms.CurrentSliceDirection case {'solution', 'selectedsolution'} curSol = ms.CurrentSolution; idxCurrRun = ceil(idxView/qLen); ms.setCurrentIndex(idxCurrRun, curSol, idxCurrPt); case 'pareto' curRun = ms.CurrentRun; idxCurrSol = ceil(idxView/qLen); ms.setCurrentIndex(curRun, idxCurrSol, idxCurrPt); end end end % pSetFocusRunSolPt %---------------------------------------- function data = pTransformDataForPoints(obj, data) %#ok<INUSL> %PTRANSFORMDATAFORPOINTS Apply any data transormations before plotting % DATA = PTRANSFORMDATAFORPOINTS(OBJ, DATA) is called on the % NPTS-by-NFACS data array before it is used to plot the solution points. % % See also pGetOutputData. % The default action is no transform. end % pTransformDataForPoints %---------------------------------------- function pUpdateOutputValuesCache(obj) %PUPDATEOUTPUTVALUESCACHE Update optimization results cache. % PUPDATEOUTPUTVALUESCACHE(OBJ) updates the optimization results in the % output values cache. if obj.hasData DataMats = {}; out = obj.MessageService.getOptimOutput; SolIdx = obj.MessageService.getFocusSolution; nRunOptim = getNumRuns(out); OutputDataArgs = {'OutputFormat', 'cell', ... 'OutputContents', pOutputContents(obj)}; if strcmp(obj.MessageService.CurrentSliceDirection, 'solution') % Display all runs at focussed solution selection if SolIdx>0 DataMats = getSolution(out, SolIdx, OutputDataArgs{:}); % Get the exit flag for each run exitFlag = getExitFlag(out, 1:nRunOptim, SolIdx)'; end elseif strcmp(obj.MessageService.CurrentSliceDirection, 'pareto') % Display all solutions at focussed run selection RunIdx = obj.MessageService.getFocusRun; if RunIdx>0 DataMats = getParetoSolution(out, RunIdx, OutputDataArgs{:}); % Get the exit flag for each solution nSolOptim = getNumSolutions(out); exitFlag = getExitFlag(out, RunIdx, 1:nSolOptim); end elseif strcmp(obj.MessageService.CurrentSliceDirection, 'selectedsolution') % Display selected solution for each run if hasSelectedSolution(out) DataMats = getSelectedSolution(out, OutputDataArgs{:}); % Get the exit flag for the selected solution exitFlag = getExitFlag(out, 1:nRunOptim, -1)'; end else % This object does not plot any data for the weighted solution % view. It will display a message instead - this is dealt with in % pCheckOutputData end if isempty(DataMats) Data = []; bRedIdx = []; bOrangeIdx = []; bGreenIdx = []; else % Only keep valid data [~, bIdx] = pGetValidItems(obj); DataMats = DataMats(bIdx); % Convert data cell array into matrix. We assume at this point that the % length of each cell array is 1 or max(lenData) lenData = cellfun('size', DataMats, 2); maxLen = max(lenData); scalarIdx = lenData == 1; DataMats(scalarIdx) = cellfun(@(x)x(:, ones(maxLen, 1)), ... DataMats(scalarIdx), 'UniformOutput', false); DataMats = cellfun(@i_makeCol, DataMats, 'UniformOutput', false); Data = [DataMats{:}]; % At this point, the exit flag and acceptable indices are row % vectors, each element determining the status of each run/solution % in the data matrix. We need to repmat these vectors so that each % element of a solution has an exit flag and acceptable index % associated with it. exitFlag = repmat(exitFlag, maxLen, 1); exitFlag = exitFlag(:); % Generate indices for red(bad), orange(warning) and green(good) % points bRedIdx = (exitFlag < 0); bOrangeIdx = (exitFlag == 0); bGreenIdx = (exitFlag > 0); end obj.OutputValues.Data = Data; obj.OutputValues.bRedIdx = bRedIdx; obj.OutputValues.bOrangeIdx = bOrangeIdx; obj.OutputValues.bGreenIdx = bGreenIdx; end end % pUpdateOutputValuesCache function setUIContextMenu(obj) obj.hSelector.Axes.UIContextMenu = obj.UIContextMenu; end function createActions(obj) % Create option actions AG = mbcgui.actions.ActionGroup('', '&View Options'); AG.MenuType = 'separate'; AGDisplay = mbcgui.actions.ActionGroup('', '&Results to Display'); AGDisplay.MenuType = 'submenu'; Adisp1 = mbcgui.actions.ToggleAction({@i_setdisplaydata, 'All', obj}, '&All'); Adisp2 = mbcgui.actions.ToggleAction({@i_setdisplaydata, 'Acceptable', obj}, 'A&cceptable'); Adisp3 = mbcgui.actions.ToggleAction({@i_setdisplaydata, 'Green', obj}, '&Green'); Adisp4 = mbcgui.actions.ToggleAction({@i_setdisplaydata, 'Orange', obj}, '&Orange'); Adisp5 = mbcgui.actions.ToggleAction({@i_setdisplaydata, 'Red', obj}, '&Red'); AGDisplay.Actions = [Adisp1 Adisp2 Adisp3 Adisp4 Adisp5]; AAcceptable = mbcgui.actions.StatefulAction({@i_setacceptable, obj}, '&Set Acceptable'); AUnacceptable = mbcgui.actions.StatefulAction({@i_setunacceptable, obj}, '&Set Unacceptable'); switch obj.DisplayData case 'Acceptable' Adisp2.Selected = true; case 'Green' Adisp3.Selected = true; case 'Orange' Adisp4.Selected = true; case 'Red' Adisp5.Selected = true; otherwise Adisp1.Selected = true; end AG.Actions = [AGDisplay, AAcceptable, AUnacceptable]; obj.ViewAction = AG; % Set the options in the multiview class obj.Options = AG; end function redraw(obj,~, ~) % redraw plot obj.pUpdateOutputValuesCache; obj.pResetInputList; obj.pRefresh; obj.pRefreshCurrentPoint; end % redraw function axesClick(obj,~, ~) % Determine whether this is a left or right click f = ancestor(obj.hSelector.Axes, 'figure'); selType = get(f, 'SelectionType'); % Only want to perform rotation on left clicks of the axes - this reserves % right-click for the context menu. if strcmpi(selType, 'normal') && obj.CanRotate % Start rotation mv_rotate3d(obj.hSelector.Axes, 'ON'); % Launch the box for rotation wbdf = get(f, 'WindowButtonDownFcn'); feval(wbdf{1}, f, [], wbdf{2}); % Use the button up manager to listen for the next button up and shut off % rotation but_manager = xregGui.ButtonUpManager(f); but_manager.getNextEvent({@i_switchRotateOff, obj}); end % Send the view's button down event to make it the current view obj.notify('ButtonDown'); end % i_axesClick end methods (Hidden) % possibly private or hidden %---------------------------------------- function [bRedIdx, bOrangeIdx, bGreenIdx, bRedAcceptIdx, bOrangeAcceptIdx, bGreenNotAcceptIdx] = ... pGetDisplayIndices(obj, bRedIdx, bOrangeIdx, bGreenIdx, bAcceptableIdx) %PGETDISPLAYINDICES Return the display indices % % [BREDIDX, BORANGEIDX, BGREENIDX, BREDACCEPTIDX, BORANGEACCEPTIDX, % BGREENNOTACCEPTIDX] = PGETDISPLAYINDICES(OBJ, BREDIDX, BORANGEIDX, % BGREENIDX, BACCEPTABLEIDX) returns a boolean index for each data point % determining whether it is displayed in that colour/shape or not. switch obj.DisplayData case 'Acceptable' bRedIdx = bRedIdx & bAcceptableIdx; bOrangeIdx = bOrangeIdx & bAcceptableIdx; bGreenIdx = bGreenIdx & bAcceptableIdx; case 'Red' bOrangeIdx = false(size(bOrangeIdx)); bGreenIdx = false(size(bGreenIdx)); case 'Orange' bRedIdx = false(size(bRedIdx)); bGreenIdx = false(size(bGreenIdx)); case 'Green' bRedIdx = false(size(bRedIdx)); bOrangeIdx = false(size(bOrangeIdx)); end % Find any points whose acceptability has been changed. These will be % marked by stars on the plot. bRedAcceptIdx = bRedIdx & bAcceptableIdx; bRedIdx(bRedAcceptIdx) = false; bOrangeAcceptIdx = bOrangeIdx & bAcceptableIdx; bOrangeIdx(bOrangeAcceptIdx) = false; bGreenNotAcceptIdx = bGreenIdx & ~bAcceptableIdx; bGreenIdx(bGreenNotAcceptIdx) = false; end % pGetDisplayIndices end % possibly private or hidden end % classdef function val = i_setDisplayData(~, val) validDisplayData = {'All', 'Acceptable', 'Green', 'Orange', 'Red'}; errmsg = 'Display data must be one of All, Acceptable, Green, Orange, Red'; if ~ismember(val, validDisplayData) error('mbc:Values2dView:InvalidArgument', errmsg); end end % i_setDisplayData function i_inputschanged(~, ~, obj) obj.pRefresh; obj.pRefreshCurrentPoint; end % i_inputschanged function i_setdisplaydata(~, ~, DisplayData, obj) obj.setDisplayFilter(DisplayData); end % i_setdisplaydata function i_switchRotateOff(~, ~, obj) % Stop rotation hSelector = obj.pGetSelector; mv_rotate3d(hSelector.Axes, 'off'); end % i_switchRotateOff function i_redLineButtonDown(~, ~, obj, isAcceptChangedLine) % Switch % Find the nearest point on the line to the mouse click. idxLine = obj.pFindNearestPoint('red', isAcceptChangedLine); % Perform update actions i_updateAfterLeftClick(obj, idxLine); end % i_redLineButtonDown function i_orangeLineButtonDown(~, ~, obj, isAcceptChangedLine) % Find the nearest point on the line to the mouse click. idxLine = obj.pFindNearestPoint('orange', isAcceptChangedLine); % Perform update actions i_updateAfterLeftClick(obj, idxLine); end % i_orangeLineButtonDown function i_greenLineButtonDown(~, ~, obj, isAcceptChangedLine) % Find the nearest point on the line to the mouse click. idxLine = obj.pFindNearestPoint('green', isAcceptChangedLine); % Perform update actions i_updateAfterLeftClick(obj, idxLine); end % i_greenLineButtonDown function i_updateAfterLeftClick(obj, idxLine) % Send the view's button down event to make it the current view obj.notify('ButtonDown'); % Temporarily disable the listeners - we want to update before everyone else. obj.disableMessageServiceListeners; % Set the focus run, solution and point corresponding to the idx-th point % clicked in the view. pSetFocusRunSolPt(obj, idxLine); % Move the current point obj.pRefreshCurrentPoint; % Enable the listeners obj.enableMessageServiceListeners; end % i_updateAfterLeftClick function i_setacceptable(~, ~, obj) i_setacceptability(obj, true); end % i_setacceptable function i_setunacceptable(~, ~, obj) i_setacceptability(obj, false); end % i_setunacceptable function i_setacceptability(obj, acceptState) % Get current run and solution ms = obj.MessageService; runIdx = ms.getFocusRun; solIdx = ms.getFocusSolution; % Set run/solution to be acceptable out = obj.MessageService.getOptimOutput; out = setAcceptableToUser(out, runIdx, solIdx, acceptState); obj.MessageService.setOptimOutput(out, 'AcceptableChanged'); end % i_setacceptability function [xdata, ydata, zdata, cp] = i_scaleData(ax, xdata, ydata, zdata, cp) % Get axes limits xlim = get(ax, 'XLim'); ylim = get(ax, 'YLim'); zlim = get(ax, 'ZLim'); % Rescale xdata xdata = (xdata - xlim(1))./(xlim(2) - xlim(1)); cp(:, 1) = (cp(:, 1) - xlim(1))./(xlim(2) - xlim(1)); % Rescale ydata ydata = (ydata - ylim(1))./(ylim(2) - ylim(1)); cp(:, 2) = (cp(:, 2) - ylim(1))./(ylim(2) - ylim(1)); % Rescale zdata zdata = (zdata - zlim(1))./(zlim(2) - zlim(1)); cp(:, 3) = (cp(:, 3) - zlim(1))./(zlim(2) - zlim(1)); end % i_scaleData function i_targetedchange(~, ~, obj, target) if strcmpi(obj.MessageService.CurrentSliceDirection,target) % Only redraw if the specified target view is currently being used % Do a full redraw because we may be on a selected view that is going % from empty to an initialised state. redraw(obj); end end % i_targetedchange function i_runchange(~, ~, obj) if strcmpi(obj.MessageService.CurrentSliceDirection, 'pareto') % Redraw the view obj.pUpdateOutputValuesCache; obj.pRefresh; end end % i_runchange function i_solchange(~, ~, obj) redrawDirs = {'solution', 'selectedsolution'}; if any(strcmpi(obj.MessageService.CurrentSliceDirection, redrawDirs)) % Redraw the view obj.pUpdateOutputValuesCache; obj.pRefresh; end end % i_solchange function i_acceptchange(~, ~, obj) obj.pRefresh; obj.pRefreshCurrentPoint; end % i_acceptchange function i_refreshcurrentpoint(~, ~, obj) obj.pRefreshCurrentPoint; end % i_refreshcurrentpoint function DataElt = i_makeCol(DataElt) DataElt = DataElt'; DataElt = DataElt(:); end % i_makeCol