scatter or gscatter specify marker and color depending on row

13 views (last 30 days)
I have different tables with measurements that I want to represent in a scatter plot. One sample is given in testfile.mat. The goal is to allocate color and marker shape to the two grouping variables.
I test with gscatter and with scatter. With gscatter I could manually adjust the result for each table but that would be quite some work.
With the scatter allown was the idea to have the color and marker included in the table and call the color and marker for each row.
Maybe it would work if I write a function for simple scatter plot and call it with row function. Will try this tomorrow. But maybe someone has a better and simpler idea.
Thanks for your input.
Desiree
load testfile.mat
testTable
testTable = 33×4 table
x-axis y-axis color marker __________ ______ _____ ______ 9.4049e+05 1.04 3 A-X 1.0665e+06 -4.83 3 A-Y 6.8489e+06 -14.57 3 A-Y 1.516e+07 -3.04 3 A-Z 1.53e+07 0.12 3 B-X 1.5664e+07 -8.01 3 B-X 1.5664e+07 -6.01 3 B-X 1.5664e+07 -4.4 3 B-X 1.5664e+07 -1.57 3 B-X 1.7183e+07 -2.72 3 B-Y 1.7185e+07 -12.38 3 B-Y 1.026e+06 0.04 4 A-X 1.0267e+07 7.28 4 A-Y 1.1133e+07 -9.15 4 A-Y 1.1749e+07 -5.82 4 A-Y 1.516e+07 5.43 4 A-Z
%% test 1 with gscatter
col = [1,0.6,0;0,1,0;0,0,1;1,0,0];
mrk = '....ssss^^^^ooooddddvvvv';
gscatter(testTable.("x-axis"),testTable.("y-axis"),{testTable.marker, testTable.color},col,mrk)
xlabel("Frequency [Hz]")
ylabel(["Magnetic field"; "strength [dB\muA/m]"])
legend('Location','northeastoutside')
%of course I can manually adjust to each table the amount of markes mkr but
%I want to run the same script on several tables with different amount of
%shapes and colors
%% test 2 with adding columns for color and marker
%% add color column
%% 1 2 3 4 5 6
%% white yellow orgnge green blue red
%% 'y' [1 0.6 0] 'g' 'b' 'r'
colorNew = rowfun(@(col){ChangeColor(col)}, testTable,"InputVariables","color","OutputVariableNames",'colorNew');
%% add marker column
%% AX point '.'
%% AY square 's'
%% AZ upwards triangle '^'
%% BX circle 'o'
%% BY diamond 'd'
%% BZ downward triangle 'v'
markerNew = rowfun(@(marker){ChangeMarker(marker)}, testTable,"InputVariables","marker","OutputVariableNames",'markerNew');
testTable= [testTable,colorNew,markerNew]
testTable = 33×6 table
x-axis y-axis color marker colorNew markerNew __________ ______ _____ ______ ______________ _________ 9.4049e+05 1.04 3 A-X {[1 0.6000 0]} {'.'} 1.0665e+06 -4.83 3 A-Y {[1 0.6000 0]} {'s'} 6.8489e+06 -14.57 3 A-Y {[1 0.6000 0]} {'s'} 1.516e+07 -3.04 3 A-Z {[1 0.6000 0]} {'^'} 1.53e+07 0.12 3 B-X {[1 0.6000 0]} {'o'} 1.5664e+07 -8.01 3 B-X {[1 0.6000 0]} {'o'} 1.5664e+07 -6.01 3 B-X {[1 0.6000 0]} {'o'} 1.5664e+07 -4.4 3 B-X {[1 0.6000 0]} {'o'} 1.5664e+07 -1.57 3 B-X {[1 0.6000 0]} {'o'} 1.7183e+07 -2.72 3 B-Y {[1 0.6000 0]} {'d'} 1.7185e+07 -12.38 3 B-Y {[1 0.6000 0]} {'d'} 1.026e+06 0.04 4 A-X {[ 0 1 0]} {'.'} 1.0267e+07 7.28 4 A-Y {[ 0 1 0]} {'s'} 1.1133e+07 -9.15 4 A-Y {[ 0 1 0]} {'s'} 1.1749e+07 -5.82 4 A-Y {[ 0 1 0]} {'s'} 1.516e+07 5.43 4 A-Z {[ 0 1 0]} {'^'}
%rowfun(@(x,y,col,mark) scatter(x,y,20,col,mark),testTable,"InputVariables",{'x-axis','y-axis','colorNew','markerNew'})
%Error using tabular/rowfun>dfltErrHandler Applying the function
%'@(x,y,col,mark) scatter(x,y,20,col,mark)' to the 1st row of A gernerated
%the following error: Specify only one marker.
%scatter(testTable.("x-axis"),testTable.("y-axis"),20,testTable.colorNew,testTable.markerNew)
%Error using scatter Specify only one marker.
function k = ChangeColor(kin)
switch kin
case 3
k = [1 0.6 0];
case 4
k = [0 1 0];
case 5
k = [0 0 1];
case 6
k = [1 0 0];
end
end
function j = ChangeMarker(jin)
switch jin
case 'A-X'
j = '.';
case 'A-Y'
j = 's';
case 'A-Z'
j = '^';
case 'B-X'
j = 'o';
case 'B-Y'
j = 'd';
case 'B-Z'
j = 'v';
end
end

