Plot gaplotdistance in one plot for multiple runs of genetic algorithm

Dear all,
With the code below I managed to run the genetic algorithm multiple times.
gprMdl2 = fitrgp(X,Y1,'KernelFunction','squaredexponential','OptimizeHyperparameters','auto','HyperparameterOptimizationOptions',struct('AcquisitionFunctionName','expected-improvement-plus'));
for i = 1:3
options = optimoptions('ga','CrossoverFrac',0.9,'PopulationSize',50,'StallGen',50,'Generations',70,'PlotFcn', {'gaplotbestf','gaplotdistance'});
fun = @(X) [abs(((predict(gprMdl2,X)-MFR_exp)/MFR_exp))];
[x_opt, Obj, exitflag,output] = ga(fun,2,[],[],[],[],[0.1 0.1], [0.9 0.9],[],[],options);
end
With PlotFcn I will get the plot of the fitness value vs genration and the average distance vs generation (as shown below). How can I combine the plots of each run into one plot?

7 Comments

Hello,
You can make your own OutputFcn for ga that does what you want. You can do the plotting with plotyy function.
Dear Mario,
I saw indeed your suggestion also in order post. I tried to save the variables that create the plot by adjusting the gaplotdistance.m file, but I have haven't been able to do that succesfully.
function state = gaplotdistance(options,state,flag)
%GAPLOTDISTANCE Averages several samples of distances between individuals.
% STATE = GAPLOTDISTANCE(OPTIONS,STATE,FLAG) plots an averaged distance
% between individuals.
%
% Example:
% Create an options structure that uses GAPLOTDISTANCE
% as the plot function
% options = optimoptions('ga','PlotFcn',@gaplotdistance);
%
% (Note: If calling gamultiobj, replace 'ga' with 'gamultiobj')
% Copyright 2003-2015 The MathWorks, Inc.
samples = 20;
choices = ceil(sum(options.PopulationSize) * rand(samples,2));
switch flag
case 'init'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
save plotdistance.mat distance samples
end
plotDist = plot(state.Generation,distance/samples,'.');
set(gca,'xlimmode','manual','zlimmode','manual', ...
'alimmode','manual')
set(gca,'xlim',[1,options.MaxGenerations]);
set(plotDist,'Tag','gaplotdistance');
xlabel('Generation','interp','none');
ylabel('Average Distance');
title('Average Distance Between Individuals','interp','none')
case 'iter'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
end
plotDist = findobj(get(gca,'Children'),'Tag','gaplotdistance');
newX = [get(plotDist,'Xdata') state.Generation];
newY = [get(plotDist,'Ydata') distance/samples];
set(plotDist,'Xdata',newX,'Ydata',newY);
end
Do you have any suggestions on how make my own OutputFcn to create the respective plots?
First, backup the original gaplotdistance.m file and create your own, under different name and call that one.
In the case of PlotFcn, optimisation solver creates a figure on its own, outside of plot function, so in case of OutputFcn, you should do it prior to calling the solver and set a name or a tag so you can find it in the OutputFcn.
OptimAxes = axes(1)
set(OptimAxes, 'Name', 'CustomOptimPlot')
Regarding the custom output function: Actually plotyy is not recommended anymore, yyaxis should be used. In this example right yyaxis is considered to be gaplotbestf as it has additional case 'done'.
function state = gaplotdistance(options,state,flag)
%GAPLOTDISTANCE Averages several samples of distances between individuals.
% STATE = GAPLOTDISTANCE(OPTIONS,STATE,FLAG) plots an averaged distance
% between individuals.
%
% Example:
% Create an options structure that uses GAPLOTDISTANCE
% as the plot function
% options = optimoptions('ga','PlotFcn',@gaplotdistance);
%
% (Note: If calling gamultiobj, replace 'ga' with 'gamultiobj')
% Copyright 2003-2015 The MathWorks, Inc.
% Getting the handle for axes *** test if you can move this in case 'init'
Axes = findobj('Name', 'CustomOptimPlot')
% options for left - gaplotdistance.m
samples = 20;
choices = ceil(sum(options.PopulationSize) * rand(samples,2));
% options for right - gaplotbestf
if size(state.Score,2) > 1
msg = getString(message('globaloptim:gaplotcommon:PlotFcnUnavailable','gaplotbestf'));
title(msg,'interp','none');
return;
end
switch flag
case 'init'
yyaxis left
% Code for first PlotFcn
yyaxis right
% Code for second PlotFcn
case 'iter'
yyaxis left
% Code for first PlotFcn
yyaxis right
% Code for second PlotFcn
case 'done'
yyaxis right
% Code for second PlotFcn
end
There might be some options that interfere with each other, like titles and labels, so consider that as well.
Edit: I will update comment later on the saving the variables
I tried saving the distance values with the code below:
case 'iter'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
test.distance(i) = distance;
save(horzcat('test',int2str(i),'.mat'),'test')
end
Then the last value of distance devided by number of samples gives the average distance value only for the last generation (which is generation). But I don't know how the save the distance value for all generations.
Unfortunately, I am not familiar with ga, if you're looking for all values of variable d, throughout all optimisations, this would be the way to do it.
function state = customgaplotdistance(options,state,flag)
%GAPLOTDISTANCE Averages several samples of distances between individuals.
% STATE = GAPLOTDISTANCE(OPTIONS,STATE,FLAG) plots an averaged distance
% between individuals.
%
% Example:
% Create an options structure that uses GAPLOTDISTANCE
% as the plot function
% options = optimoptions('ga','PlotFcn',@gaplotdistance);
%
% (Note: If calling gamultiobj, replace 'ga' with 'gamultiobj')
% Copyright 2003-2015 The MathWorks, Inc.
persistent testdist % change number 1
testdist(1,:) = [0 0]; % initialising the value
samples = 20;
choices = ceil(sum(options.PopulationSize) * rand(samples,2));
switch flag
case 'init'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
testdist(end+1,:) = d; % change number 2
end
plotDist = plot(state.Generation,distance/samples,'.');
set(gca,'xlimmode','manual','zlimmode','manual', ...
'alimmode','manual')
set(gca,'xlim',[1,options.MaxGenerations]);
set(plotDist,'Tag','gaplotdistance');
xlabel('Generation','interp','none');
ylabel('Average Distance');
title('Average Distance Between Individuals','interp','none')
case 'iter'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
testdist(end+1,:) = d; % change number 3
assignin('base', 'testdist', testdist) % it might be better to assign it and save it from the main file
% save('testdist.mat', 'testdist') % as it will save the file 3000+ times
end
plotDist = findobj(get(gca,'Children'),'Tag','gaplotdistance');
newX = [get(plotDist,'Xdata') state.Generation];
newY = [get(plotDist,'Ydata') distance/samples];
set(plotDist,'Xdata',newX,'Ydata',newY);
end
I changed the following line of code
testdist(end+1,:) = distance
After that I devided every value of the testdist by the number of samples, which is 20. That is how you get the values of the average distance. Than I filterd out the average distance values of every optimization run and put each run in a seperate column. Every 20th value corresponds to the value in the column corresponds to the average distance value in the plot.
A1 = testdis(:,1)/20;
A2 = zeros(1281,3);
A2(1:1281,1)=A1(1:1281,1);
A2(2:1081,2)=A1(1282:2361,1);
A2(2:1221,3)=A1(2362:3581,1);
A3 = A2(41:20:1221,3);
A4 = A2(41:20:1081,2);
A5 = A2(41:20:1281,1);
The resulting plot is shown below
I want to thank you for your help. Can you post your comment as an answer so I can accept it.
Great to hear it works! Actually, I put the distance first, and then I thought, but it doesn't show every single distance out there, so I set it back to d.

