Draw lines around specific regions in imagesc plot

16 views (last 30 days)
I have a NxN matrix T that I am plotting with imagesc. This matrix is a matrix of t values. I would like to mark the t values that are significant. Ideally, I would draw around them with a black line in the imagesc plot. I have another NxN matrix of p values P.
So essentially, I want to find every element in P that is less than 0.05, and draw a line around the corresponding point in the imagesc representation of T. Also, if there are multiple elements next to eachtoehr that are below 0.05 in P, the line should ideally encompass all these points in one, rather than each element being encircled on its own.
Like how the top image looks in the attached image.
Thanks
  1 Comment
Aleksandar Besevic
Aleksandar Besevic on 21 Dec 2022
Hey, did you ever manage to solve this? Having a similar issue whereby I want to draw a box/rectangle around a defect in an imagesc plot . Contour plot just creates a squiggle inside the pixel which is pretty useless

Sign in to comment.

Answers (2)

Image Analyst
Image Analyst on 21 Dec 2022

Elizabeth
Elizabeth on 27 Apr 2025
Edited: Elizabeth on 28 Apr 2025
I had the exact same question for a time frequency plot, and couldn't find a function, so I ended up writing one. It was more complicated than I expected!
It takes a matrix in which members of the cluster are non-zero and everything else is zero. It outputs an N x 3 matrix of vertices, where N is the total number of "corners" of the patch. The vertices are ordered starting at one vertex and going round the edge of the cluster clockwise until you get back to where you started. The first and second columns are the X and Y coordinates of each vertex, respectively. The third column is the "perimeter number", as if there are any "holes" in the cluster, e.g. a clump of non-significant values enclosed by the cluster, you will need a separate array of ordered perimeter vertices representing the perimeter of the hole. When you draw each perimeter, you have to draw each separately, as you don't want a line connecting the edge of the cluster with the edge of the hole.
Then I used patch.m to overlay the perimeters on the time frequency plot.
Here's the function. Someone else might have done a simpler one by now, but this one worked for me!
function [ClusterVertices] = ClusterBorder(ClusterMap)
% CLUSTERBORDER function to draw line round a cluster of significant TFS
% cells in colourmap e.g. using imagesc.
%
% Takes a logical matrix showing a cluster of contiguous TFS cells, and
% and finds the coordinates of the internal and external vertices of the
% cluster, and orders them clockwise round the perimeter. The output of
% ordered vertices can be used with patch.m to draw a line round the cluster
%% Pads the cluster array with zeros by one cell all round
Mask=abs(ClusterMap)>0;
PaddedMask=padarray(1*Mask,[1,1],0);
%% Finds linear and subscript indices of all cluster cells
LinIdx=find(PaddedMask==1);
[Row,Col]=ind2sub(size(PaddedMask),LinIdx);
ClusterSubs=[Row,Col];
%% Find neighbours of each cell in mask
NCellIdx=sub2ind(size(PaddedMask),Row-1,Col);
SCellIdx=sub2ind(size(PaddedMask),Row+1,Col);
WCellIdx=sub2ind(size(PaddedMask),Row,Col-1);
ECellIdx=sub2ind(size(PaddedMask),Row,Col+1);
NWCellIdx=sub2ind(size(PaddedMask),Row-1,Col-1);
NECellIdx=sub2ind(size(PaddedMask),Row-1,Col+1);
SWCellIdx=sub2ind(size(PaddedMask),Row+1,Col-1);
SECellIdx=sub2ind(size(PaddedMask),Row+1,Col+1);
ClusterCellNeighbours=[...
PaddedMask(NWCellIdx),...
PaddedMask(NCellIdx),...
PaddedMask(NECellIdx),...
PaddedMask(ECellIdx),...
PaddedMask(SECellIdx),...
PaddedMask(SCellIdx),...
PaddedMask(SWCellIdx),...
PaddedMask(WCellIdx)];
%% Find Edge cells
EdgeCellIdx=sum(ClusterCellNeighbours,2)<8; % Find all edge cells
EdgeSubs=ClusterSubs(EdgeCellIdx,:);
EdgeCellNeighbours=ClusterCellNeighbours(EdgeCellIdx,:);
ExtTL_Subs=EdgeSubs(sum(EdgeCellNeighbours(:,[2,8]),2)==0,:);
ExtTR_Subs=EdgeSubs(sum(EdgeCellNeighbours(:,[2,4]),2)==0,:);
ExtBL_Subs=EdgeSubs(sum(EdgeCellNeighbours(:,[6,8]),2)==0,:);
ExtBR_Subs=EdgeSubs(sum(EdgeCellNeighbours(:,[4,6]),2)==0,:);
IntTL_Subs=EdgeSubs(ismember(EdgeCellNeighbours(:,[8,1,2]), [1,0,1], 'rows'),:);
IntTR_Subs=EdgeSubs(ismember(EdgeCellNeighbours(:,2:4), [1,0,1], 'rows'),:);
IntBL_Subs=EdgeSubs(ismember(EdgeCellNeighbours(:,6:8), [1,0,1], 'rows'),:);
IntBR_Subs=EdgeSubs(ismember(EdgeCellNeighbours(:,4:6), [1,0,1], 'rows'),:);
%% Finds coordinates of all cluster corners
ExtTL_verts=[ExtTL_Subs(:,2)-0.5,ExtTL_Subs(:,1)-0.5];
ExtTR_verts=[ExtTR_Subs(:,2)+0.5,ExtTR_Subs(:,1)-0.5];
ExtBL_verts=[ExtBL_Subs(:,2)-0.5,ExtBL_Subs(:,1)+0.5];
ExtBR_verts=[ExtBR_Subs(:,2)+0.5,ExtBR_Subs(:,1)+0.5];
IntTL_verts=[IntTL_Subs(:,2)-0.5,IntTL_Subs(:,1)-0.5];
IntTR_verts=[IntTR_Subs(:,2)+0.5,IntTR_Subs(:,1)-0.5];
IntBL_verts=[IntBL_Subs(:,2)-0.5,IntBL_Subs(:,1)+0.5];
IntBR_verts=[IntBR_Subs(:,2)+0.5,IntBR_Subs(:,1)+0.5];
%% Makes column indicating of direction of next vertex (in polar coords)
ExtTLlabel=repmat(0,size(ExtTL_verts,1),1);
ExtTRlabel=repmat(-pi/2,size(ExtTR_verts,1),1);
ExtBLlabel=repmat(pi/2,size(ExtBL_verts,1),1);
ExtBRlabel=repmat(pi,size(ExtBR_verts,1),1);
IntTLlabel=repmat(pi/2,size(IntTL_verts,1),1);
IntTRlabel=repmat(0,size(IntTR_verts,1),1);
IntBLlabel=repmat(pi,size(IntBL_verts,1),1);
IntBRlabel=repmat(-pi/2,size(IntBR_verts,1),1);
Vertices_Cat=[...
ExtTL_verts;...
ExtTR_verts;...
ExtBL_verts;...
ExtBR_verts;...
IntTL_verts;...
IntTR_verts;...
IntBL_verts;...
IntBR_verts];
Directions_Cat=[...
ExtTLlabel;...
ExtTRlabel;...
ExtBLlabel;...
ExtBRlabel;...
IntTLlabel;...
IntTRlabel;...
IntBLlabel;...
IntBRlabel];
Vertices_Cat=[Vertices_Cat,Directions_Cat];
%% Order Vertices clockwise round perimeter of cluster
Nvertices=size(Vertices_Cat,1);
ThisVertex=Vertices_Cat(1,:);
Vertices_Cat(1,:)=[NaN,NaN,NaN];
StartVertex=ThisVertex;
PerimeterID=1;
iVertex=1;
ClusterVertices=NaN(Nvertices,3);
ClusterVertices(1,1:2)=ThisVertex(1:2);
ClusterVertices(iVertex,3)=PerimeterID;
for iVertex=2:Nvertices
switch ThisVertex(3)
case 0 % Go right
NextIdx=find(Vertices_Cat(:,2)==ThisVertex(2));
Possibles=Vertices_Cat(NextIdx,:);
if StartVertex(2)==ThisVertex(2)
Possibles=[StartVertex;Possibles];
end
Possibles=Possibles(Possibles(:,1)>ThisVertex(1),:);
NextVertex=Possibles(Possibles(:,1)==min(Possibles(:,1)),:);
NextVertex=NextVertex(1,:); % to handle cases where the same vertex occurs twice
case pi % Go left
NextIdx=find(Vertices_Cat(:,2)==ThisVertex(2));
Possibles=Vertices_Cat(NextIdx,:);
if StartVertex(2)==ThisVertex(2)
Possibles=[StartVertex;Possibles];
end
Possibles=Possibles(Possibles(:,1)<ThisVertex(1),:);
NextVertex=Possibles(Possibles(:,1)==max(Possibles(:,1)),:);
NextVertex=NextVertex(1,:);
case pi/2 % Go up
NextIdx=find(Vertices_Cat(:,1)==ThisVertex(1));
Possibles=Vertices_Cat(NextIdx,:);
if StartVertex(1)==ThisVertex(1)
Possibles=[StartVertex;Possibles];
end
Possibles=Possibles(Possibles(:,2)<ThisVertex(2),:);
NextVertex=Possibles(Possibles(:,2)==max(Possibles(:,2)),:);
NextVertex=NextVertex(1,:);
case -pi/2 % Go down
NextIdx=find(Vertices_Cat(:,1)==ThisVertex(1));
Possibles=Vertices_Cat(NextIdx,:);
if StartVertex(1)==ThisVertex(1)
Possibles=[StartVertex;Possibles];
end
Possibles=Possibles(Possibles(:,2)>ThisVertex(2),:);
NextVertex=Possibles(Possibles(:,2)==min(Possibles(:,2)),:);
NextVertex=NextVertex(1,:);
end
if ~ismember(NextVertex,StartVertex,"rows")
ThisVertex=NextVertex;
else
PerimeterID=PerimeterID+1;
VerticesLeftIdx=find(~isnan(Vertices_Cat(:,1)));
ThisVertex=Vertices_Cat(VerticesLeftIdx(1),:);
StartVertex=ThisVertex;
end
[~,idx]=ismember(ThisVertex,Vertices_Cat,'rows');
Vertices_Cat(idx,:)=[NaN,NaN,NaN];
ClusterVertices(iVertex,1:2)=ThisVertex(1:2);
ClusterVertices(iVertex,3)=PerimeterID;
end
%% Remove padding from vertex coordinates
ClusterVertices(:,1:2)=ClusterVertices(:,1:2)-1;
end
Then I used the ClusterVertices matrix with patch.m:
Perimeters=ClusterVertices(:,3);
Nperimeters=max(Perimeters);
for iPerimeter=1:Nperimeters()
patch('Faces',1:sum(Perimeters==iPerimeter),'Vertices',...
ClusterVertices(Perimeters==iPerimeter,1:2),...
'FaceColor','none', 'EdgeColor','k','LineWidth',1)
end

Categories

Find more on Vector Fields in Help Center and File Exchange

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!