Skip to content

Commit 620b91d

Browse files
bug fixings for option colorBlindSafe
1 parent 17653d4 commit 620b91d

8 files changed

Lines changed: 107 additions & 56 deletions

File tree

toolbox/+aux/computePCA.m

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
computePCA(Y,bsb,rownames,varnames,standardize,NumComponents,dispresults,plots,Latitude,Longitude,ShapeFile,smartEVchart,colorBlindSafe)
33
% Compute all PCA quantities (this function is not intended to be called
44
% directly)
5-
65
[n,v]=size(Y);
76
if isempty(bsb)
87
bsb=true(n,1);
@@ -145,43 +144,44 @@
145144
end
146145
elseif iscellstr(plots) || ischar(plots) %#ok<ISCLSTR>
147146
% Note that warning is suppressed because of routine convertStringsToChars
148-
% Check whether input is a cell array of characters or a character array
147+
% Check whether input is a cell array of characters or a character array
149148
showPlots=string(plots);
150149
else
151150
error('FSDA:pcaFS:WrongInputOpt',['input argument plots can be either 0/1 false/true' newline 'or a cell array of characters or a string array or a character array'])
152151
end
153152

154-
%% Explained variance through Pareto plot
155-
% Delete figure if it already exists
156-
if ismember("Explained",showPlots)
157-
delete(findobj(0, 'type', 'figure','tag','pl_eigen'));
158-
figure('Name','Explained variance','Tag','pl_eigen')
159-
[h,axesPareto]=pareto(explained(:,1),namerows);
160-
% h(1) refers to the bars h(2) to the line
161-
if colorBlindSafe
162-
h(1).FaceColor=aux.sequential_hcl_matlab(1);
163-
else
164-
h(1).FaceColor='g';
153+
%% Explained variance through Pareto plot
154+
% Delete figure if it already exists
155+
if ismember("Explained",showPlots)
156+
delete(findobj(0, 'type', 'figure','tag','pl_eigen'));
157+
figure('Name','Explained variance','Tag','pl_eigen')
158+
[h,axesPareto]=pareto(explained(:,1),namerows);
159+
% h(1) refers to the bars h(2) to the line
160+
if colorBlindSafe
161+
h(1).FaceColor=aux.sequential_hcl_matlab(1);
162+
else
163+
h(1).FaceColor='g';
164+
end
165+
linelabels = string(round(100*h(2).YData/sumla,2));
166+
text(axesPareto(2),h(2).XData,h(2).YData,linelabels,...
167+
'Interpreter','none');
168+
xlabel('Principal components')
169+
ylabel('Explained variance')
165170
end
166-
linelabels = string(round(100*h(2).YData/sumla,2));
167-
text(axesPareto(2),h(2).XData,h(2).YData,linelabels,...
168-
'Interpreter','none');
169-
xlabel('Principal components')
170-
ylabel('Explained variance')
171-
end
172171

173172
%% Plot loadings
174173
if ismember("Loadings",showPlots)
174+
175+
xlabels = categorical(varnames,varnames);
176+
175177
if colorBlindSafe
176178
[negColor,posColor] = aux.plotLoadingsDiverging(loadings, varnames, NumComponents, 'Loadings', 'pl_loadings');
177179
else
178180
negColor = 'r';
179181
posColor = 'b';
180-
182+
181183
delete(findobj(0, 'type', 'figure','tag','pl_loadings'));
182184
figure('Name','Loadings','Tag','pl_loadings')
183-
184-
xlabels = categorical(varnames,varnames);
185185

186186
for i=1:NumComponents
187187
subplot(NumComponents,1,i)
@@ -266,7 +266,7 @@
266266
'VerticalAlignment','bottom')
267267
text(i, ax.YLim(1) - 0.05*diff(ax.YLim), string(b.XData(i)), ...
268268
'HorizontalAlignment','center', 'VerticalAlignment','top', ...
269-
'Color', 'b', 'Parent', ax);
269+
'Color', 'b', 'Parent', ax); % DDD 'b' or 'k'?
270270
end
271271
end
272272

