Why do I get Empty Plots during Optimization?

197 次查看(过去 30 天)
Inspired by custom plotting given here, for one-dimensional design variable case, I would like to generalize it to n-dimensional case. I wrote the following code to achieve that:
function state = gaPlotRangeND(options, state, flag)
% gaPlotRangeND Plots the mean and the range of the population for n-dimensions.
% STATE = gaPlotRangeND(OPTIONS, STATE, FLAG) plots the mean and the range
% (highest and the lowest) of individuals for each variable.
generation = state.Generation;
population = state.Population;
numVars = size(population, 2);
M = mean(population);
L = M - min(population);
U = max(population) - M;
switch flag
case 'init'
for i = 1:numVars
subplot(numVars, 1, i);
set(gca, 'xlim', [1, options.MaxGenerations + 1]);
plotRange = errorbar(generation, M(:, i), L(:, i), U(:, i));
set(plotRange, 'Tag', ['Var_' num2str(i)]);
title(['Range of Population, Mean for Variable ' num2str(i)], 'interp', 'none')
xlabel('Generation', 'interp', 'none')
end
case 'iter'
for i = 1:numVars
subplot(numVars, 1, i);
plotRange = findobj(get(gca, 'Children'), 'Tag', ['Var_' num2str(i)]);
newX = [get(plotRange, 'Xdata'), generation];
newY = [get(plotRange, 'Ydata'), M(:, i)];
newL = [get(plotRange, 'Ldata'), L(:, i)];
newU = [get(plotRange, 'Udata'), U(:, i)];
set(plotRange, 'Xdata', newX, 'Ydata', newY, 'Ldata', newL, 'Udata', newU);
end
end
end
When I run it for a simple two-dimensional test problem defined below, it does not work. It just outputs two empty subplots on top of each other during execution of genetic algorithm, and ends with a single empty plot. It is supposed to plot mean and range of population at each iteration for each variable, which is two in this case.
function y = booth_func(x)
y = (x(1) + 2 * x(2) - 7) ^ 2 + (2 * x(1) + x(2) - 5) ^ 2;
end
options = optimoptions('ga', 'PlotFcn', @gaPlotRangeND);
[x, fval] = ga(@booth_func, 2, [], [], [], [], [], [], [], options);
How can I solve this issue? What do I miss here?
  3 个评论
B. Burak
B. Burak 2024-8-11,13:12
I added breakpoints to observe as you suggested, but under 'iter' plotRange returns 0x0 empty GraphicsPlaceholder array.
dpb
dpb 2024-8-11,15:26
编辑:dpb 2024-8-11,15:28
This is probably going to be complicated, but...in
case 'init'
for i = 1:numVars
subplot(numVars, 1, i);
set(gca, 'xlim', [1, options.MaxGenerations + 1]);
...
You are creating multiple subplot axes and you have not saved the handle to any of them to later be able to address which of them you want...and, using gca simply will return whatever happens to be the current axes at the time it is called which will always be the last one referenced (which might be any one if user clicks on one during code execution).
At a barest minimum you'll need an array of axes handles to the various suplot axes objects and have to address each one in turn inside the iteration case code.
Not having the toolbox, no way can try anything specific here, but there's at least a starting point to try to work out the issues...
I'd suggest it also may be a place to use the tiledlayout instead of subplot()

请先登录,再进行评论。

采纳的回答

Voss
Voss 2024-8-14,16:25
移动:Walter Roberson 2024-8-14,20:32
Specifying the OutputFcn rather than the PlotFcn seems to provide something like what was intended.
options = optimoptions('ga', 'OutputFcn', @gaPlotRangeND);
[x, fval] = ga(@booth_func, 2, [], [], [], [], [], [], [], options)
ga stopped because it exceeded options.MaxGenerations.
x = 1x2
1.0052 3.0107
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
fval = 0.0012
function y = booth_func(x)
y = (x(1) + 2 * x(2) - 7) ^ 2 + (2 * x(1) + x(2) - 5) ^ 2;
end
function [state,options,optchanged] = gaPlotRangeND(options, state, flag)
% gaPlotRangeND Plots the mean and the range of the population for n-dimensions.
% [STATE,OPTIONS,OPTCHANGED] = gaPlotRangeND(OPTIONS, STATE, FLAG) plots the
% mean and the range (highest and the lowest) of individuals for each variable.
generation = state.Generation;
population = state.Population;
numVars = size(population, 2);
M = mean(population);
L = M - min(population);
U = max(population) - M;
persistent hAx hEB
switch flag
case 'init'
f = figure();
hAx=gobjects(size(M)); % prealloate for axes handles
hEB=gobjects(size(M)); % and for errorbars, too...
for i = 1:numVars
hAx(i)=subplot(numVars, 1, i, 'Parent', f); % create subplot, save handle to each
hEB(i)=errorbar(generation, M(:, i), L(:, i), U(:, i)); % save handle to ith EB
xlim(hAx(i),[1 options.MaxGenerations+1]);
title(hAx(i),['Range of Population, Mean for Variable ' num2str(i)])
xlabel(hAx(i),'Generation')
end
case 'iter'
for i = 1:numVars
newX=[hEB(i).XData, generation]; % return existing data
newY=[hEB(i).XData, M(:, i)];
newL=[hEB(i).YNegativeDelta,L(:, i)]; % must use correct field names...
newU=[hEB(i).YPositiveDelta,U(:, i)];
set(hEB(i),'Xdata',newX,'Ydata',newY,'YNegativeDelta',newL,'YPositiveDelta',newU);
end
end
optchanged = false;
end
  3 个评论
