views:

64

answers:

2

I would like to plot how the amplitude and orientation of a 2D vector evolves over time. To do this I would like to create a graph reminiscent of the canonical E & B field graphs you may recall from an introductory electricity and magnetism class.

alt text

Specifically, I would like to connect my 2D vector points with a ribbon, so that they are easy to see. Is there a simple way to do this in MATLAB? quiver3 is pretty close, but it lacks the ribbon. Perhaps some sort of parametric surface?

+5  A: 

You can use the plotting functions FILL3 and QUIVER3 to do something like this:

x = linspace(0,4*pi,30);  %# Create some x data
y1 = sin(x);              %# Create wave 1
y2 = sin(x-pi);           %# Create wave 2
u = zeros(size(x));       %# Create a vector of zeroes

hRibbon1 = fill3(x,y1,u,'r');     %# Plot wave 1 and fill underneath with color
set(hRibbon1,'EdgeColor','r',...  %# Change the edge color and
             'FaceAlpha',0.5);    %#   make the colored patch transparent
hold on;                          %# Add to the existing plot
quiver3(x,u,u,u,y1,u,0,'r');      %# Plot the arrows

hRibbon2 = fill3(x,u,y2,'b');     %# Plot wave 2 and fill underneath with color
set(hRibbon2,'EdgeColor','b',...  %# Change the edge color and
             'FaceAlpha',0.5);    %#   make the colored patch transparent
quiver3(x,u,u,u,u,y2,0,'b');      %# Plot the arrows
axis equal;                       %# Use equal axis scaling

And here's the resulting plot:

alt text

gnovice
This is quite brilliant and exactly recapitulates the figure, but it has some limitations for what I am trying to do. I am interested in the case where the vector can rotate. E.g. y=sin(t), x=sin(t-pi/2) and where the vector is free to not necessarily start or end at zero. In other words a twisting ribbon. In this example the ribbon only works if the vector starts or ends at zero and the fill does not seem to deal with a twisting curve well. I apologize if this was less clear in the question. I had a hard time finding a twisty ribbon diagram online.
AndyL
+2  A: 

here's a solution that draws a ribbon between any two lines in 3D space. you can plot your quiver over it & adjust the opacity using 'FaceAlpha' as in gnovice's solution

To make the function clearer, I am first posting it without error-checking and resizing functions (which make up most of the body of the function & aren't particularly interesting)

function h = filledRibbon (x,y,z,u,v,w,c, varargin)
%function filledRibbon (x,y,z,u,v,w,c, varargin)
%
%plots a ribbon spanning the area between the lines x,y,z and x+u,y+v,z+w
%in the color c
%varargin is passed directly to patch
%returns a handle to the patch graphic created

%make up a set of regions that span the space between the lines

xr = [x(1:end-1); x(1:end-1) + u(1:end-1); x(2:end) + u(2:end); x(2:end)];
yr = [y(1:end-1); y(1:end-1) + v(1:end-1); y(2:end) + v(2:end); y(2:end)];
zr = [z(1:end-1); z(1:end-1) + w(1:end-1); z(2:end) + w(2:end); z(2:end)];

%plot the regions with no edges
h = patch(xr,yr,zr,c, 'LineStyle','none', varargin{:});

use this error-checking version in your actual code:

function h = filledRibbon (x,y,z,u,v,w,c, varargin)
%function filledRibbon (x,y,z,u,v,w,c, varargin)
%
%plots a ribbon spanning the area between the lines x,y,z and x+u,y+v,z+w
%in the color c
%varargin is passed directly to patch
%returns a handle to the patch graphic created


if ~exist('w', 'var') || isempty(w)
    w = 0;
end
if ~exist('u', 'var') || isempty(u)
    u = 0;
end
if ~exist('v', 'var') || isempty(v)
    v = 0;
end
if ~exist('c', 'var') || isempty(c)
    c = 'b';
end


%make all vectors 1xN 
x = reshape(x,1,[]);
y = reshape(y,1,[]);
z = reshape(z,1,[]);

%if any offsets are scalar, expand to a vector
if all(size(u) == 1)
    u = repmat(u, size(x));
end

if all(size(v) == 1)
    v = repmat(v, size(x));
end
if all(size(w) == 1)
    w = repmat(w, size(x));
end

%make up a set of regions that span the space between the lines

xr = [x(1:end-1); x(1:end-1) + u(1:end-1); x(2:end) + u(2:end); x(2:end)];
yr = [y(1:end-1); y(1:end-1) + v(1:end-1); y(2:end) + v(2:end); y(2:end)];
zr = [z(1:end-1); z(1:end-1) + w(1:end-1); z(2:end) + w(2:end); z(2:end)];

%plot the regions with no edges
h = patch(xr,yr,zr,c, 'LineStyle','none', varargin{:});
Marc
Brilliant! I ran this: x=[0:.1:3*pi]; w=sin(x); v=cos(x); u=zeros(size(x)); y=zeros(size(x)); z=zeros(size(x)); c='r'; filledRibbon(x,y,z,u,v,w,c,'FaceAlpha',0.2); axis vis3d; It works like a charm.
AndyL