@@ -340,9 +340,23 @@
340340
if ~isempty(Latitude) && ~isempty(Longitude)
341341
delete(findobj(0, 'type', 'figure','tag','pl_latlong'));
342342
figure('Name','geobubble','tag','pl_latlong')
343-
aux.plotGeobubbleDiverging(Latitude, Longitude, score(:,1), score(:,2), ...
344-
"Geobubble of all units", "First PC (size)", "Second PC (color)", ...
345-
'MapLayout','maximized');
343+
344+
if colorBlindSafe
345+
aux.plotGeobubbleDiverging(Latitude, Longitude, score(:,1), score(:,2), ...
346+
"Geobubble of all units", "First PC (size)", "Second PC (color)", ...
347+
'MapLayout','maximized');
348+
else
349+
350+
% Divide the second PC into 4 classes
351+
cate=discretize(score(:,2),linspace(min(score(:,2)),max(score(:,2)),4),'categorical');
352+
353+
% Add title and legend titles
354+
gb=geobubble(Latitude,Longitude,score(:,1),cate,'Basemap','topographic','MapLayout','maximized');
355+
gb.Title = "Geobubble of all units";
356+
gb.SizeLegendTitle = "First PC (size)";
357+
gb.ColorLegendTitle = "Second PC (color)";
358+
end
359+
346360
elseif ~isempty(Latitude) || ~isempty(Longitude)
347361
error('FSDA:pcaFS:WrongInputOpt','Both Latitude and Longitude must be given.');
348362
end

toolbox/+aux/diverging_hcl_matlab.m

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,59 @@
3838
% cmap = diverging_hcl_matlab(256);
3939
% colormap(cmap); colorbar; caxis([-1 1]);
4040

41+
% p = inputParser;
42+
% addParameter(p,'H1',260);
43+
% addParameter(p,'H2',12);
44+
% addParameter(p,'C1',80);
45+
% addParameter(p,'L1',30);
46+
% addParameter(p,'L2',95);
47+
% addParameter(p,'Power',1.5);
48+
% parse(p,varargin{:});
49+
% o = p.Results;
50+
%
51+
% half = ceil(n/2);
52+
% t = linspace(1,0,half)'; % 1 at extreme, 0 at center
53+
% L = o.L2 - (o.L2-o.L1).*t.^o.Power;
54+
% C = o.C1.*t.^o.Power;
55+
%
56+
% negHalf = local_hcl2rgb(o.H1*ones(half,1), C, L); % extreme -> center
57+
% posHalf = local_hcl2rgb(o.H2*ones(half,1), C, L); % extreme -> center
58+
%
59+
% cmap = [negHalf; flipud(posHalf(2:end,:))]; % extreme -> center -> extreme
60+
% cmap = max(0, min(1, cmap));
61+
%
62+
% if size(cmap,1) ~= n
63+
% idx = round(linspace(1, size(cmap,1), n));
64+
% cmap = cmap(idx,:);
65+
% end
66+
% end
67+
68+
4169
p = inputParser;
42-
addParameter(p,'H1',260);
43-
addParameter(p,'H2',12);
70+
addParameter(p,'H1',260); % negative extreme hue (blue)
71+
addParameter(p,'H2',12); % positive extreme hue (red)
4472
addParameter(p,'C1',80);
4573
addParameter(p,'L1',30);
4674
addParameter(p,'L2',95);
4775
addParameter(p,'Power',1.5);
4876
parse(p,varargin{:});
4977
o = p.Results;
5078

51-
half = ceil(n/2);
52-
t = linspace(1,0,half)'; % 1 at extreme, 0 at center
53-
L = o.L2 - (o.L2-o.L1).*t.^o.Power;
54-
C = o.C1.*t.^o.Power;
79+
t = linspace(-1, 1, n)'; % -1 = negative extreme, 0 = center, 1 = positive extreme
80+
absT = abs(t);
5581

