www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+xregdatagui/TssfClusterView.m
classdef TssfClusterView < xregdatagui.AbstractDataView %xregdatagui.TssfClusterView class % xregdatagui.TssfClusterView extends xregdatagui.AbstractDataView. % % xregdatagui.TssfClusterView 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' (read only) % UIContextMenu - Property is of type 'MATLAB array' % Listeners - Property is of type 'handle vector' (read only) % Graph - Property is of type 'MATLAB array' (read only) % Axes - Property is of type 'MATLAB array' (read only) % MatchedDesignLine - Property is of type 'MATLAB array' (read only) % MatchedDesign - Property is of type 'MATLAB array' % UnmatchedDesignLine - Property is of type 'MATLAB array' (read only) % UnmatchedDesign - Property is of type 'MATLAB array' % HighlightDesignLine - Property is of type 'MATLAB array' (read only) % HighlightDesign - Property is of type 'MATLAB array' % MatchedDataLine - Property is of type 'MATLAB array' (read only) % MatchedData - Property is of type 'MATLAB array' % UnmatchedDataLine - Property is of type 'MATLAB array' (read only) % UnmatchedData - Property is of type 'MATLAB array' % ExcludedDataLine - Property is of type 'MATLAB array' (read only) % ExcludedData - Property is of type 'MATLAB array' % HighlightDataLine - Property is of type 'MATLAB array' (read only) % HighlightData - Property is of type 'MATLAB array' % DataDesignLine - Property is of type 'MATLAB array' (read only) % DataDesign - Property is of type 'MATLAB array' % DataLabelHandles - Property is of type 'MATLAB array' (read only) % DataLabels - Property is of type 'MATLAB array' % DesignLabelHandles - Property is of type 'MATLAB array' (read only) % DesignLabels - Property is of type 'MATLAB array' % LabelsVisible - Property is of type 'bool' % ClusterPatches - Property is of type 'MATLAB array' (read only) % ClusterVisible - Property is of type 'MATLAB array' % GlobalDataCache - Property is of type 'MATLAB array' (read only) % DisplayOptions - Property is of type 'MATLAB array' (read only) % StaticInfo - Property is of type 'MATLAB array' (read only) % CurrentClusterInfo - Property is of type 'MATLAB array' (read only) % LegendAxes - Property is of type 'MATLAB array' (read only) % % xregdatagui.TssfClusterView methods: % ClusterTypesToDisplay - A short description of the function % gettitle - returns string describing this view % Copyright 2015-2016 The MathWorks, Inc. and Ford Global Technologies, Inc. properties (Constant) %ViewInfo view description ViewInfo = { @xregdatagui.TssfClusterView; 'Design &Match'; xregrespath('clusterplot.bmp'); 'Match data to design'; 1}; end properties (AbortSet, SetObservable) %MATCHEDDESIGN Property is of type 'MATLAB array' MatchedDesign = []; %UNMATCHEDDESIGN Property is of type 'MATLAB array' UnmatchedDesign = []; %HIGHLIGHTDESIGN Property is of type 'MATLAB array' HighlightDesign = []; %MATCHEDDATA Property is of type 'MATLAB array' MatchedData = []; %UNMATCHEDDATA Property is of type 'MATLAB array' UnmatchedData = []; %EXCLUDEDDATA Property is of type 'MATLAB array' ExcludedData = []; %HIGHLIGHTDATA Property is of type 'MATLAB array' HighlightData = []; %DATADESIGN Property is of type 'MATLAB array' DataDesign = []; %DATALABELS Property is of type 'MATLAB array' DataLabels = []; %DESIGNLABELS Property is of type 'MATLAB array' DesignLabels = []; %LABELSVISIBLE Property is of type 'bool' LabelsVisible = false; %CLUSTERVISIBLE Property is of type 'MATLAB array' ClusterVisible = []; end properties (SetAccess=protected, AbortSet, SetObservable) %GRAPH Property is of type 'MATLAB array' (read only) Graph = []; %AXES Property is of type 'MATLAB array' (read only) Axes = []; %MATCHEDDESIGNLINE Property is of type 'MATLAB array' (read only) MatchedDesignLine = []; %UNMATCHEDDESIGNLINE Property is of type 'MATLAB array' (read only) UnmatchedDesignLine = []; %HIGHLIGHTDESIGNLINE Property is of type 'MATLAB array' (read only) HighlightDesignLine = []; %MATCHEDDATALINE Property is of type 'MATLAB array' (read only) MatchedDataLine = []; %UNMATCHEDDATALINE Property is of type 'MATLAB array' (read only) UnmatchedDataLine = []; %EXCLUDEDDATALINE Property is of type 'MATLAB array' (read only) ExcludedDataLine = []; %HIGHLIGHTDATALINE Property is of type 'MATLAB array' (read only) HighlightDataLine = []; %DATADESIGNLINE Property is of type 'MATLAB array' (read only) DataDesignLine = []; %DATALABELHANDLES Property is of type 'MATLAB array' (read only) DataLabelHandles = []; %DESIGNLABELHANDLES Property is of type 'MATLAB array' (read only) DesignLabelHandles = []; %CLUSTERPATCHES Property is of type 'MATLAB array' (read only) ClusterPatches = []; %GLOBALDATACACHE Property is of type 'MATLAB array' (read only) GlobalDataCache = []; %DISPLAYOPTIONS Property is of type 'MATLAB array' (read only) DisplayOptions = []; %STATICINFO Property is of type 'MATLAB array' (read only) StaticInfo = []; %CURRENTCLUSTERINFO Property is of type 'MATLAB array' (read only) CurrentClusterInfo = []; %LEGENDAXES Property is of type 'MATLAB array' (read only) LegendAxes = []; %ClusterInfo cluster info view embedded in cluster plot ClusterInfo end methods % constructor block function obj = TssfClusterView(varargin) %TSSFCLUSTERVIEW constructor % OUT = TSSFCLUSTERVIEW(VARARGIN) % Do the setup stuff from inside the abstractDataView constructor obj@xregdatagui.AbstractDataView(varargin{ : }); % converted super class constructor call % Create the graphical objects and put in the Display field obj.pCreateDisplay; % Update the display obj.pUpdateDisplay createActions(obj); end % tssfclusterview end % constructor block methods function set.MatchedDesign(obj,value) obj.MatchedDesign = i_setDesign(obj,value); end function set.UnmatchedDesign(obj,value) obj.UnmatchedDesign = i_setDesign(obj,value); end function set.HighlightDesign(obj,value) obj.HighlightDesign = i_setDesign(obj,value); end function set.MatchedData(obj,value) obj.MatchedData = i_setData(obj,value); end function set.UnmatchedData(obj,value) obj.UnmatchedData = i_setData(obj,value); end function set.ExcludedData(obj,value) obj.ExcludedData = i_setData(obj,value); end function set.HighlightData(obj,value) obj.HighlightData = i_setData(obj,value); end function set.DataDesign(obj,value) obj.DataDesign = i_setData(obj,value); end function set.DataLabels(obj,value) obj.DataLabels = i_setData(obj,value); end function set.DesignLabels(obj,value) obj.DesignLabels = i_setDesign(obj,value); end function set.ClusterVisible(obj,value) obj.ClusterVisible = i_setCluster(obj,value); end end % set and get functions methods % public methods %---------------------------------------- function types = ClusterTypesToDisplay(obj) %ClusterTypesToDisplay A short description of the function % OUT = ClusterTypesToDisplay(IN) % What are the possible types validTypes = {'same' 'moredata' 'moredesign' 'unmatcheddata' 'unmatcheddesign' 'designonly'}; % Which ones are selected s(1) = get(obj.DisplayOptions(3), 'Value') == 1; s(2) = get(obj.DisplayOptions(6), 'Value') == 1; s(3) = get(obj.DisplayOptions(9), 'Value') == 1; % Create the chosen array chosen = [s true true s(1)]; % Subselect the possible types types = validTypes(chosen); end % ClusterTypesToDisplay %---------------------------------------- function out = gettitle(obj) %#ok<MANU> %GETTITLE returns string describing this view % OUT = GETTITLE(OBJ) out = 'Design Match'; end % gettitle %---------------------------------------- function pSendCurrentClusterChanged(obj, ClusterIdx) %PSENDCURRENTCLUSTERCHANGED A short description of the function % OUT = PSENDCURRENTCLUSTERCHANGED(IN) obj.MessageService.setCurrentCluster(ClusterIdx); % And update me in this event obj.pUpdateCurrentClusterInfo; % Update selected tests obj.pSendSelectedTestsChanged; end % pSendCurrentClusterChanged %---------------------------------------- function pSendSelectedTestsChanged(obj) %PSENDSELECTEDTESTSCHANGED A short description of the function % PSENDSELECTEDTESTSCHANGED(obj) dms = obj.MessageService; tssf = dms.TestplanSweepsetFilter; ClusterIdx = dms.CurrentClusterIndex; if ~dms.isOneStage && ClusterIdx>0 % Get the information about the clusters % Set the selected tests for two-stage data only thisCluster = get(dms.TestplanSweepsetFilter, 'clusters', ClusterIdx); dms.setSelectedTests( convertTestIndices(tssf, thisCluster.selecteddata) ); end end % pSendSelectedTestsChanged %---------------------------------------- function pUpdateCurrentClusterInfo(obj, ~,~) %PUPDATECURRENTCLUSTERINFO update the information about the selected cluster % PUPDATECURRENTCLUSTERINFO(OBJ) % Reset all patches with magenta borders to have normal borders and replace % in the correct z-order h = findobj(obj.Axes, '-depth', 1, 'Type', 'rectangle', 'EdgeColor', 'm'); if ~isempty(h) set(h, 'EdgeColor', 'k',... 'LineWidth', 1); end % Reset all data and design to highlight dataToHighlight = false(size(get(obj.HighlightDataLine, 'XData'))); designToHighlight = false(size(get(obj.HighlightDesignLine, 'XData'))); ClusterIdx = obj.MessageService.CurrentClusterIndex; % Check the validity of the cluster index if ClusterIdx> 0 % Get the selected cluster thisCluster = get(obj.MessageService.TestplanSweepsetFilter, 'clusters', ClusterIdx); % Check it isn't the dataonly cluster if ~any(strcmp(thisCluster.status, {'unmatcheddata' 'unmatcheddesign'})) % Highlight this patch thisClusterH = obj.ClusterPatches{ClusterIdx}; set(thisClusterH, 'EdgeColor', 'm',... 'LineWidth', 2.5); % Highlight the data and design associated with the patch dataToHighlight(thisCluster.data) = true; designToHighlight(thisCluster.design) = true; % Determine the top most objects topMost = [... findobj(obj.Axes, '-depth', 1, 'type', 'line', '-or', 'type', 'text') ;... thisClusterH']; % Reoder the children set(obj.Axes, 'Children', [topMost ; setdiff(get(obj.Axes, 'Children'), topMost)]); end end % Ensure correct Highlights in data and design obj.HighlightData = dataToHighlight; obj.HighlightDesign = designToHighlight; % Have we got a cluster index of zero - indicating a reset if ClusterIdx < 1 obj.CurrentClusterInfo.ListText = {}; return end % OK - What sort of cluster is it switch thisCluster.status case 'unmatcheddata' % Write this cluster info to the stats box obj.CurrentClusterInfo.ListText =... {'Unmatched Data Points', num2str(length(thisCluster.data))}; case 'unmatcheddesign' % Write this cluster info to the stats box obj.CurrentClusterInfo.ListText =... {'Unmatched Design Points', num2str(length(thisCluster.design))}; case {'moredesign' 'moredata' 'same' 'designonly'} % Write this cluster info to the stats box - note transpose on Test % Number to ensure it prints nicely obj.CurrentClusterInfo.ListText = {... 'Design Points', num2str(length(thisCluster.design));... 'Data Points', num2str(length(thisCluster.data));... 'Design Index', num2str(thisCluster.design);... 'Test Number', num2str(obj.GlobalDataCache(thisCluster.data, end)');... }; otherwise warning(message('mbc:xregdatagui:tssfclusterview:InvalidState', thisCluster.status)); end end % pUpdateCurrentClusterInfo %---------------------------------------- function pUpdateDisplay(obj) %PUPDATEDISPLAY complete update of the view display % PUPDATEDISPLAY(OBJ) if hasData(obj.MessageService) % Simulate a data type changed update obj.pdmsDataTypeChangedUpdate; % Check the class of the current data object if obj.MessageService.isaTSSF obj.ptssfActualDesignChangedUpdate; obj.ptssfClustersCreatedUpdate; obj.ptssfClustersChangedUpdate; end end end % pUpdateDisplay %---------------------------------------- function pUpdateLabelVisibility(obj) %PUPDATELABELVISIBILITY A short description of the function % OUT = PUPDATELABELVISIBILITY(IN) % Which data labels should be visible dataLabelsToDisplay = ... ((obj.MatchedData & strcmp(get(obj.MatchedDataLine, 'Visible'), 'on') ) | ... (obj.UnmatchedData & strcmp(get(obj.UnmatchedDataLine, 'Visible'), 'on') ) | ... (obj.ExcludedData & strcmp(get(obj.ExcludedDataLine, 'Visible'), 'on') )) & obj.LabelsVisible; designLabelsToDisplay = ... ((obj.MatchedDesign & strcmp(get(obj.MatchedDesignLine, 'Visible'), 'on') ) | ... (obj.UnmatchedDesign & strcmp(get(obj.UnmatchedDesignLine, 'Visible'), 'on') )) & obj.LabelsVisible; % This should fire off the listeners in pCreateDisplay - however if % obj.DataLabels is already the same as it's new value then the event isn't % fired. However, after the view is made visible all childern of axes are % set visible on and so this call doesn't correctly reset the visibility. % % For now we'll explicitly set the visibility, as we do in % pUpdateLineVisibility - However this does mean that obj.DataLabels is % perhaps a little redundant % obj.DataLabels = dataLabelsToDisplay; % obj.DesignLabels = designLabelsToDisplay; set(obj.DataLabelHandles(dataLabelsToDisplay), 'Visible', 'on'); set(obj.DataLabelHandles(~dataLabelsToDisplay), 'Visible', 'off'); set(obj.DesignLabelHandles(designLabelsToDisplay), 'Visible', 'on'); set(obj.DesignLabelHandles(~designLabelsToDisplay), 'Visible', 'off'); end % pUpdateLabelVisibility %---------------------------------------- function pUpdateLineAndPatchData(obj) %PUPDATELINEANDPATCHDATA reset the line and patch data % PUPDATELINEANDPATCHDATA(OBJ) % This method is triggered by a change in the factors being displayed % Get the data tssf = obj.MessageService.TestplanSweepsetFilter; % Get my data - note, this excludes any sweeps I remove - PROBABLY NOT A % GOOD THING! X = obj.GlobalDataCache; % Get the clusters and actual design clusters = get(tssf, 'clusters'); [D, ~] = get(tssf, {'actualdesign' 'actualdata'}); tol = get(tssf, 'tolerances'); if size(D,2)==0 D = zeros(0,1); X = D; tol = 1e-3; end xFacInd = obj.Graph.XFactor; yFacInd = obj.Graph.YFactor; % Put data into each line on the plot. These do not change and will only % get turned vis on/off set([obj.MatchedDesignLine obj.UnmatchedDesignLine obj.HighlightDesignLine],... 'XData', D(:, xFacInd),... 'YData', D(:, yFacInd)); set([obj.MatchedDataLine obj.UnmatchedDataLine obj.ExcludedDataLine obj.DataDesignLine obj.HighlightDataLine],... 'XData', X(:, xFacInd),... 'YData', X(:, yFacInd)); % Add the data and design test numbers obj.DataLabelHandles = mbctagdata(X(:, [xFacInd yFacInd]), obj.GlobalDataCache(:, end), obj.Axes, obj.DataLabelHandles, 'on', 'simple'); obj.DesignLabelHandles = mbctagdata(D(:, [xFacInd yFacInd]), 1:size(D, 1) , obj.Axes, obj.DesignLabelHandles, 'on', 'simple'); % Make the design labels left aligned set(obj.DesignLabelHandles, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'top'); tolx = tol(xFacInd); toly = tol(yFacInd); % Cluster-by-cluster, plot patch around each design point in the cluster for i = 1:length(clusters) % Get the design indices for this cluster desInds = clusters(i).design; % OK - set the patch data for j = 1:length(obj.ClusterPatches{i}) xval = D(desInds(j), xFacInd); yval = D(desInds(j), yFacInd); set(obj.ClusterPatches{i}(j),... 'Position', [xval-tolx yval-toly 2*tolx 2*toly]); end end set(obj.Axes, 'XLimMode', 'auto', 'YLimMode', 'auto'); end % pUpdateLineAndPatchData %---------------------------------------- function pUpdateLineVisibility(obj) %PUPDATELINEVISIBILITY A short description of the function % OUT = PUPDATELINEVISIBILITY(IN) DispOpts = get(obj.DisplayOptions, {'Value'}); set(obj.MatchedDataLine, 'Visible', mbconoff(DispOpts{1})); set(obj.UnmatchedDataLine, 'Visible', mbconoff(DispOpts{2})); set(obj.MatchedDesignLine, 'Visible', mbconoff(DispOpts{4})); set(obj.UnmatchedDesignLine, 'Visible', mbconoff(DispOpts{5})); set(obj.ExcludedDataLine, 'Visible', mbconoff(DispOpts{7})); set(obj.DataDesignLine, 'Visible', mbconoff(DispOpts{8})); obj.pUpdateLabelVisibility; end % pUpdateLineVisibility %---------------------------------------- function pdmsDataTypeChangedUpdate(obj, ~,~) %PDMSDATATYPECHANGEDUPDATE event handler for the dmsDataTypeChanged event % PDMSDATATYPECHANGEDUPDATE(OBJ, SRC, EVENT) % Find the tssf listeners tssfListeners = obj.MessageService.findListeners(obj.Listeners, 'TestplanSweepsetFilter'); % If the dataObject isn't a sweepsetfilter then... % Turn on the sweepsetfilter listener [tssfListeners.Enabled] = deal(true); % Disable all the check boxes set(obj.DisplayOptions, 'Enable', 'on'); tolAction = findobj(obj.Options.Actions,'Description','Set input tolerances'); if ~isempty(tolAction) % disable Tolerances action when data is readonly tolAction.Enabled = ~obj.MessageService.IsReadOnly; end end % pdmsDataTypeChangedUpdate %---------------------------------------- function ptssfActualDesignChangedUpdate(obj, ~,~) %ptssfActualDesignChangedUpdate update of the view display for design changes % ptssfActualDesignChangedUpdate(OBJ) % What signal names are being used in the design signalNames = globalsignalnames(obj.MessageService.TestplanSweepsetFilter); set(obj.Graph, 'factors', signalNames); end % ptssfActualDesignChangedUpdate %---------------------------------------- function ptssfClustersChangedUpdate(obj, ~,~) %ptssfClustersChangedUpdate redraws the cluster patches % ptssfClustersChangedUpdate(OBJ) clusters = get(obj.MessageService.TestplanSweepsetFilter, 'clusters'); % Ensure that the clusterVisible listener isn't fired listener = obj.Listeners.findobj('Source', {obj.findprop('ClusterVisible')}); % Disable listener if ~isempty(listener) listener.Enabled = false; end % Update the cluster visibility obj.ClusterVisible = ismember({clusters.status}, obj.ClusterTypesToDisplay); if ~isempty(listener) % Re-enable listener listener.Enabled = true; end % Update the patches obj.pUpdateClusterVisibility; end % ptssfClustersChangedUpdate %---------------------------------------- function ptssfClustersCreatedUpdate(obj, ~,~) %PTSSFCLUSTERSCREATEDUPDATE redraws the cluster patches % PTSSFCLUSTERSCREATEDUPDATE(OBJ, EVENT) % Need to create the clusters patches correctly % Get the data tssf = obj.MessageService.TestplanSweepsetFilter; % Faster to get all these together tssfInfo = get(tssf, { ... 'clusters' ... 'actualdata' ... 'numberdesignpoints' ... }); % Get my data obj.GlobalDataCache = [mean(tssfInfo{2}) testnum(tssfInfo{2})']; % Get the clusters and actual design clusters = tssfInfo{1}; % Get info on the new clusters numDataPoints = size(tssfInfo{2}, 3); numDesignPoints = tssfInfo{3}; % Remove all the patches if ~isempty(obj.ClusterPatches) patches = [obj.ClusterPatches{:}]; delete(patches(isgraphics(patches))); end obj.ClusterPatches = cell(1, length(clusters)); % Set the unmatched data buttondown callback to not be associated with a cluster set(obj.UnmatchedDataLine, 'DataOnlyClusterIndex', 0); set(obj.UnmatchedDesignLine, 'DesignOnlyClusterIndex', 0); % Need to reorder the axes children to ensure that the lines are drawn on % top of the rectangles lines = get(obj.Axes, 'Children'); % Cluster-by-cluster, create a patch for each design point PatchCB = @i_patchClicked; for i = 1:length(clusters) % Is this the data only cluster if strcmp(clusters(i).status, 'unmatcheddata') % Set the unmatched data buttondown callback to have the index of % this cluster set(obj.UnmatchedDataLine, 'DataOnlyClusterIndex', i); % Don't create any patches for this cluster continue end if strcmp(clusters(i).status, 'unmatcheddesign') % Set the unmatched data buttondown callback to have the index of % this cluster set(obj.UnmatchedDesignLine, 'DesignOnlyClusterIndex', i); % Don't create any patches for this cluster continue end % Get the design indices for this cluster numDesignInds = length(clusters(i).design); % Pre-initialise the number of patch to be drawn obj.ClusterPatches{i} = gobjects(1, numDesignInds); % OK - create the patches for j = 1:numDesignInds obj.ClusterPatches{i}(j) = rectangle('Parent', obj.Axes,... 'ButtonDownFcn', {PatchCB, obj, i},... 'EdgeColor', 'k'); end end % Re-order the axes children to put the lines at the top set(obj.Axes, 'Children', [lines ; setdiff(get(obj.Axes, 'Children'), lines)]); % OK - all patches created, lets give them the correct data obj.pUpdateLineAndPatchData; % Turn all highlight lines off to start with falseData = false(numDataPoints, 1); falseDesign = false(numDesignPoints, 1); set(obj, 'HighlightData', falseData,... 'HighlightDesign', falseDesign); % And reset current cluster info obj.CurrentClusterInfo.ListText = {}; end % ptssfClustersCreatedUpdate end % public methods methods (Hidden) % possibly private or hidden %---------------------------------------- function pCreateDisplay(obj) %PCREATEDISPLAY create main view % ------------------------------------------------------------------------- % create Right hand side factor seletor and legend % ------------------------------------------------------------------------- SC = mbcgui.util.SystemColorsDbl; dataAxesLayout = mbcgui.container.layoutpanel(... 'Parent', obj.Parent, ... 'BorderType', 'beveledin', ... 'LayoutBorder', [3 3 3 3]); obj.Graph = mbcwidgets.factorselector2d('parent', dataAxesLayout,... 'FactorChangecallback',{@i_graphFactorChangeCallback, obj},... 'UIContextMenu',obj.UIContextMenu,... 'SelectionType', 'exclusive'); set(dataAxesLayout, 'LayoutComponent', obj.Graph); obj.Axes = obj.Graph.Axes; set(obj.Axes, 'ButtonDownFcn', {@i_axesButtonDown, obj},... 'Box','on',... 'XGrid','on',... 'YGrid','on',... 'UIContextMenu',obj.UIContextMenu) legendLayout = mbcgui.container.layoutpanel(... 'Parent', obj.Parent, ... 'BorderType', 'beveledin'); legAxPanel = mbcgui.widget.AxesContainer(... 'Parent', legendLayout,... 'UIContextMenu',obj.UIContextMenu); obj.LegendAxes = legAxPanel.AxesHandle; set(obj.LegendAxes,... 'Color', [1 1 1], ... 'XTickLabel', '',... 'XTick', [],... 'XLim', [0 100],... 'XColor', [1 1 1],... 'YTickLabel', '',... 'YTick', [],... 'YLim', [0 100],... 'YColor', [1 1 1],... 'ZColor', [1 1 1],... 'ButtonDownFcn', {@i_legendAxesButtonDown, obj}); % Line types xdata = [6 6 38 38 70 70]; ydata = [80 55 80 55 80 55]; marker = {'.' '.' 'o' 'o' 'x' '+'}; color = {'b' 'r' 'b' 'r' 'k' 'm'}; string = {'Matched data' 'Unmatched data' 'Matched design' ... 'Unmatched design' 'Excluded data' 'Data in design'}; for i = 1:length(xdata) line('Parent', obj.LegendAxes,... 'XData', xdata(i),... 'YData', ydata(i),... 'Marker', marker{i},... 'MarkerSize', 6,... 'Color', color{i},... 'LineStyle' ,'none'); text(xdata(i) + 2, ydata(i), string{i},... 'Parent', obj.LegendAxes); end % Patch types xPos = [0 0 2 2 0]; yPos = [0 10 10 0 0]; xOffset = [5 37 69]; yOffset = [25 25 25]; string = {'Equal data and design' 'More data than design' 'Less data than design'}; col = [188 231 191 ; 107 185 214 ; 197 137 166]./255; for i = 1:length(xOffset) patch('Parent', obj.LegendAxes,... 'XData', xPos + xOffset(i),... 'YData', yPos + yOffset(i),... 'FaceColor', col(i, :),... 'EdgeColor', 'k'); text(xOffset(i) + 3, yOffset(i) + 5, string{i},... 'Parent', obj.LegendAxes); end % Try and layer a checkbox next to the legend callbacks = {... {@i_checkClicked, obj},... {@i_checkClicked, obj},... {@i_clusterCheckClicked, obj},... {@i_checkClicked, obj},... {@i_checkClicked, obj},... {@i_clusterCheckClicked, obj},... {@i_checkClicked, obj},... {@i_checkClicked, obj},... {@i_clusterCheckClicked, obj}}; tags = {'matcheddata' ... 'unmatcheddata' ... 'same' ... 'matcheddesign' ... 'unmatcheddesign' ... 'moredata' ... 'excludeddata' ... 'dataindesign' ... 'moredesign'}; check = cell(length(tags),1); for i = 1:length(tags) check{i} = uicontrol(... 'Style', 'checkbox',... 'Value',1,... 'Parent', legendLayout,... 'BackgroundColor', [1 1 1],... 'String','',... 'HitTest', 'off',... 'Tag', tags{i},... 'Callback', callbacks{i}); end obj.DisplayOptions = [check{:}]; oneCol = repmat({[]}, 1, 5); checkGrid = xreggridbaglayout(legendLayout,... 'packgroup', 'xregdatagui.tssfclusterview',... 'dimension', [5 7],... 'elements', {oneCol{:} ... [] check{1:3} [] ... oneCol{:} ... [] check{4:6} [] ... oneCol{:} ... [] check{7:9} []},... 'rowratios', [0.075 0.25 0.25 0.25 0.175],... 'colratios', [0.01 0.03 0.29 0.03 0.29 0.03 0.33]); %#ok<*CCAT> % Note border to stop white axes interfering with edge legendLayer = xreglayerlayout(legendLayout,... 'packgroup', 'xregdatagui.tssfclusterview',... 'elements', {legAxPanel, checkGrid},... 'border', [3 3 3 3]); set(legendLayout, 'LayoutComponent', {legendLayer}); dataSplitLayout = xregsnapsplitlayout(obj.Parent,... 'packgroup', 'xregdatagui.tssfclusterview',... 'barstyle', 1,... 'orientation', 'ud',... 'style','tobottom',... 'split', [0.99 0.01],... 'minwidth', [210 90],... 'top', dataAxesLayout,... 'bottom', legendLayout); % ------------------------------------------------------------------------- % create Grid layout on left hand side % ------------------------------------------------------------------------- statisticsTitle = mbcgui.container.titlebarpanel(... 'Parent', obj.Parent, ... 'BarTitle', 'Statistics'); statisticsList = mbcgui.table.InfoPane('Parent', statisticsTitle,... 'SplitPosition', .7); set(statisticsTitle, 'ContentHandle', statisticsList); currentClusterTitle = mbcgui.container.titlebarpanel(... 'Parent', obj.Parent, ... 'BarTitle', 'Current Cluster'); currentClusterList = mbcgui.table.InfoPane('Parent', currentClusterTitle,... 'SplitPosition', .4); set(currentClusterTitle, 'ContentHandle', currentClusterList); graypatch = uicontrol('Parent', obj.Parent, ... 'Style', 'text', ... 'BackgroundColor', SC.CTRL_BG, ... 'HitTest', 'off', ... 'Enable', 'inactive'); listsGridLayout = xreggridbaglayout(obj.Parent,... 'packgroup', 'xregdatagui.tssfclusterview',... 'dimension', [3, 1],... 'rowsizes', [-1, 2, -1],... 'elements', {statisticsTitle graypatch currentClusterTitle}); clusterView = xregsplitlayout(obj.Parent,... 'packgroup', 'xregdatagui.tssfclusterview',... 'orientation','lr',... 'dividerstyle','flat',... 'left',listsGridLayout,... 'right',dataSplitLayout,... 'split',[.2 .8],... 'dividerwidth',4); % add cluster information lowerPanel = mbcgui.container.titlebarpanel('Parent',obj.Parent,... 'BarTitle','Cluster Information'); obj.ClusterInfo = xregdatagui.TssfInfoView('Parent',lowerPanel,... 'UIContextMenu',obj.UIContextMenu,... 'MessageService',obj.MessageService); lowerPanel.ContentHandle = obj.ClusterInfo; mainLayout = xregsplitlayout(obj.Parent,... 'packgroup', 'xregdatagui.tssfclusterview',... 'dividerstyle','flat',... 'orientation','ud',... 'split',[1 0],... 'minwidthunits','pixels',... 'minwidth',[300 100],... 'rowsizes', [-1, 80],... 'elements', {clusterView lowerPanel}); obj.ContentHandle = mainLayout; obj.StaticInfo = statisticsList; obj.CurrentClusterInfo = currentClusterList; createClusterGraphics(obj); % Create Listeners to changes in internal properties lineIndexListeners = [... event.proplistener(obj, obj.findprop('MatchedDesign'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.MatchedDesignLine));... event.proplistener(obj, obj.findprop('UnmatchedDesign'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.UnmatchedDesignLine));... event.proplistener(obj, obj.findprop('HighlightDesign'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.HighlightDesignLine));... event.proplistener(obj, obj.findprop('MatchedData'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.MatchedDataLine));... event.proplistener(obj, obj.findprop('UnmatchedData'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.UnmatchedDataLine));... event.proplistener(obj, obj.findprop('ExcludedData'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.ExcludedDataLine));... event.proplistener(obj, obj.findprop('HighlightData'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.HighlightDataLine));... event.proplistener(obj, obj.findprop('DataDesign'), 'PostSet', @(h,evt) i_updateLineDisplay(h,evt,obj.DataDesignLine));... ]; clusterListeners = event.proplistener(obj, obj.findprop('ClusterVisible'), 'PostSet', @i_updateClusterDisplay); labelListeners = [... event.proplistener(obj, obj.findprop('LabelsVisible'), 'PostSet', @i_updateLabelVisibility);... event.proplistener(obj, obj.findprop('DataLabels'), 'PostSet', @(h,evt) i_updateLabelDisplay(h,evt,'DataLabelHandles'));... event.proplistener(obj, obj.findprop('DesignLabels'), 'PostSet', @(h,evt) i_updateLabelDisplay(h,evt,'DesignLabelHandles'));... ]; obj.Listeners = [obj.Listeners ; lineIndexListeners; clusterListeners ; labelListeners]; end % pCreateDisplay function createClusterGraphics(obj) %createClusterGraphics create the lines used to display the different types of data obj.MatchedDesignLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', 'o',... 'MarkerSize',6,... 'Color', 'b',... 'ButtonDownFcn',{@i_pointClicked obj},... 'LineStyle' ,'none'); obj.UnmatchedDesignLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', 'o',... 'MarkerSize',6,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'r',... 'LineStyle' ,'none'); obj.HighlightDesignLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', 'd',... 'MarkerSize', 12,... 'LineWidth', 1.5,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'm',... 'LineStyle' ,'none'); obj.MatchedDataLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', '.',... 'MarkerSize',6,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'b',... 'LineStyle' ,'none'); obj.UnmatchedDataLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', '.',... 'MarkerSize',6,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'r',... 'LineStyle' ,'none'); % Add a property to this line that holds the data only cluster information mbcgui.hgclassesutil.addprop(obj.UnmatchedDataLine, 'DataOnlyClusterIndex'); mbcgui.hgclassesutil.addprop(obj.UnmatchedDesignLine, 'DesignOnlyClusterIndex'); obj.ExcludedDataLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', 'x',... 'MarkerSize',6,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'k',... 'LineStyle' ,'none'); obj.HighlightDataLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', 's',... 'MarkerSize', 12,... 'LineWidth', 1.5,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'm',... 'LineStyle' ,'none'); obj.DataDesignLine = line('Parent', obj.Axes,... 'XData', [],... 'YData', [],... 'Marker', '+',... 'MarkerSize',6,... 'ButtonDownFcn',{@i_pointClicked obj},... 'Color', 'm',... 'LineStyle' ,'none'); obj.ClusterPatches = {}; end function createActions(obj) %createActions creat view option actions obj.Options.Actions = [mbcgui.actions.StatefulAction(@obj.onSelectUnmatchedData,'&Select Unmatched Data','Select unmatched data',[]) mbcgui.actions.StatefulAction(@obj.onSelectUnmatchedDesign,'Select Unmatched D&esign','Select Unmatched data',[]) mbcgui.actions.ToggleAction(@obj.onShowLabels,'Show &Labels','Show Labels',[]) mbcgui.actions.StatefulAction(@obj.onSetTolerance,'T&olerances...','Set input tolerances',[]) ]; obj.Options.Actions(3).Selected = obj.LabelsVisible; obj.Options.Actions(4).Enabled = ~obj.MessageService.IsReadOnly; end %---------------------------------------- function pPostSetDataMessageService(obj, ~,~) %PPOSTSETDATAMESSAGESERVICE setup MessageService listeners % PPOSTSETDATAMESSAGESERVICE(OBJ, SRC, EVT) % Call the super pPostSetDataMessageService pPostSetDataMessageService@xregdatagui.AbstractDataView(obj); dms = obj.MessageService; dmsListeners = [... event.listener(dms, 'dmsDataTypeChanged', @obj.pdmsDataTypeChangedUpdate);... event.listener(dms, 'tssfActualDesignChanged', @obj.ptssfActualDesignChangedUpdate);... event.listener(dms, 'tssfClustersCreated', @obj.ptssfClustersCreatedUpdate);... event.listener(dms, 'tssfClustersChanged', @obj.ptssfClustersChangedUpdate);... event.listener(dms, 'CurrentClusterChanged', @obj.pUpdateCurrentClusterInfo);... ]; obj.Listeners = [obj.Listeners(:); dmsListeners(:)]; end % pPostSetDataMessageService %---------------------------------------- function pUpdateClusterVisibility(obj) %PUPDATECLUSTERVISIBILITY update cluster visibility % OUT = PUPDATECLUSTERVISIBILITY(IN) % Get the data tssf = obj.MessageService.TestplanSweepsetFilter; % Get information from tssf in one call - this is an optimisation [... clusters,... numDesignPoints,... numDataPoints,... matchedDesign,... unmatchedDesign,... matchedData,... unmatchedData,... excludedData,... dataInDesign... ] ... = get(tssf, { ... 'clusters' ... 'NumberDesignPoints' ... 'NumberDataPoints',... 'MatchedDesignInds' ... 'UnmatchedDesignInds' ... 'MatchedDataInds' ... 'UnmatchedDataInds' ... 'ExcludedDataInds' ... 'DataInDesignInds' ... }); numUnmatchedClusters = sum(strcmp({clusters(:).status}, 'unmatcheddata')) + sum(strcmp({clusters(:).status}, 'unmatcheddesign')); % Update the static test info display obj.StaticInfo.ListText = {... 'Design Points', num2str(numDesignPoints) ;... 'Matched Design', num2str(length(matchedDesign)) ;... 'Unmatched Design', num2str(length(unmatchedDesign)) ;... 'Data in Design', num2str(length(dataInDesign)) ;... 'Data Points', num2str(numDataPoints) ;... 'Matched Data', num2str(length(matchedData)) ;... 'Unmatched Data', num2str(length(unmatchedData)) ;... 'Excluded Data', num2str(length(excludedData));... 'Clusters', num2str(length(clusters) - numUnmatchedClusters);... 'Green Clusters', num2str(sum(strcmp({clusters(:).status}, 'same'))) ;... 'Blue Clusters', num2str(sum(strcmp({clusters(:).status}, 'moredata'))) ;... 'Red Clusters', num2str(sum(strcmp({clusters(:).status}, 'moredesign'))) ;... }; % Get the data indices of those clusters not being displayed unselectedData = [clusters(~obj.ClusterVisible).data]; % Get the design indices of those clusters not being displayed unselectedDesign = [clusters(~obj.ClusterVisible).design]; % Set the design line visibility obj.MatchedDesign = i_indexToLogical(setdiff(matchedDesign, unselectedDesign), numDesignPoints); obj.UnmatchedDesign = i_indexToLogical(setdiff(unmatchedDesign, unselectedDesign), numDesignPoints); % Set the data line visibility obj.MatchedData = i_indexToLogical(setdiff(matchedData, unselectedData), numDataPoints); obj.UnmatchedData = i_indexToLogical(setdiff(unmatchedData, unselectedData), numDataPoints); obj.ExcludedData = i_indexToLogical(setdiff(excludedData, unselectedData), numDataPoints); % Set the dataInDesign visibility % MOVE THIS SOME WHERE ELSE obj.DataDesign = i_indexToLogical(dataInDesign, numDataPoints); obj.pUpdateLabelVisibility; % Set the cluster visibility if any(obj.ClusterVisible) set([obj.ClusterPatches{obj.ClusterVisible}], 'Visible', 'on'); end if any(~obj.ClusterVisible) set([obj.ClusterPatches{~obj.ClusterVisible}], 'Visible', 'off'); end % Set the Cluster colors and zdata status = {clusters.status}; % More Design Points inds = strcmp('moredesign', status); col = [197 137 166]./255; if any(inds) set([obj.ClusterPatches{inds}],... 'Tag','MoreDesign',... 'FaceColor', col); end % More Data Points inds = strcmp('moredata', status); col = [107 185 214]./255; if any(inds) set([obj.ClusterPatches{inds}],... 'Tag','MoreData',... 'FaceColor', col); end % Same number of Points inds = strcmp('same', status) | strcmp('designonly', status); col = [188 231 191]./255; if any(inds) set([obj.ClusterPatches{inds}],... 'Tag','Same',... 'FaceColor', col); end % Ensure that highlights are set correctly obj.HighlightData(unselectedData) = false; obj.HighlightDesign(unselectedDesign) = false; end % pUpdateClusterVisibility end % possibly private or hidden methods (Access=protected) %---------------------------------------- function setVisible(obj,Vis) %setVisible set component visible % OUT = setVisible(IN) setVisible@xregdatagui.AbstractDataView(obj,Vis); % After setting this view visible on we need to ensure that the correct % lines are visible or invisible if strcmp(Vis, 'on') obj.pUpdateLineVisibility; obj.pUpdateClusterVisibility; end end % pPostSetVisible function onSelectUnmatchedData(obj, ~,~) %onSelectUnmatchedData action callback for select unmatched data % Get the current clusters clusters = get(obj.MessageService.TestplanSweepsetFilter, 'clusters'); % Find the data only clusters dataOnlyIndices = find(strcmp({clusters.status}, 'unmatcheddata')); if ~isempty(dataOnlyIndices) % Update the current cluster info with the data only cluster obj.pSendCurrentClusterChanged(dataOnlyIndices(end)); end end % i_selectUnmatchedData %------------------------------------------------------------------------ function onSelectUnmatchedDesign(obj, ~,~) %onSelectUnmatchedDesign action callback for select unmatched design % Get the current clusters clusters = get(obj.MessageService.TestplanSweepsetFilter, 'clusters'); % Find the data only clusters designOnlyIndices = find(strcmp({clusters.status}, 'unmatcheddesign')); if ~isempty(designOnlyIndices) % Update the current cluster info with the data only cluster obj.pSendCurrentClusterChanged(designOnlyIndices(end)); end end % i_selectUnmatchedDesign %------------------------------------------------------------------------ function onShowLabels(obj,src, ~) %onShowLabels show labels on cluster plot obj.LabelsVisible = src.Selected; end % onShowLabels % ------------------------------------------------------------------------------ function onSetTolerance(obj,~,~) %onSetTolerance redefine matching tolerances % Indicate this task might take a little time busy(obj.MessageService,'Changing Tolerances...'); % Get the data object to work on tssf = obj.MessageService.TestplanSweepsetFilter; % Call the tolerances GUI f = allchild(0); [OK, newTolerance] = toleranceEditDlg(tssf, f(1)); % Did the user click OK if OK % Set the new tolerances tssf = setTolerance(tssf, newTolerance); % Flush the event queue obj.MessageService.flushEventQueue(tssf); % Remove the pointer end % Remove the message and the pointer idle(obj.MessageService) end % onSetTolerance end end % classdef function design = i_setDesign(obj, design) % Check that the design is the correct length if length(design) ~= length(get(obj.MatchedDesignLine, 'XData')) error(message('mbc:xregdatagui:tssfclusterview:InvalidProperty')); end end % i_setDesign %------------------------------------------------------------------------ function data = i_setData(obj, data) % Check that the data is the correct length if length(data) ~= length(get(obj.MatchedDataLine, 'XData')) error(message('mbc:xregdatagui:tssfclusterview:InvalidProperty1')); end end % i_setData %------------------------------------------------------------------------ function clusters = i_setCluster(obj, clusters) % Check that the clusters is the correct length if length(clusters) ~= length(obj.ClusterPatches) error(message('mbc:xregdatagui:tssfclusterview:InvalidProperty2')); end end % i_setCluster function i_updateLineDisplay(prop, evt, line) % Take the logical array and create a double array that contains NaN where % the property is one. The extra 1 is to ensure that the zdata has the % correct length - we will only use 1:end-1 lPointsToKeep = get(evt.AffectedObject, prop.Name); zdata = zeros(size(lPointsToKeep)); zdata(~lPointsToKeep) = NaN; % Convert true to NaN and false to zero set(line, 'ZData', zdata(1:end)); end % i_updateLineDisplay %------------------------------------------------------------------------ function i_updateLabelDisplay(prop, evt, handleName) handles = get(evt.AffectedObject, handleName); % Create a logical variable that indicates which handles should be displayed lLabelsToDisplay = get(evt.AffectedObject, prop.Name); set(handles(lLabelsToDisplay), 'Visible', 'on'); set(handles(~lLabelsToDisplay), 'Visible', 'off'); end % i_updateLabelDisplay %------------------------------------------------------------------------ function i_updateLabelVisibility(~, evt) evt.AffectedObject.pUpdateLabelVisibility; end % i_updateLabelVisibility %------------------------------------------------------------------------ function i_updateClusterDisplay(~, evt) % Take the logical array and make the relevant patches visible or invisible evt.AffectedObject.pUpdateClusterVisibility; end % i_updateClusterDisplay %------------------------------------------------------------------------ function i_axesButtonDown(ax, ~, obj) % First dispatch to the container notify(obj, 'ButtonDown'); % Then call mv_zoom mv_zoom(ax); end % i_axesButtonDown %------------------------------------------------------------------------ function i_legendAxesButtonDown(~, ~, obj) % Dispatch to the container notify(obj, 'ButtonDown'); end % i_legendAxesButtonDown %------------------------------------------------------------------------ function i_checkClicked(~, ~, obj) obj.pUpdateLineVisibility; end % i_checkClicked %------------------------------------------------------------------------ function i_clusterCheckClicked(~, ~, obj) % Get the clusters clusters = get(obj.MessageService.TestplanSweepsetFilter, 'clusters'); % Changed which clusters need to be displayed obj.ClusterVisible = ismember({clusters.status}, obj.ClusterTypesToDisplay); end % i_clusterCheckClicked %------------------------------------------------------------------------ function i_graphFactorChangeCallback(~, ~, obj) % Update the line and patch data obj.pUpdateLineAndPatchData; end % i_graphFactorChangeCallback %------------------------------------------------------------------------ function i_pointClicked(~, ~, obj) % Get the current point on the axes cp = get(obj.Axes, 'CurrentPoint'); cp = cp(1,1:2); % X & Y values for data and design data = get(obj.MatchedDataLine, {'XData' 'YData'}); design = get(obj.MatchedDesignLine, {'XData' 'YData'}); % Get the axes limits axesLims = get(obj.Axes, {'XLim' 'YLim'}); % Calculate a distance metric that takes account of the current axes limits dataDist = abs((data{1} - cp(1))/diff(axesLims{1})) + abs((data{2} - cp(2))/diff(axesLims{2})); designDist = abs((design{1} - cp(1))/diff(axesLims{1})) + abs((design{2} - cp(2))/diff(axesLims{2})); % Which data points are visible dataVisible = ... (obj.MatchedData & strcmp(get(obj.MatchedDataLine, 'Visible'), 'on')) | ... (obj.ExcludedData & strcmp(get(obj.ExcludedDataLine, 'Visible'), 'on')) | ... (obj.UnmatchedData & strcmp(get(obj.UnmatchedDataLine, 'Visible'), 'on')) | ... (obj.DataDesign & strcmp(get(obj.DataDesignLine, 'Visible'), 'on')); % Which design points are visible designVisible = ... (obj.MatchedDesign & strcmp(get(obj.MatchedDesignLine, 'Visible'), 'on')) | ... (obj.UnmatchedDesign & strcmp(get(obj.UnmatchedDesignLine, 'Visible'), 'on')); % Find those that are within 1% of the axes limits and visible nearestData = find(dataDist' < 0.02 & dataVisible); nearestDesign = find(designDist' < 0.02 & designVisible); % Switch highlight the clicked points obj.HighlightData(nearestData) = ~obj.HighlightData(nearestData); obj.HighlightDesign(nearestDesign) = ~obj.HighlightDesign(nearestDesign); % Are any of the nearest highlighted? if any(obj.HighlightData(nearestData)) || any(obj.HighlightDesign(nearestDesign)) % Display info about all highlighted points dataIndex = find(obj.HighlightData); designIndex = find(obj.HighlightDesign); % Get the data object tssf = obj.MessageService.TestplanSweepsetFilter; % Get the names of the global factors but put 2 blank lines above names = char([{' '; ' '}; globalsignalnames(tssf)]); % Need to get all coods into strings and concatenate in blocks % saves playing around with tabbing the text to get alignment design = get(tssf, 'actualdesign'); % Ensure suitable output outStr = ''; % Iterate through all points "hit" for i = 1:length(dataIndex) dataStr = char('TEST', sprintf(' %.4g', obj.GlobalDataCache(dataIndex(i), end))); % Iterate through all coords for j = 1:size(obj.GlobalDataCache, 2)-1 thisStr = sprintf(' %.4g',obj.GlobalDataCache(dataIndex(i), j)); dataStr = char(dataStr,thisStr); end outStr = [outStr dataStr]; %#ok<AGROW> end % Iterate through all points "hit" for i = 1:length(designIndex) dataStr = char('INDEX', sprintf(' %.4g', designIndex(i))); % Iterate through all coords for j = 1:nfactors(design) thisStr = sprintf(' %.4g',design(designIndex(i), j)); dataStr = char(dataStr, thisStr); end outStr = [outStr dataStr]; %#ok<AGROW> end % Display the data patch xregDisplayDataPatch(obj.Axes, [names outStr], cp); end end % i_pointClicked function l = i_indexToLogical(i, outputSize) % Create the correct sized output l = false(outputSize, 1); % And turn the correct bits on l(i) = true; end % i_indexToLogical function i_patchClicked(~, ~, obj, thisClusterInd) % What sort of click? fig = ancestor(obj.Parent,'figure'); if strcmp(get(fig, 'SelectionType'), 'normal') % Update the current cluster info obj.pSendCurrentClusterChanged(thisClusterInd); else % Pass to the patch parent xregcallback(get(obj.Axes, 'ButtonDownFcn'), obj.Axes, []); end end % i_patchClicked