Why do I get Empty Plots during Optimization?

3 Ansichten (letzte 30 Tage)
B. Burak
B. Burak am 10 Aug. 2024
Kommentiert: Torsten am 14 Aug. 2024
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 Kommentare
B. Burak
B. Burak am 11 Aug. 2024
I added breakpoints to observe as you suggested, but under 'iter' plotRange returns 0x0 empty GraphicsPlaceholder array.
dpb
dpb am 11 Aug. 2024
Bearbeitet: dpb am 11 Aug. 2024
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()

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Voss
Voss am 14 Aug. 2024
Verschoben: Walter Roberson am 14 Aug. 2024
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 Kommentare
B. Burak
B. Burak am 14 Aug. 2024
Verschoben: Walter Roberson am 14 Aug. 2024
@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 am 14 Aug. 2024
Strange behaviour of "ga" for the problem at hand ...

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

dpb
dpb am 11 Aug. 2024
Bearbeitet: dpb am 12 Aug. 2024
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 Kommentare
Torsten
Torsten am 14 Aug. 2024
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 am 14 Aug. 2024
Bearbeitet: dpb am 14 Aug. 2024
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...

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Errorbars finden Sie in Help Center und File Exchange

Produkte


Version

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by