Displaying matrix of correlation coefficients

Hi, i have a large matrix of correlation coefficients, which i am displaying using imagesc function. It gives me the imageof the matrix with colours representing each element of thematrix. Is there some way to represent each entry of the matrix as individual circles instead of pixels.Please see the attached imagewhich is what i want to get. The code below representswhat i presently have
C=rand(20,20);
imagesc(C)
colormap(gca,'parula');
colorbar() ; % Add color bar and make sure the color ranges from 0:1
caxis([-1,1]);
download.png

 Accepted Answer

I'm not aware of a Matlab function that produces such a plot, It appears that the circles are scaled by color and size.
This code produces a similar plot. See inline comments for details.
% Produce the input matrix data
C=rand(20,30);
% Set [min,max] value of C to scale colors
% This must span the range of your data!
clrLim = [0,1]; % or [-1,1] as in your question
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.3, 1];
% Plot the data using imagesc() for later comparison
figure()
imagesc(C)
colormap(gca,'parula');
colorbar();
caxis(clrLim);
axis equal
axis tight
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(C,2); % x edges
y = 1 : 1 : size(C,1); % y edges
[xAll, yAll] = meshgrid(x,y);
% Set color of each rectangle
% Set color scale
cmap = parula(256);
Cscaled = (C - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size in the same way we scale the color
diamSize = Cscaled * range(diamLim) + diamLim(1);
% diamSize = abs(C) * range(diamLim) + diamLim(1); for [-1,1] scaling
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'parula');
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
% If you get an error in this line below, "Index in position 1 is invalid",
% that probably means you didn't set clrLim correctly.
h = arrayfun(@(i)fill(diamSize(i)/2 * cos(theta) + xAll(i), ...
diamSize(i)/2 * sin(theta) + yAll(i), cmap(colIdx(i),:)),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
Update
In Matlab R2020b bubblechart() was released which produces similar plots. However, the size of the circles are in point units where one point equals 1/72 inch and currently there is no other unit options. This means that when the figure or axes are resized, the circles will not maintain the axis-relative size. It would be nice if bubblechart supported data-units for its size parameter in a future release.
Here's what the plot would look like in R2021a using the same variables produced above.
figure();
bubblechart(xAll(:), yAll(:), diamSize(:), colIdx(:), ...
'MarkerEdgeColor','k', 'MarkerEdgeAlpha',1, ...
'MarkerFaceAlpha',1)
bubblesize([3,12]) % <-- customized for the display size below
axis equal
axis tight
set(gca, 'ydir','reverse') % for direct comparison with imagesc plot

21 Comments

Hi, Thanks a lot for this nice code. It worked well, but i have a basic question. If i change the dimensions of matrix C, The code gave me an error stating that "Index in position 1 is invalid. Array indices must be positive integers or logical values." Matlab referes to the following line. Sorry for this basic question but i could not figure out where you set the indices?
h = arrayfun(@(i)fill(diamSize(i)/2 * cos(theta) + xAll(i), ...
diamSize(i)/2 * sin(theta) + yAll(i), cmap(colIdx(i),:)),1:numel(xAll));
Adam Danz
Adam Danz on 16 Dec 2019
Edited: Adam Danz on 16 Dec 2019
Could you provide the inputs that reproduce this error?
I used a 7x10 matrix, but dont worry, now it works fine. Many thanks for your kind help
"now it works fine"
Was a change required or was the problem with the inputs? I tested it with multiple sizes of C and there were no problems.
Glad I could help.
The code is perfect, i guess, i made some unknown formatting mistake in copying and adopting it to my matrix. It wroks perfectly. Thanks again.
Good! Thanks for letting me know.
Great job Adam Danz.
Just there is a small issue in your code. When correlation coefficients are [-1,1] as allowable range, the circle sizes are not correct. Circle sizes should be defined based on absolute values of correlations. So circle diameters should be:
% Set size of each circle
% Scale the size between [0 1]
diamSize = abs(C) * range(diamLim) + diamLim(1);
Also triangular display provided [Here] , thanks to your code:
Hi Sumera, I am having the same error as you did.
'Index in position 1 is invalid. Array indices must be positive integers or logical values.'
How did you solve it?
Are you getting that error while running an exact copy of the code in my answer? If so, what line produces that error? If not, you'll need to provide more info about your version of the code and the inputs or about the line producing the error.
Louis Aye Kyaw's answer moved here as a comment.
Thanks for the quick response. The exact copy of your code works fine and its awesome. It happened when I put my data as an input. The error happened here.
Index in position 1 is invalid. Array indices must be positive integers or logical values.
Error in
corrcolor>@(i)fill(diamSize(i)/2*cos(theta)+xAll(i),diamSize(i)/2*sin(theta)+yAll(i),cmap(colIdx(i),:))
(line 52)
diamSize(i)/2*sin(theta)+yAll(i),cmap(colIdx(i),:)),1:numel(xAll));
Error in corrcolor (line 51)
h = arrayfun(@(i)fill(diamSize(i)/2*cos(theta)+xAll(i),...
My xAll has some Nan values in it. Not sure is it the problem though.
Thanks
If xAll has NaN values, it should not cause an error. Instead, some of the columns of circles would be missing.
The only indices in that line are i and colIdx(i). I doubt i is the problem as long as it's defined by 1:numel(xAll) as in my answer.
Could you attach a mat file containing the variables C and clrLim or whatever you've named them? Or describe their values in detail.
Thank you for the response. I have pasted my code here. T1 is the 484x28 matrix with positive and negative values as well as some zeroes in it. Nan from it has been remove using isnan. Cscaled values seem to be fine without any Nan but colIdx sure has tons of Nan in it.
%from struct to matrix using function
REC = load('C:\Users\ACK\corrcolortest.mat');
T1 = revised2(REC);
T1=T1';
%removing Nan
idx=any(isnan(T1),2);
T1(idx,:)=[];
% Set [min,max] value of C to scale colors
clrLim = [-1,1];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
myLabel = {'A','Spd','E2','E',...
'5','T6','T7','S4',...
'EG','RH','rate',...
'R1','ux',...
'Fu','Fue','load',...
'PM','Frate','R',...
'de','C4',...
'FR','P1','AM','X','e','O',...
'S'};
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(T1,2); % x edges
y = 1 : 1 : size(T1,1); % y edges
[xAll, yAll] = meshgrid(x,y);
xAll(T1==0)=nan; % eliminate cordinates for zero correlations
% Set color of each rectangle
% Set color scale
cmap = jet(256);
% cmap = CorrColormap; % Uncomment for CorrColormap
Cscaled = (T1 - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size between [0 1]
Cscaled = (abs(T1) - 0)/1;
diamSize = Cscaled * range(diamLim) + diamLim(1);
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'jet');
% colormap(CorrColormap) %Uncomment for CorrColormap
tickvalues = 1:size(T1,2);
x = zeros(size(tickvalues));
text(x, tickvalues, myLabel, 'HorizontalAlignment', 'right');
x(:) = size(T1,1)+1;
text(tickvalues, x, myLabel, 'HorizontalAlignment', 'right','Rotation',90);
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
h = arrayfun(@(i)fill(diamSize(i)/2*cos(theta)+xAll(i),...
diamSize(i)/2*sin(theta)+yAll(i),cmap(colIdx(i),:)),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
axis off
Could you attach corrcolortest.mat so I can run it?
My apologies. The data is not in my control to attach it here. I have attached colIdx.mat though.
I also need revised2(). T1 is the starting point of the investigation.
Hi Adam, I have attached the T1.mat file after clearing of Nan values which is a time series data with large variation in values. Please have a look.
Thank you.
The error is because you haven't set clrLim according to the range of your data (T1).
Copied from my answer,
% Set [min,max] value of C to scale colors
clrLim = [0,1]; % or [-1,1] as in your question
clrLim should span the range of your data (or more). In my demo, the variable C is random values between 0 and 1 so my clrLim is set to [0,1]. Your T1 data spans [-21.63, 3156.2] so perhaps you want to set clrLim to something like [-25, 3200] or perhaps you want to use the actual bounds (or use round/ceil/floor etc).
I'll update my answer to make it even more clearer that clrLim should span the range of data.
Once you fix that, note that you are working with 10164 values in xAll so the arrayfun() function will run 10164 times. It took several seconds to generate the figure because of this and will also consume a nice chunk of memory. Using the bounds [-25, 3200], the plot from T1 looks like this (after removing some text() lines that broke).
Obviously there's something wrong if your goal is to produce a plot similar to the ones above. Looking into it further, you can get rid of this line: Cscaled=(abs(T1) - 0)/1; That should scale the diamSize variable property which should contain normalized values between 0 and 1.
Finally, it produces the plot you may have expected.... but.... since your data have a narrow range of x values relative to y values, your plot is very tall and narrow. I ran your data through the bubblechart version in my answer and it's clear that only 1 column of data vary so perhaps this form of visualization is not best for this dataset.
Thank you for the response. Does this implies that my dataset is not very suitable to run correlation? I put the T1 into zscore to make it more standardized and change the clrLim to [-3.5,5] which include everything the T1 has. The issue 'Index in position 1' still exists which I think is due to linspace not covering all of Cscale (some of which are in -2 to 3 range) and causing some of the colIdx values to be Nan which returns the error in indexing.
Is there any workaround in solving the Nan issue?
T1=zscore(T1);
% Set [min,max] value of C to scale colors
clrLim = [-3.5,5];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
myLabel = {'A','Spd','E2','E',...
'5','T6','T7','S4',...
'EG','RH','rate',...
'R1','ux',...
'Fu','Fue','load',...
'PM','Frate','R',...
'de','s'};
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(T1,1); % x edges
y = 1 : 1 : size(T1,2); % y edges
[xAll, yAll] = meshgrid(x,y);
xAll(T1==0)=nan; % eliminate cordinates for zero correlations
% Set color of each rectangle
% Set color scale
cmap = jet(484);
% cmap = CorrColormap; % Uncomment for CorrColormap
Cscaled = (T1 - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size between [0 1]
diamSize = Cscaled * range(diamLim) + diamLim(1);
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'jet');
% colormap(CorrColormap) %Uncomment for CorrColormap
tickvalues = 1:size(T1,2);
x = zeros(size(tickvalues));
text(x, tickvalues, myLabel, 'HorizontalAlignment', 'right');
x(:) = size(T1,1)+1;
text(tickvalues, x, myLabel, 'HorizontalAlignment', 'right','Rotation',90);
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
h = arrayfun(@(i)fill(diamSize(i)/2*cos(theta)+xAll(i),...
diamSize(i)/2*sin(theta)+yAll(i),cmap(colIdx(i),:)),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
axis off
I just put in the T1 into corrcoef function to make it into square matrix like yours and now its working. The clrLim can also be -1 to 1 now. Not sure about the accuracy of the result though.
What do you think? And how can I change the color for correlation coefficient 1 to blue and -1 to red?
Thanks
T1 = createDataMatrix_revised(REC);
T1=T1';
%removing Nan
idx=any(isnan(T1),2);
T1(idx,:)=[];
T1=corrcoef(T1);
T1 = tril(T1,-1);
T1(logical(eye(size(T1)))) = 1;
% Set [min,max] value of C to scale colors
clrLim = [-1,1];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
> Does this implies that my dataset is not very suitable to run correlation
No. The solution in my answer produces a visualization of correlations (a corellogram) or of any rectangular dataset. It does not compute correlations.
> I just put in the T1 into corrcoef function to make it into square matrix like yours and now its working.
It sounds like you're just trying stuff until you get a figure that looks nice. I see this approach a lot and it's not how data should be analyzed and interpretted. For example, do you want to visualize T1 or do you want to visualize the correlations between the variables in T1? That decision should be made before you start write code. Secondly, you shouldn't use other people's code without reading it and making sense of it. Even if you don't understand every line, it's important to get a sense of what the code does. I know this takes some skill that newbies may not yet have but that's where Matlab documentation comes in handy. If you can't understand what the code is doing you'll never be able to make small adjustments to the code to customize it to your needs.
> Not sure about the accuracy of the result though
clrLim=[-1,1], that part is fine and will not affect any kind of accuracy. It's just used to set the color limits. Actually no part of my solution is related to accuracy. It just produces a visualization of data.
> And how can I change the color for correlation coefficient 1 to blue and -1 to red
Try this
nbins = 10;
rgb = [ones(ceil(nbins/2),1),linspace(0,1,ceil(nbins/2))' .* [1,1]];
rgb = [rgb; rot90(rgb(1:floor(nbins/2),:),2)];
colormap(ax,rgb);
% or
colormap(ax,flipud(rgb))
Thank you for the detailed responses and suggestions. I do checked all the functions use in your code before using it but still learning how to make sense of the whole thing. Yes, I want to visualize the correlation between the variables in T1. The code for correlation coefficient color bar change works and I have also match the circle colors to blue. Many thanks!

Sign in to comment.

More Answers (0)

Asked:

on 16 Dec 2019

Commented:

ack
on 9 Sep 2021

Community Treasure Hunt

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

Start Hunting!