- object used to create detailed plots of SOS optimization copyright 2009-2012 Blair Armstrong, Christine Watson, David Plaut This file is part of SOS SOS is free software: you can redistribute it and/or modify it for academic and non-commercial purposes under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. For commercial or for-profit uses, please contact the authors (sos@cnbc.cmu.edu). SOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
0001 % - object used to create detailed plots of SOS optimization 0002 % 0003 % copyright 2009-2012 Blair Armstrong, Christine Watson, David Plaut 0004 % 0005 % This file is part of SOS 0006 % 0007 % SOS is free software: you can redistribute it and/or modify 0008 % it for academic and non-commercial purposes 0009 % under the terms of the GNU General Public License as published by 0010 % the Free Software Foundation, either version 3 of the License, or 0011 % (at your option) any later version. For commercial or for-profit 0012 % uses, please contact the authors (sos@cnbc.cmu.edu). 0013 % 0014 % SOS is distributed in the hope that it will be useful, 0015 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 % GNU General Public License for more details. 0018 0019 % You should have received a copy of the GNU General Public License 0020 % along with SOS (see COPYING.txt). 0021 % If not, see <http://www.gnu.org/licenses/>. 0022 0023 classdef sosPlots < handle 0024 %% plots detailed history data 0025 % 0026 % This class provides support for creating plots of various metrics 0027 % related to the optimization process. 0028 % plots various metrics related to the optimization process 0029 % Specifically, the following items are recorded: 0030 % 0031 % creates plots for several optimization parameters, as follows: 0032 % - cost 0033 % - deltaCost 0034 % - temperature 0035 % - pFlipHistory 0036 % - sosStatTestpvals (for all stat tests in the sos Object) 0037 % 0038 % This code uses the plt library by Paul Mennen (may 11, 2010 version) 0039 % and also takes some of its implementational inspiration 0040 % from the demos therein. 0041 % 0042 % This class also inherits from the handle CLASS to gain standard 0043 % object-oriented behavior 0044 % 0045 % PROPERTIES 0046 % sosObj % the sos object the plots are associated with 0047 % histObj % pointer to history object in SOS object that is to be displayed 0048 % hFig % handle to the plot graphic object 0049 % pFig % pointer to traces in figure 0050 % dispIt % range of iterations to show on the plots at any one time 0051 % startIt % iteration that the plot was created at (plots from then on after) 0052 % startRow % starting row when plotObj was created from which information will begin being plotted 0053 % pvalTestNames % names of the stat tests to plot. these names are stored seperately than those in histObj so as to be able to discern if the stat tests to plot have changed. 0054 % curXLim % range limit for x-axis 0055 % curCostYLim % range limit for Cost Y axis 0056 % curdeltaCostYLim % range limit for deltaCost Y axis 0057 % curTempYLim % range limit for tempreature Y axis 0058 % 0059 % METHODS 0060 % sosPlots(sosObj,histObj,dispIt,startIt) % constructor 0061 % updatePlots() % updates the plot based on the most recent history information 0062 % namesBTN(~,~,t) % call linked to names button that toggles display of stat test names. 0063 % namesBTN(obj,~,~,t) % call linked to names button that toggles display of stat test names. 0064 0065 %% PROPERTIES 0066 properties 0067 sosObj % the sos object the plots are associated with 0068 histObj % pointer to history object in SOS object that is to be displayed 0069 hFig % handle to the plot graphic object 0070 pFig % pointer to traces in figure 0071 dispIt % range of iterations to show on the plots at any one time 0072 startIt % iteration that the plot was created at (plots from then on after) 0073 startRow % starting row when plotObj was created from which information will begin being plotted 0074 pvalTestNames % names of the stat tests to plot. these names are stored seperately than those in histObj so as to be able to discern if the stat tests to plot have changed. 0075 curXLim % range limit for x-axis 0076 curCostYLim % range limit for Cost Y axis 0077 curdeltaCostYLim % range limit for deltaCost Y axis 0078 curTempYLim % range limit for tempreature Y axis 0079 end 0080 0081 %% METHODS 0082 methods 0083 0084 %% obj = sosPlots(sosObj,histObj,dispIt,startIt) CONSTRUCTOR 0085 function obj = sosPlots(sosObj,histObj,dispIt,startIt) 0086 % creates plots of optimization history metrics 0087 % 0088 % PARAMETERS: 0089 % sosObj % sos object associated with the plot 0090 % histObj % history object whose data will be plotted 0091 % dispIt % default number of iterations to display on the plot at any one time 0092 % startit % iteration that the plot was started on (plotting begins thereafter) 0093 0094 % validate inputs 0095 if exist('dispIt','var') == 0 0096 dispIt = 100000; 0097 else 0098 validateattributes(dispIt, {'numeric'}, ... 0099 {'scalar', 'integer', 'positive', '>', 0}); 0100 end 0101 0102 obj.sosObj = sosObj; 0103 obj.histObj = histObj; 0104 obj.dispIt = dispIt; 0105 obj.startIt = startIt; 0106 obj.pvalTestNames = obj.histObj.pvalTestNames; 0107 0108 % begin the plot creation process: 0109 0110 % prepare abbreviated trace names for p-vals 0111 shortNames = {}; 0112 for i=1:length(obj.pvalTestNames) 0113 shortNames = [shortNames ; strcat('Test #',num2str(i))]; %#ok<AGROW> 0114 end 0115 0116 0117 minX = obj.startIt; 0118 0119 % find the row in the history that the starting iteration 0120 % appears in 0121 obj.startRow = 1; 0122 for i=1:length(obj.histObj.itHistory) 0123 if obj.histObj.itHistory(i) < minX 0124 obj.startRow = i+1; 0125 else 0126 break; 0127 end 0128 end 0129 0130 %need to include NaN's for as many traces as there are 0131 %statTests when first buiding the stat test. There also needs 0132 %to be at least 1 stat test so that the stat test plot is 0133 %created, even if it will ultimately be empty. 0134 numStatTests = length(obj.pvalTestNames); 0135 0136 initStatTraces = nan(1,max(numStatTests,1)); 0137 0138 % create initial x-limits based on the starting iteration and 0139 % the number of iterations to keep on the screen. 0140 obj.curXLim = [minX minX+obj.dispIt]; 0141 0142 % set the initial ranges for the y axis of the plots 0143 0144 % create a small initial range on the axes; The intent is to 0145 % have this range be overridden with the real data range 0146 % because that range will be bigger than smallNum. This is a 0147 % somewhat awkward bit of the code that hopefully won't be too 0148 % troublesome, but is apparently needed because the plot must 0149 % take two real value min and max bounds such that min<max, and 0150 % more sophisticated overriding code probably isn't worth it 0151 % presently. 0152 smallNum = 0.0000001; 0153 0154 % range of probabilities is always 0-1 0155 probYLim = [0 1]; 0156 0157 % cost and deltaCost can have both positive and negative 0158 % values, so make their initial ranges symmetric around 1 0159 obj.curdeltaCostYLim = [-smallNum smallNum]; 0160 obj.curCostYLim = [-smallNum smallNum]; 0161 %temperature can only be negative, have it be bounded by zero 0162 obj.curTempYLim = [0 smallNum]; 0163 0164 % create empty initial traces for as many traces as will 0165 % ultimately be in the plot. 0166 initYs = [NaN,NaN,NaN,NaN,initStatTraces]; 0167 0168 % have each individual data point marked with a star, below. 0169 % There are as many stars for trace marks as there are traces, 0170 % above. 0171 mark = ''; 0172 for j=1:length(initYs) 0173 mark = strcat(mark,'*'); 0174 end 0175 0176 % create the figure. 0177 obj.pFig = plt(NaN,initYs, ... % create NaN's for x-axis and y-axis traces 0178 'FigName','plotObj', ... % name of figure 0179 'SubPlot',[20 20 20 20 20] ... % percent of figure occupied by each subplot 0180 ,'Xlim',obj.curXLim, ... % set initial Xlimits 0181 'Options','Ticks',... init plots /w tick marks 0182 'Options','-Ylog',... % remove logy transform of y axis 0183 'Options','-Xlog',...% remove logx transform of xaxis 0184 'Options','-Rotate',... % 2-d plots don't need 3d rotation 0185 'Options','-Help',... % remove (non-existent) help access 0186 'Options','S',... % enable x-axis slider 0187 'ENApre', [0 0],... % disables unit scaling and uses scientific notation. 0188 'TraceID',shortNames,... % name all of the stat test traces 0189 'Markers',mark,... % add marks for each actual value on the plot that is not interpolated 0190 'LabelX','Iteration',... 0191 'LabelY',{'p-val','p(swap)','deltaCost','cost','temperature'},... 0192 'FigBKc',[0.3 0.3 0.3]); % sets plot bg color to dark grey 0193 0194 % get a pointer to the newly created figure. 0195 obj.hFig = gcf(); 0196 0197 %update the axes for all of the other plots to their 0198 %default bounds 0199 hAxes = getappdata(obj.hFig,'axis'); 0200 0201 set(hAxes(1),'Ylim',probYLim); % pval plot 0202 set(hAxes(2),'Ylim',probYLim); % p(swap) plot 0203 set(hAxes(3),'Ylim',obj.curdeltaCostYLim); % deltaCost 0204 set(hAxes(4),'Ylim',obj.curCostYLim); % cost 0205 set(hAxes(5),'Ylim',obj.curTempYLim); % temperature 0206 0207 0208 % create a message listing the names of all the stat tests 0209 dispMsg = sprintf('\nThe names of the stats tests are:\n\n'); 0210 0211 for i=1:length(obj.pvalTestNames) 0212 dispMsg = sprintf(' %s#%s: %s\n',dispMsg,num2str(i),... 0213 obj.pvalTestNames{i}); 0214 end 0215 0216 %add the 'names' button that displays the plot names 0217 % snippet inspired from plt demo trigplt.m by Paul Mennen 0218 plot.names = text(2,3,dispMsg,... % first 2 params are x,y offset 0219 'HorizontalAlignment','left',... 0220 'BackgroundColor',[0.5 0.5 0.5],... 0221 'EdgeColor','red','Color','black','Editing','off'); 0222 0223 % try to adjust the color (plt seems to override this on 0224 % initialization though). 0225 set(plot.names,'units','norm','color',[1 .7 .7]); 0226 0227 % add the names button 0228 uicontrol('string','Names','pos',[5 500 50 20],... 0229 'CallBack',{@obj.namesBTN,plot.names}); 0230 0231 % hide names on plot creation. 0232 set(plot.names,'visible','off'); 0233 0234 % if the plot is closed via the plot's gui, have it delete the 0235 % plotObj in the main SOS variable: 0236 set(obj.hFig, 'closeReq',strcat('delete(',num2str(obj.hFig),... 0237 '); mySOS.plotObj = {}; ')); 0238 0239 0240 % ensure that the whole plot has been updated. 0241 drawnow; 0242 0243 verbosePrint('Plotting detailed optimization history...', ... 0244 'sosPlots_constructor_end'); 0245 0246 end % constructor 0247 0248 0249 %% function updatePlots() METHOD 0250 function updatePlots(obj) 0251 % updates the plot based on the most recent history information 0252 0253 %number of data points in the history 0254 histLength = length(obj.histObj.itHistory); 0255 0256 if histLength == 0 0257 error('updatePlots() was called but detailed optimization was not stored'); 0258 else 0259 lastPoint = histLength; 0260 firstPoint = obj.startRow; 0261 0262 % find the number of iterations on the last datapoint 0263 lastIt = max(obj.dispIt,obj.histObj.itHistory(length(obj.histObj.itHistory))); 0264 firstIt = max(0,lastIt-obj.dispIt); 0265 0266 % check to see if the x-axes need to be updated. This 0267 % should only happen if there are at least two datapoints; 0268 newXLim = [firstIt lastIt]; 0269 0270 % only try updating the original axes if more than one data 0271 % point is present; otherwise the initial value will be 0272 % fine 0273 if firstPoint < lastPoint && ... 0274 (newXLim(1) ~= obj.curXLim(1) || ... 0275 newXLim(2) ~= obj.curXLim(2)) 0276 hAxes = getappdata(obj.hFig,'axis'); 0277 obj.curXLim = newXLim; 0278 0279 for i=1:5 % for every subplot 0280 set(hAxes(i),'Xlim', ... 0281 obj.curXLim); 0282 end 0283 end 0284 0285 % update datapoints on the p-val plot 0286 for i=1:length(obj.pvalTestNames) 0287 set(obj.pFig(i),'x',obj.histObj.itHistory(firstPoint:lastPoint), ... 0288 'y',obj.histObj.pvalHistory(firstPoint:lastPoint,i)); 0289 end 0290 0291 0292 nextIndex = i+1; 0293 0294 % update pFlip 0295 set(obj.pFig(nextIndex),'x',obj.histObj.itHistory(firstPoint:lastPoint), ... 0296 'y',obj.histObj.pFlipHistory(firstPoint:lastPoint)); 0297 0298 0299 % from hereon out, it may be necessary to update the YLim 0300 % since they are not bounded 0301 0302 % update deltaCost Axis 0303 obj.curdeltaCostYLim = obj.updateAxis(... 0304 obj.histObj.deltaCostHistory(lastPoint), ... 0305 obj.curdeltaCostYLim, 3); 0306 0307 % update deltaCost plot 0308 nextIndex = nextIndex+1; 0309 set(obj.pFig(nextIndex),'x',obj.histObj.itHistory(firstPoint:lastPoint), ... 0310 'y',obj.histObj.deltaCostHistory(firstPoint:lastPoint)); 0311 0312 0313 % same for cost 0314 obj.curCostYLim = obj.updateAxis(... 0315 obj.histObj.costHistory(lastPoint), ... 0316 obj.curCostYLim, 4); 0317 0318 nextIndex = nextIndex+1; 0319 set(obj.pFig(nextIndex),'x',obj.histObj.itHistory(firstPoint:lastPoint), ... 0320 'y',obj.histObj.costHistory(firstPoint:lastPoint)); 0321 0322 % same for temp 0323 0324 obj.curTempYLim = obj.updateAxis(... 0325 obj.histObj.tempHistory(lastPoint), ... 0326 obj.curTempYLim, 5); 0327 0328 nextIndex = nextIndex+1; 0329 set(obj.pFig(nextIndex),'x',obj.histObj.itHistory(firstPoint:lastPoint), ... 0330 'y',obj.histObj.tempHistory(firstPoint:lastPoint)); 0331 0332 0333 end % if histLength == 0 0334 0335 drawnow; 0336 0337 end % updatePlots 0338 0339 0340 0341 0342 0343 0344 %% namesBTN(~,~,t) METHOD 0345 function namesBTN(obj,~,~,t) 0346 % call linked to names button that toggles display of stat test 0347 % names. 0348 % 0349 % PARAMETERS: 0350 % ~ -- standard graphic parameters for button calls - not used. 0351 % t - pionter to text object that displays the names 0352 % 0353 % snippet inspried from plt demo trigplt.m by Paul Mennen, in 0354 % the plt package demos 0355 0356 dispMsg = sprintf('\nThe names of the stats tests are:\n'); 0357 0358 for i=1:length(obj.pvalTestNames) 0359 dispMsg = sprintf('%s#%s: %s\n',dispMsg,num2str(i), ... 0360 obj.pvalTestNames{i}); 0361 end 0362 0363 v = get(t(1),'visible'); 0364 if v(2)=='n'; v='off'; else v='on'; end; 0365 set(t,'visible',v); 0366 0367 drawnow; 0368 0369 end 0370 0371 end % methods 0372 0373 0374 %% METHODS (Access = private) 0375 methods (Access = private) 0376 0377 %% curLim = updateAxis(x,curLim,subPlotIndex) METHOD 0378 function curLim = updateAxis(obj,x,curLim,subPlotIndex) 0379 % determines whether the y-axis for a given plot need to be 0380 % updated based on the new data, which may have changed the 0381 % min/max values for the axis. 0382 % 0383 % PARAMETERS: 0384 % x - new data point in history array 0385 % curLim - 2-entry array containing the current min/max vals 0386 % subPlotIndex - index of subplot in hFig handle obj 0387 0388 update = false; 0389 0390 if x < curLim(1) 0391 curLim(1) = x; 0392 update = true; 0393 end 0394 0395 if x > curLim(2) 0396 curLim(2) = x; 0397 update = true; 0398 end 0399 0400 if update == true 0401 hAxes = getappdata(obj.hFig,'axis'); 0402 set(hAxes(subPlotIndex),'Ylim', ... 0403 curLim); 0404 end 0405 0406 end 0407 end 0408 0409 end 0410 0411