4
votes

Problem:

The legend colors in my scatter3 plot do not match the series colors after using a for loop.

Background:

I'm writing a script to produce a 3d plot based on experimental data. I process the data in R, as well. So the data is formatted as a data.frame (i.e. a nx7 CSV with headers are Value Gain Cost, Entropy, Risk, Credibility, algorithm, color, pch). I want the resulting 3d scatter plot to add a point for each observation (i.e. each [x,y,z] element) and color it according to its pch value (e.g. all observations with pch==1 should be the same color).

Code:

%get & count unique pch values ommitting NANs
UniquePchVal =transpose(unique(pch));
numberOfUniquePchVals=length(UniquePchVal(~isnan(UniquePchVal)))
UniquePchVal = UniquePchVal(1:numberOfUniquePchVals);

% get boolean vector for each series to indicate which observations should
% are to be included
numberOfObservations=length(pch)
UniquePchValMatrix = repmat(UniquePchVal,numberOfObservations,1);
pchMatrix=repmat(pch,1,numberOfUniquePchVals);
rows=UniquePchValMatrix(1:numberOfObservations,1:numberOfUniquePchVals);
rows =(rows==pchMatrix);

%make the plot
hold on
for i=1:numberOfUniquePchVals
   x=ValueGain(rows(:,i));
   y=Cost(rows(:,i));
   z=Risk(rows(:,i));
   size=repmat(20,length(x),1);
   color=repmat(i,length(x),1);
   h(i)=scatter3(x,y,z,size,color,'filled');
end
xlabel('Value Gain')
ylabel('Cost')
zlabel('Risk')
legend(h,unique(algorithm))
hold off

Result:

Executing the code produces a legend where each dot is the same color. Result from executing the above code

Sample Data:

Value Gain  Cost    Entropy Risk    Credibility algorithm   color   pch
-0.0    0.0 -0.0    0.0 -0.0    MOEAD   orange  3
-1.39838    1.44    -1.0    2.55555 -1.0    MOEAD   orange  3
-1.41319    4.15    -1.0    1.55555 -1.0    MOEAD   orange  3
-1.39593    3.84    -1.0    1.55555 -1.0    MOEAD   orange  3
-1.25189    1.11    -0.5    1.55555 -1.0    IBEA    cornflowerblue  4
-1.43183    2.87    -0.5    2.55555 -1.0    IBEA    cornflowerblue  4
-1.38953    1.43    -1.0    1.55555 -1.0    NSGA2   #fb8072 5
-1.39585    1.13    -0.33333    1.55555 -1.0    NSGA2   #fb8072 5
-1.1792 1.0 -0.2    2.55555 -1.0    NSGA2   #fb8072 5
-1.38244    1.14    -1.0    1.55555 -1.0    NSGA2   #fb8072 5
-0.05665    0.89    -1.0    2.55543 -1.0    NSGA2   #fb8072 5
-0.1175 0.9 -0.5    1.55556 -1.0    NSGA2   #fb8072 5
-0.06518    0.75    -0.33333    1.55555 -1.0    NSGA2   #fb8072 5
-0.51192    0.98    -0.5    1.55555 -1.0    NSGA2   #fb8072 5
-0.77432    0.98    -1.0    2.55555 -1.0    NSGA2   #fb8072 5
-0.82269    0.94    -0.25   2.55555 -1.0    NSGA2   #fb8072 5
-0.92626    1.0 -1.0    1.55555 -1.0    NSGA2   #fb8072 5
1
This isn't an answer but have you considered using a dynamic legend? It's technically not supported but I've found it very helpful to build legend's with the correct color, etc especially in contexts where I'm putting lots of different series on the same graph. - chessofnerd
Is pch always going to be linked to algorithm? - excaza
@excaza, Yes pch is always linked to algorithm. In fact, color is linked to algorithm, as well. They are "R"isms: pch indicates the desired Marker type and color indicates the desired marker color. - Austin D

1 Answers

1
votes

If all markers are the same colour, or there are only a few distinct colours, it is much more efficient to just use line instead of scatter3; the latter makes one handle per marker, line has one handle for all points. scatter3 with many points can bring Matlab to a halt.

Added bonus when using line is that the legend works as expected:

colors = ['r','g','b'];
hold on
h = [];
for ii = 1:3
    x = rand(10,1);
    y = rand(10,1);
    z = rand(10,1);
    h(ii) = line(x,y,z);
    set(h(ii),...
        'Marker','.',...
        'MarkerEdgeColor',colors(ii),...
        'MarkerFaceColor',colors(ii),...
        'MarkerSize',10,...
        'LineStyle','none')
end
legend('a','b','c')