Sign in to comment.

 Accepted Answer

Edited according to the change of testdist. More details in comments.
function state = customgaplotdistance(options,state,flag)
%GAPLOTDISTANCE Averages several samples of distances between individuals.
% STATE = GAPLOTDISTANCE(OPTIONS,STATE,FLAG) plots an averaged distance
% between individuals.
%
% Example:
% Create an options structure that uses GAPLOTDISTANCE
% as the plot function
% options = optimoptions('ga','PlotFcn',@gaplotdistance);
%
% (Note: If calling gamultiobj, replace 'ga' with 'gamultiobj')
% Copyright 2003-2015 The MathWorks, Inc.
persistent testdist % change number 1
testdist(1,:) = [0 0]; % initialising the value
samples = 20;
choices = ceil(sum(options.PopulationSize) * rand(samples,2));
switch flag
case 'init'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
testdist(end+1,:) = distance; % change number 2
end
plotDist = plot(state.Generation,distance/samples,'.');
set(gca,'xlimmode','manual','zlimmode','manual', ...
'alimmode','manual')
set(gca,'xlim',[1,options.MaxGenerations]);
set(plotDist,'Tag','gaplotdistance');
xlabel('Generation','interp','none');
ylabel('Average Distance');
title('Average Distance Between Individuals','interp','none')
case 'iter'
population = state.Population;
distance = 0;
for i = 1:samples
d = population(choices(i,1),:) - population(choices(i,2),:);
distance = distance + sqrt( sum ( d.* d));
testdist(end+1,:) = distance; % change number 3
assignin('base', 'testdist', testdist) % it might be better to assign it and save it from the main file
% save('testdist.mat', 'testdist') % as it will save the file 3000+ times
end
plotDist = findobj(get(gca,'Children'),'Tag','gaplotdistance');
newX = [get(plotDist,'Xdata') state.Generation];
newY = [get(plotDist,'Ydata') distance/samples];
set(plotDist,'Xdata',newX,'Ydata',newY);
end
Filtering out each ga run is done by lines below
A1 = testdis(:,1)/20;
A2 = zeros(1281,3);
A2(1:1281,1)=A1(1:1281,1);
A2(2:1081,2)=A1(1282:2361,1);
A2(2:1221,3)=A1(2362:3581,1);
A3 = A2(41:20:1221,3);
A4 = A2(41:20:1081,2);
A5 = A2(41:20:1281,1);

More Answers (0)

Categories

Products

Release

R2020a

Asked:

on 28 Oct 2020

Edited:

on 31 Oct 2020

Community Treasure Hunt

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

Start Hunting!