6

I need to plot a list of 3d lines in matlab. What is the quickest way to do that? I am currently doing something like

%edges is a MX2 matrix, holding the list of edges
%points are the vertices' coordinates
hold on; %so all the lines will be saved
for i=1:size(edges,1)
    a=edges(i,1); %get first point's index
    b=edges(i,2); %get second point's index
    p=[points(:,a) points(:,b)]; %construct a 3X2 matrix out of the 2 points
    plot3(p(1,:),p(2,:),p(3,:)); %plot a line
end

But this is not only slow during the actual loop, but also at the end, the resulting plot is very slow and irresponsive when I try to, for instance, rotate it using the drag & rotate tool.

I know the same plot using opengl etc would run much faster...

olamundo
  • 23,991
  • 34
  • 108
  • 149

2 Answers2

6

You can use the LINE low-level function, using NaN to plot as separate segments:

%# sample graph vertices and edges (similar to your data)
[adj,XYZ] = bucky;
[r c] = find(adj);
edges = [r c];      %# M-by-2 matrix holding the vertex indices
points = XYZ';      %# 3-by-N matrix of points X/Y/Z coordinates

%# build a list of separated lines
e = edges';
e(end+1,:) = 1;
e = e(:);
p = points(:,e);
p(:,3:3:end) = NaN;

figure
h = line(p(1,:), p(2,:), p(3,:));
view(3)

This is very efficient as it creates a single line object. Now you can customize the line, but it is restricted to have one color for the entire thing:

set(h, 'Color',[.4 .4 1], 'Marker','.', 'MarkerSize',10, ...
    'MarkerFaceColor','g', 'MarkerEdgeColor','g')

line


According to the comments, if you want to have each edge in your graph in a specified color, consider the following code instead. It involves using the SURFACE function:

p = p';                      %'# transpose the above p for convenience
clr = (1:size(p,1))';        %'# for each edge, color index in current colormap
figure
surface(p(:,[1 1]), p(:,[2 2]), p(:,[3 3]), [clr clr], ...
    'EdgeColor','flat', 'FaceColor','none')
colormap( hsv(numel(clr)) )  %# specify your colormap here
view(3)

surface

Amro
  • 123,847
  • 25
  • 243
  • 454
  • The `surface` solution is the closest to what's asked, but if you check http://www.mathworks.com/help/techdoc/ref/surface_props.html, it again seems that the `edgecolor` is only set indirectly via the vertex colour data (It implies all edges per face share the colour of the lowest numbered vertex), rather than specifying a colour for each edge directly - which is what is wanted. Based on a quick check, this seems to give the same behaviour as the `patch` solution. Maybe I missed something?? – Darren Engwirda Aug 21 '11 at 20:41
1

I think you can do something like this (caution - brain compiled code...)

figure;
patch('faces', edges, 'vertices', points, 'edgecolor', 'b');
axis equal;

Where edges should be an Nx2 matrix of indices and points should be an Mx3 matrix of coordinates (the transpose of your points array).

From my experience, calling patch directly can be significantly faster than repeated calls to plot.

To give some idea, the times to generate 1000 randomly generated line segments, using my (admittedly old!) MATLAB 7.1 are as follows:

  1. Calling patch: 0.03 seconds.
  2. Calling plot: 0.5 seconds.

EDIT: One way to get the edge colour behaving as you want (specifying a single colour per edge) is to introduce duplicate vertices as follows:

This works-around the issue that the edge colour can only be specified indirectly via vertex colour data. If we were to rely only on the vertex colours then all edges sharing a common vertex might end up with the colour assigned to that vertex - check out the 'flat 'edgecolour description here.

%% a "star" shape, so that we can really see what's going on 
%% with the edge colours!!
pp = [0,0,0; 1,-1,0; 1,1,0; -1,1,0; -1,-1,0];
ee = [1,2; 1,3; 1,4; 1,5];

%% important - only 1 colour known per edge, not per vertex!!
cc = (1:size(ee,1))'; 

%% setup a new set of vertices/edges/colours with duplicate vertices
%% so that each edge gets it's correct colour
nnum = 0;
pnew = zeros(2 * size(ee, 1), 3); %% new vertices
enew = zeros(1 * size(ee, 1), 2); %% new edge indices
cnew = zeros(2 * size(ee, 1), 1); %% new edge colours - via vertices
for j = 1 : size(ee, 1)
    n1 = ee(j, 1); %% old edge indices
    n2 = ee(j, 2);
    enew(j, 1) = nnum + 1; %% new edge indicies into pnew
    enew(j, 2) = nnum + 2;
    pnew(nnum + 1, :) = pp(n1, :); %% create duplicate vertices
    pnew(nnum + 2, :) = pp(n2, :);
    cnew(nnum + 1) = cc(j); %% map single edge colour onto both vertices
    cnew(nnum + 2) = cc(j);
    nnum = nnum + 2;
end

%% Draw the set efficiently via patch
tic
figure;
hold on;
patch('faces', enew, 'vertices', pnew, 'facevertexcdata', cnew, ...
    'edgecolor', 'flat', 'facecolor', 'none');
plot(pnew(:,1), pnew(:,2), 'b.');
axis equal;
toc

It would be nicer if MATLAB allowed you to directly specify the edge colour data - but it doesn't seem to support that...

Hope this helps.

Darren Engwirda
  • 6,915
  • 4
  • 26
  • 42
  • Thanks! Is there a chance you can also show me how can I send an array of colors so that each edge would be colored with a different color? – olamundo Aug 21 '11 at 13:01
  • @noam: There are a few different colouring options, depending on what you want. You can use the `'facevertexcdata'` parameter to set interpolated colours from the vertices - type `edit trimesh` to get an idea along these lines. If you just wanted a few flat colours (`'b', 'k', 'r', etc`) I guess you could break the edges into a few different groups and choose a single colour for each group - I'm assuming here that you have many more edges than colours. There may be other options - check the documentation... – Darren Engwirda Aug 21 '11 at 13:11
  • I actually need to color each edge with a different color, out of many colors (Say I am displaying the stress exerted on all the support beams of some structure). So I need to specify the color by edge, not by vertex, and I can't break the edges into several different groups as there are a lot of colors... – olamundo Aug 21 '11 at 13:27
  • @noam: It seems you can get individual edge colours, but only indirectly from vertex colour indexing - check out the `edgecolor` section here http://www.mathworks.com/help/techdoc/ref/patch_props.html. Unfortunately, I'm not sure it can do what you want... – Darren Engwirda Aug 21 '11 at 13:54
  • 2
    @noam: Check the two solutions I added: one using LINE with a single color, the other using SURFACE for multicolored lines.. – Amro Aug 21 '11 at 16:22