56-
negHalf = local_hcl2rgb(o.H1*ones(half,1), C, L); % extreme -> center
57-
posHalf = local_hcl2rgb(o.H2*ones(half,1), C, L); % extreme -> center
82+
L = o.L2 - (o.L2 - o.L1) .* absT.^o.Power;
83+
C = o.C1 .* absT.^o.Power;
5884

59-
cmap = [negHalf; flipud(posHalf(2:end,:))]; % extreme -> center -> extreme
60-
cmap = max(0, min(1, cmap));
85+
H = zeros(n,1);
86+
H(t < 0) = o.H1;
87+
H(t >= 0) = o.H2;
6188

62-
if size(cmap,1) ~= n
63-
idx = round(linspace(1, size(cmap,1), n));
64-
cmap = cmap(idx,:);
65-
end
89+
cmap = local_hcl2rgb(H, C, L);
90+
cmap = max(0, min(1, cmap));
6691
end
6792

93+
6894
function rgb = local_hcl2rgb(H, C, L)
6995

7096
% Polar LUV (H,C,L) -> LUV -> CIEXYZ -> linear sRGB -> gamma-corrected sRGB

toolbox/+aux/plotGeobubbleDiverging.m

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717

1818
edges = linspace(min(colorVar), max(colorVar), 4);
1919
cate = discretize(colorVar, edges, 'categorical');
20-
cate = reordercats(cate, string(categories(cate))); % ensure numeric bin order
20+
cate = reordercats(cate, string(categories(cate)));
21+
22+
nCats = numel(categories(cate));
2123

2224
gb = geobubble(lat, lon, sizeVar, cate, ...
2325
'Basemap','topographic', ...
2426
varargin{:});
25-
gb.BubbleColorList = diverging_hcl_matlab(3);
27+
gb.BubbleColorList = aux.diverging_hcl_matlab(nCats); % always matches actual category count
2628
gb.Title = titleStr;
2729
gb.SizeLegendTitle = sizeLegend;
2830
gb.ColorLegendTitle = colorLegend;
2931
end
32+
33+

toolbox/graphics/biplotAPP.mlapp

1.1 KB
Binary file not shown.

toolbox/graphics/geoplotAPP.mlapp

161 Bytes
Binary file not shown.

toolbox/graphics/pcaProjection.m

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ function pcaProjection(Y,varargin)
177177
LineWidthAxes=3;
178178
TextDensityPercentage =60;
179179

