I have the following Matlab plot representing a graph. I would like to display the darker on top of the lighter ones in such a way the lighter edges don't modify the darker when crossing them. How could I do?
Edit: the Matlab code for reproduce the example is the following
plot(G, 'XData', Xcoords, 'YData', Ycoords,'NodeLabel',{}, 'MarkerSize', 7,...
'Linewidth',1.6, 'EdgeCData', G.Edges.Weight)
colormap(flipud(gray(40)));
colorbar('southoutside');
caxis([min(G.Edges.Weight) max(G.Edges.Weight)])
axis off
where the weights of the edges are encoded in G.Edges.Weight
To reproduce the effect (with a smaller graph), you can try with the following code:
A= zeros(4,4);
A(1,[2 3 4])=1;
A(2,4)=0.04;
A(2,[1 3])=1;
A(3,[2 1 4])=1;
A(4,2)=0.04;
A(4,[3 1])=1;
Xcoords=[1 2 2 1]';
Ycoords= [1 1 2 2 ]';
G= graph(A);% base toolbox
figure()
plot(G, 'XData', Xcoords, 'YData', Ycoords, 'NodeLabel',{}, 'MarkerSize', 7,...
'LineWidth', 3.8, 'EdgeCdata', G.Edges.Weight)
colormap(flipud(gray(40)));
colorbar('southoutside'); caxis([0 1]);
axis off
It seems that is the ordering of the edges that decide who is on top. For instance, if the weight 0.04 is assigned to the other crossing edge (A(1,3)=A(3,1)) the effect is not visible since the edge A(2,4)=A(4,2) cames after.
The order of the edge table in MATLAB's graph
class seems pretty tightly dependent on position in the graph's adjacency matrix, which is inherently impossible to contrive in a way that guarantees some arbitrary edge order. So I think you only have two options:
The second option is possible by noting that the plotted GraphPlot
object has a LineStrip
object in its NodeChildren
which is responsible for drawing all the relevant edges. Because you're using a grayscale color map, the RGB data in this object is all you need to figure out how its vertices need to be ordered to get the right plot order.
First, store the plotted result in P
and set EdgeAlpha
to 1
so the graph is plotted
in such a way the lighter edges don't modify the darker when crossing them
P = plot(G, 'XData', Xcoords, 'YData', Ycoords, 'NodeLabel',{}, 'MarkerSize', 7,...
'LineWidth', 3.8, 'EdgeCdata', G.Edges.Weight, 'EdgeAlpha',1);
colormap(flipud(gray(40)));
colorbar('southoutside'); caxis([0 1]);
axis off
Then find the LineStrip
created in the drawing process:
drawnow
s = P.NodeChildren(arrayfun(@(o) isa(o,'matlab.graphics.primitive.world.LineStrip'), P.NodeChildren));
The new order of the vertices in s
can then be determined from its ColorData
, which must then be applied to both the ColorData
and VertexData
properties to reorder the edges without anything else changing:
[~,idx] = sortrows(s.ColorData','desc');
set(s, 'VertexData',s.VertexData(:,idx), 'ColorData',s.ColorData(:,idx));
This will be liable to be overridden by any further redrawing that takes place and being undocumented functionality comes with no guarantees as to how it will behave – but superficially it seems to do what you're looking for.