Accepted Answer

Désirée Kroner
Désirée Kroner on 4 Jul 2022
Edited: Désirée Kroner on 4 Jul 2022
Here comes the final version for now. To get it into a full function would take more time. This is enough for my needs.
load testfile.mat
%% test 2 with adding columns for color and marker
%% add color column
%% 1 2 3 4 5 6
%% white yellow orgnge green blue red
%% 'y' [1 0.6 0] 'g' 'b' 'r'
colorNew = rowfun(@(clr){ChangeColor(clr)}, testTable,"InputVariables","color","OutputVariableNames",'colorNew');
%% add marker column
%% AX point '.'
%% AY square 's'
%% AZ upwards triangle '^'
%% BX circle 'o'
%% BY diamond 'd'
%% BZ downward triangle 'v'
markerNew = rowfun(@(marker){ChangeMarker(marker)}, testTable,'InputVariables','marker','OutputVariableNames', 'markerNew');
%% add size to each marker
%% '.' 50, all other 20
sizeNew = rowfun(@(marker){ChangeSize(marker)}, testTable,'InputVariables','marker','OutputVariableNames', 'sizeNew');
% add size,color, marker to table
testTable= [testTable,sizeNew,colorNew,markerNew];
% convert to string
testTable.color = string(testTable.color);
testTable.marker = string(testTable.marker);
% create a list of all entries for the legend.
strFullLegend = rowfun(@(in1,in2){two2oneString(in1,in2)},testTable,'InputVariables',{'marker' 'color'},'OutputVariableNames','str');
strFullLegend = table2cell(strFullLegend); %legend needs to be a cell array
% group the table entries
[G,i1,i2] = findgroups(testTable.color,testTable.marker);
GroupTable = table(string(i2), string(i1));
strGroupLegend= rowfun(@(in1,in2){two2oneString(in1,in2)},GroupTable,'InputVariables',{'Var1' 'Var2'},'OutputVariableNames','str');
strGroupLegend = table2cell(strGroupLegend); %legend needs to be a cell array
figure %% with full legend
hold on
t=rowfun(@(tx,ty,tsz,tclr,tmrk){scatter(tx,ty,tsz{:},tclr{:},tmrk{:})}, testTable,"InputVariables",{'x-axis' 'y-axis' 'sizeNew' 'colorNew' 'markerNew'});
hold off
xlabel("Frequency [Hz]")
ylabel(["Magnetic field"; "strength [dB\muA/m]"])
legend(strFullLegend{:},'Location','northeastoutside')
% replace all double entries by ''
% preallocate cell array with {''}
strShortLegend = repmat({''},size(strFullLegend));
for i= 1:max(G)
idx = G==i; %creat index list for all groups
if sum(idx)>1
%find first one and replace with strGroupLegend value
flag = 1;
for f = 1:length(idx)
if idx(f)==1 && flag ==1
flag = 0;
idx(f) = 1;
else
idx(f) = 0;
end
end
else
% do nothing
end
%than write in the rest ''
strShortLegend(idx)= strGroupLegend(i,1);
end
figure %% with short legend
hold on
t=rowfun(@(tx,ty,tsz,tclr,tmrk){scatter(tx,ty,tsz{:},tclr{:},tmrk{:})}, testTable,"InputVariables",{'x-axis' 'y-axis' 'sizeNew' 'colorNew' 'markerNew'});
hold off
xlabel("Frequency [Hz]")
ylabel(["Magnetic field"; "strength [dB\muA/m]"])
legend(strShortLegend{:},'Location','northeastoutside')
function clr = ChangeColor(clr_in)
switch clr_in
case 3
clr = [1 0.6 0];
case 4
clr = [0 1 0];
case 5
clr = [0 0 1];
case 6
clr = [1 0 0];
end
end
function mkr = ChangeMarker(mkr_in)
switch mkr_in
case 'A-X'
mkr = '.';
sz = 60;
case 'A-Y'
mkr = 's';
sz = 30;
case 'A-Z'
mkr = '^';
sz = 30;
case 'B-X'
mkr = 'o';
sz = 30;
case 'B-Y'
mkr = 'd';
sz = 30;
case 'B-Z'
mkr = 'v';
sz = 30;
end
end
function sz = ChangeSize(mkr_in)
switch mkr_in
case 'A-X'
sz = 50;
case 'A-Y'
sz = 20;
case 'A-Z'
sz = 20;
case 'B-X'
sz = 20;
case 'B-Y'
sz = 20;
case 'B-Z'
sz = 20;
end
end
function str = two2oneString(in1,in2)
str = sprintf('%s,%s',in1,in2);
end