180+
% Okabe–Ito is a colorblind-safe qualitative palette used by Zeileis et al. (2020)
181+
okabeIto = [0.00 0.45 0.70; % blue
182+
0.90 0.60 0.00; % orange
183+
0.00 0.62 0.45; % bluish green
184+
0.80 0.40 0.70; % reddish purple
185+
0.94 0.89 0.26; % yellow
186+
0.84 0.37 0.00; % vermillion
187+
0.35 0.35 0.35]; % gray (fallback for extra groups)
188+
180189
if nargin>1
181190
options=struct('standardize',standardize,...
182191
'conflev',conflev,'AddAxes',AddAxes,'LineWidthAxes',LineWidthAxes,...
@@ -295,7 +304,7 @@ function pcaProjection(Y,varargin)
295304

296305
for j=1:3
297306
if AddAxes(j) == true
298-
addLinePCj(V,Xtilde,j,LineWidthAxes,TextAnToolbox);
307+
addLinePCj(V,Xtilde,j,LineWidthAxes,TextAnToolbox,okabeIto(j,:));
299308
end
300309
end
301310

@@ -316,7 +325,8 @@ function pcaProjection(Y,varargin)
316325

317326
for j=1:3
318327
if AddAxes(j) == true
319-
addLinePCj(V,Xtilde,1,LineWidthAxes,TextAnToolbox)
328+
% DDD bug? is it V,Xtilde,1 or V,Xtilde,j ?
329+
addLinePCj(V,Xtilde,1,LineWidthAxes,TextAnToolbox,okabeIto(j,:))
320330
end
321331
end
322332

@@ -343,7 +353,7 @@ function pcaProjection(Y,varargin)
343353
hold('on')
344354
for j=1:3
345355
if AddAxes(j) == true
346-
addLinePCj(V,Xtilde,j,LineWidthAxes,TextAnToolbox);
356+
addLinePCj(V,Xtilde,j,LineWidthAxes,TextAnToolbox,okabeIto(j,:));
347357
end
348358
end
349359

@@ -445,7 +455,7 @@ function pcaProjection(Y,varargin)
445455

446456
for j=1:3
447457
if isMatlab && AddAxes(j) == true
448-
addLinePCj(V,XX1,j,LineWidthAxes,TextAnToolbox);
458+
addLinePCj(V,XX1,j,LineWidthAxes,TextAnToolbox,okabeIto(j,:));
449459
end
450460
end
451461

@@ -456,30 +466,26 @@ function pcaProjection(Y,varargin)
456466

457467
end
458468

459-
function addLinePCj(V,Xtilde,j,lwd,TextAnToolbox)
469+
470+
function addLinePCj(V,Xtilde,j,lwd,TextAnToolbox,axColor)
460471
vj=V(:,j);
461472
Xhatj = Xtilde*(vj*vj');
462-
% Take two points to draw this line
463473
[~,indminXj] = min(Xhatj(:,2));
464474
[~,indmaxXj] = max(Xhatj(:,2));
465475

466-
% Add the line associated with jth PC
467476
line([Xhatj(indminXj,1); Xhatj(indmaxXj,1)], [Xhatj(indminXj,2); Xhatj(indmaxXj,2)], ...
468-
[Xhatj(indminXj,3); Xhatj(indmaxXj,3)],'LineWidth',lwd);
477+
[Xhatj(indminXj,3); Xhatj(indmaxXj,3)],'LineWidth',lwd,'Color',axColor);
469478

470479
if TextAnToolbox ==true
471-
472480
signindmaxXj=sign([Xhatj(indmaxXj,1); Xhatj(indmaxXj,2); Xhatj(indmaxXj,3) ]);
473-
474481
if isequal(sign(vj),signindmaxXj)
475482
textscatter3(Xhatj(indmaxXj,1), Xhatj(indmaxXj,2), ...
476-
Xhatj(indmaxXj,3),"PC"+j);
483+
Xhatj(indmaxXj,3),"PC"+j,'ColorData',axColor);
477484
else
478485
textscatter3(Xhatj(indminXj,1), Xhatj(indminXj,2), ...
479-
Xhatj(indminXj,3),"PC"+j);
486+
Xhatj(indminXj,3),"PC"+j,'ColorData',axColor);
480487
end
481488
end
482-
483489
end
484490

485491
function add3Daxes(j,color,lwd)

toolbox/graphics/scatterboxplot.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
% the number of groups before calling scatterhist, so both the scatter and
9292
% the boxplot color inherit it consistently.
9393

94+
% Okabe–Ito is a colorblind-safe qualitative palette used by Zeileis et al. (2020)
9495
okabeIto = [0.00 0.45 0.70; % blue
9596
0.90 0.60 0.00; % orange
9697
0.00 0.62 0.45; % bluish green

toolbox/multivariate/pcaFS.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@
395395
'dispresults',dispresults,'NumComponents',NumComponents,...
396396
'robust',robust,'Latitude',Latitude,'Longitude',Longitude, ...
397397
'ShapeFile',ShapeFile,'smartEVchart',smartEVchart,...
398-
'colorBlindSafe',false);
398+
'colorBlindSafe',colorBlindSafe);
399399

400400
[varargin{:}] = convertStringsToChars(varargin{:});
401401
UserOptions=varargin(1:2:length(varargin));

0 commit comments

Comments
 (0)