B. Burak
B. Burak 2024-8-14,20:05
移动:Walter Roberson 2024-8-14,20:33
@Voss -- This is amazing! I think your original reply deserves to be accepted as solution to my query. If you separately post it as an answer to this thread, I would be glad to accept it as answer.
Torsten
Torsten 2024-8-14,20:54
Strange behaviour of "ga" for the problem at hand ...

请先登录,再进行评论。

更多回答(1 个)

dpb
dpb 2024-8-11,18:23
编辑:dpb 2024-8-12,15:08
Per the above comments, at least a start would be something more like...
function state = gaPlotRangeND(options, state, flag)
% gaPlotRangeND Plots the mean and the range of the population for n-dimensions.
% STATE = gaPlotRangeND(OPTIONS, STATE, FLAG) plots the mean and the range
% (highest and the lowest) of individuals for each variable.
generation = state.Generation;
population = state.Population;
numVars = size(population, 2);
M = mean(population);
L = M - min(population);
U = max(population) - M;
switch flag
case 'init'
hAx=gobjects(size(M)); % prealloate for axes handles
hEB=gobjects(size(M)); % and for errorbars, too...
for i = 1:numVars
hAx(i)=subplot(numVars, 1, i); % create subplot, save handle to each
set(hAx(i), 'xlim', [1, options.MaxGenerations+1]);
hEB(i)=errorbar(generation, M(:, i), L(:, i), U(:, i)); % save handle to ith EB
title(hAx(i),['Range of Population, Mean for Variable ' num2str(i)])
xlabel(hAx(i),'Generation')
end
case 'iter'
for i = 1:numVars
newX=[hEB(i).XData, generation]; % return existing data
newY=[hEB(i).XData, M(:, i)];
newL=[hEB(i).YNegativeData,L(:, i)]; % must use correct field names...
newU=[hEB(i).YPositiveData,U(:, i)];
set(hEB(i),'Xdata',newX,'Ydata',newY,'YNegativeData',newL,'YPositiveData',newU);
end
end
end
Should at least have a chance...
  34 个评论
Torsten
Torsten 2024-8-14,15:33
Same for option 2:
options = optimoptions('ga', 'PlotFcn', @gaPlotRangeND);
[x, fval] = ga(@booth_func, 2, [], [], [], [], [], [], [], options);
Unrecognized method, property, or field 'XData' for class 'matlab.graphics.GraphicsPlaceholder'.

Error in solution>gaPlotRangeND (line 34)
newX=[hEBi.XData, generation]; % return existing data

Error in gadsplot>callOnePlotFcn (line 228)
optimValues = plotfcn(varargin{1:end});

Error in gadsplot (line 165)
[state,optimValues] = callOnePlotFcn(fname,plotNames{i},state,options.OutputPlotFcnOptions,optimValues,flag,args{i}{:});

Error in gaunc (line 116)
state = gadsplot(options,state,currentState,gaPlotTitle);

Error in ga (line 417)
[x,fval,exitFlag,output,population,scores] = gaunc(FitnessFcn,nvars, ...
function y = booth_func(x)
y = (x(1) + 2 * x(2) - 7) ^ 2 + (2 * x(1) + x(2) - 5) ^ 2;
end
function state = gaPlotRangeND(options, state, flag)
% gaPlotRangeND Plots the mean and the range of the population for n-dimensions.
% STATE = gaPlotRangeND(OPTIONS, STATE, FLAG) plots the mean and the range
% (highest and the lowest) of individuals for each variable.
generation = state.Generation;
population = state.Population;
numVars = size(population, 2);
M = mean(population);
L = M - min(population);
U = max(population) - M;
switch flag
case 'init'
hAx=gobjects(size(M)); % prealloate for axes handles
hEB=gobjects(size(M)); % and for errorbars, too...
for i = 1:numVars
hAx(i)=subplot(numVars, 1, i); % create subplot, save handle to each
hold(hAx(i),'on') % hold on to add more later
xlim(hAx(i),[1 options.MaxGenerations+1])
hEB(i)=errorbar(generation, M(:, i), L(:, i), U(:, i)); % save handle to ith EB
title(hAx(i),['Range of Population, Mean for Variable ' num2str(i)])
xlabel(hAx(i),'Generation')
end
case 'iter'
for i = 1:numVars
hAxi=subplot(numVars,1,i); % the axes handle
hEBi=findobj(hAxi,'Type','ErrorBar'); % find the EB object
newX=[hEBi.XData, generation]; % return existing data
newY=[hEBi.XData, M(:, i)];
newL=[hEBi.YNegativeData,L(:, i)]; % must use correct field names...
newU=[hEBi.YPositiveData,U(:, i)];
set(hEBi,'Xdata',newX,'Ydata',newY,'YNegativeData',newL,'YPositiveData',newU);
end
end
end
dpb
dpb 2024-8-14,15:39
编辑:dpb 2024-8-14,16:02
That's truly bizarre! ga has to be mucking around with the HG environment behind the scenes...
I don't suppose you put a breakpoint into the 'iter' case to see what gca returns as compared to the saved hAx, did you? It's truly mind-boggling that those are really no longer valid handles to the initially-created axes...

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Errorbars 的更多信息

产品


版本

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by