More Answers (1)

Désirée Kroner
Désirée Kroner on 11 Jul 2022
Here an add on to the legend.
I found that eaven the short legend that I created in the earlier answer was getting quite long. Therefore I went over to create a fake legened that discribes the symbole and color combinations.
Note now is everything in a function.
load testfile.mat
test1 = testTable;
figure
hold on
sct_tab = tblScatter2grp(test1.("x-axis"),test1.("y-axis"),test1.color,test1.marker);
xlabel("Frequency [Hz]")
ylabel(["Magnetic field"; "strength [dB\muA/m]"])
hold off
%% The function creates an scatter plot from a table that has two grouping variables.
%% The size, color and marker needs to be added manually to the table,
%% manipulate the corresponding function
%% Input (x-axis), y (y-axis), grpc (group color), grpm (group marker)
%% Output scatter plot with fake legend
function sct = tblScatter2grp(x,y,grpc,grpm)
%create table
tbl = table(x,y,grpc,grpm,'VariableNames',{'x','y','grpc','grpm'});
% add size, EdgColor, marker %% Note those functions need to be adjusted befor each call.
EdgColor = rowfun(@(clr){ChangeEdgeColor(clr)}, tbl,"InputVariables","grpc","OutputVariableNames",'EdgColor');
%% add marker column
marker = rowfun(@(mrk){ChangeMarker(mrk)}, tbl,'InputVariables','grpm','OutputVariableNames', 'marker');
%% add size to each marker
size = rowfun(@(mrk){ChangeSize(mrk)}, tbl,'InputVariables','grpm','OutputVariableNames', 'size');
% add size, EdgColor, marker to table
tbl = [tbl,size, EdgColor,marker];
% convert to string
tbl.grpc = string(tbl.grpc);
tbl.grpm = string(tbl.grpm);
% create a list of all entries for the Full legend.
strFullLegend = rowfun(@(in1,in2){two2oneString(in1,in2)},tbl,'InputVariables',{'grpc' 'grpm'},'OutputVariableNames','str');
strFullLegend = table2cell(strFullLegend); %legend needs to be a cell array
tbl.dName = strFullLegend;
% group the table entries
[G,i1,i2] = findgroups(tbl.grpc,tbl.grpm);
GroupTable = table(string(i1),string(i2));
strGroupLegend = rowfun(@(in1,in2){two2oneString(in1,in2)},GroupTable,'InputVariables',{'Var1' 'Var2'},'OutputVariableNames','str');
strGroupLegend = table2cell(strGroupLegend); %legend needs to be a cell array
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% could be removed when only using fake legend %%%%%%%%%%%%%%%%%%%%%%%
% replace all double entries by ''
% preallocate cell array with {''}
strShortLegend = repmat({''},height(tbl),1);
strShortLegend;
for i= 1:max(G)
idx = G==i; %create index list for all groups
if sum(idx)>1
%find first one and replace with strGroupLegend value
flag = 1;
for f = 1:length(idx)
if idx(f)==1 && flag ==1
flag = 0;
idx(f) = 1;
else
idx(f) = 0;
end
end
else
% do nothing
end
%than write in the values that shouldn't be equal ''
strShortLegend(idx,1) = strGroupLegend(i,1);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create a face legend that discribes all posible symbles and colors
x = [NaN;NaN;NaN;NaN;NaN;NaN]; % NaN makes it posible to make fake legends points won't be printed
mrk = {'p';'s';'^';'h';'d';'v'};
dName_PosAx = {'A-X';'A-Y';'A-Z';'B-X';'B-Y';'B-Z'};
dName_Cat = {'6-10 dB'; '11-15 dB';'16-20 dB';'>20 dB'};
clr = [1 0.6 0; 0 1 0; 0 0 1; 1 0 0];
leg_mark = table(x,x,mrk,dName_PosAx);
leg_col= table(x(1:length(dName_Cat),:), x(1:length(dName_Cat),:),clr,dName_Cat);
sct_mrk = rowfun(@(tx,ty,tmrk,tdN){scatter(tx,ty,60,'k',tmrk{:},'DisplayName',tdN{:})},leg_mark,"InputVariables",{'x' 'x' 'mrk' 'dName_PosAx'});
sct_clr = rowfun(@(tx,ty,teclr,tdN){scatter(tx,ty,60,teclr,'o','filled','DisplayName',tdN{:})},leg_col,"InputVariables",{'Var1' 'Var2' 'clr' 'dName_Cat'});
Asct_mrk = table2array(sct_mrk); %legend input needs to be an array
Asct_clr = table2array(sct_clr);
% create the scatter plot from the table
sct=rowfun(@(tx,ty,tsz,teclr,tmrk,tdN){scatter(tx,ty,tsz{:},teclr{:},tmrk{:},'DisplayName',tdN{:})}, tbl,"InputVariables",{'x' 'y' 'size' 'EdgColor' 'marker' 'dName'});
% Asct = table2array(sct);
%create a legend from only the two fake entries. Note you can add more here
legend([Asct_mrk{:}, Asct_clr{:}],'location','eastoutside')
grid on
grid minor
end
function clr = ChangeEdgeColor(clr_in)
%% 1 2 3 4 5 6
%% white yellow orgnge green blue red
%% 'y' [1 0.6 0] 'g' 'b' 'r'
switch clr_in
case 1
clr = [1 1 1];
case 2
clr = [1 1 0];
case 3
clr = [1 0.6 0];
case 4
clr = [0 1 0];
case 5
clr = [0 0 1];
case 6
clr = [1 0 0];
end
end
function mkr = ChangeMarker(mkr_in)
%% AX pentagram 'p'
%% AY square 's'
%% AZ upwards triangle '^'
%% BX hexagram 'h'
%% BY diamond 'd'
%% BZ downward triangle 'v'
switch mkr_in
case 'A-X'
mkr = 'p';
case 'A-Y'
mkr = 's';
case 'A-Z'
mkr = '^';
case 'B-X'
mkr = 'h';
case 'B-Y'
mkr = 'd';
case 'B-Z'
mkr = 'v';
end
end
function sz = ChangeSize(mkr_in)
%% '.' 50, all other 20
switch mkr_in
case 'A-X'
sz = 60;
case 'A-Y'
sz = 60;
case 'A-Z'
sz = 60;
case 'B-X'
sz = 60;
case 'B-Y'
sz = 60;
case 'B-Z'
sz = 60;
end
end
function str = two2oneString(in1,in2)
str = sprintf('%s,%s',in1,in2);
end

Categories

Find more on Data Distribution Plots in Help Center and File Exchange

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!