Loren on the Art of MATLAB

October 31st, 2008

Olympic Rings

Well, I am very late on this challenge. In August, Mike posted some code to reproduce the Olympic rings and mentioned that I might have a more clever way to create the same plot. Here's my attempt.

Contents

Create X and Y Values for the 5 Rings

First, I'll follow Mike's parameters and code to create the initial five rings.

N = 1000;
angle = linspace(pi/4,9*pi/4,N);

xb = cos(angle) * 0.9;
yb = sin(angle) * 0.9;

xy = cos(angle) * 0.9 + 1;
yy = sin(angle) * 0.9 - 1;

xk = cos(angle) * 0.9 + 2;
yk = sin(angle) * 0.9;

xg = cos(angle) * 0.9 + 3;
yg = sin(angle) * 0.9 - 1;

xr = cos(angle) * 0.9 + 4;
yr = sin(angle) * 0.9;

Mike's Rings

What Mike does next is to break rings into segments for plotting so the last ring plotted in any given location is the color that should be on top.

h1 = figure;
hold on
plot(xb(1:3*N/4),yb(1:3*N/4),'b','linewidth',5);
plot(xy(N/4:N),yy(N/4:N),'y','linewidth',5)

plot(xk(1:3*N/4),yk(1:3*N/4),'k','linewidth',5);
plot(xy(1:N/4),yy(1:N/4),'y','linewidth',5);
plot(xb(3*N/4:end),yb(3*N/4:end),'b','linewidth',5);

plot(xr(1:N/2),yr(1:N/2),'r','linewidth',5);
plot(xg(1:N),yg(1:N),'g','linewidth',5);

plot(xk(3*N/4:N),yk(3*N/4:N),'k','linewidth',5);
plot(xr(N/2:N),yr(N/2:N),'r','linewidth',5);

% make the axis pretty
axis equal
axis off
xlim([-1.2 5.2])
set(h1,'Color',[1 1 1])
hold off

My Solution

My "cleverness" is to offset the rings in the Z-plane.

First I noticed that all the top rings have an axis about which I can "tilt" them ever so slightly to get the most of the over/under behavior for the rings. Add small Z values to each ring.

thetab = -pi/4;
thetak = -pi/4;
thetar = -pi/4;

Now I create Z values for the rings in the upper rows by tilting them about the axes defined by the angles above (which happen to be identical).

zb = cos(angle + thetab) * 0.1;
zk = cos(angle + thetak) * 0.1;
zr = cos(angle + thetar) * 0.1;

Next I deal with the lower rings in a lazy way, introducing a discontinuity in Z. If I had more patience today, I could have come up with an undulation in Z that was more than a tilted plane or a step.

I find the angles where I need to depress the bottom rings relative to the top and set appropriate Z values for these to be less than 0.

mask = angle >= 2*pi;
zg = zeros(size(xb));
zy = zeros(size(xb));
zg(mask) = -0.1;
zy(mask) = -0.1;

Loren's Rings

Here's my rendition of the rings. My plot commands are a bit less complicated than Mike's. I do the work earlier by setting Z values. Also, because of my laziness, if you were to rotate my version of rings in 3-D, you'd see the bottom two aren't really rings, but have discontinuities.

h2 = figure;
hold on
plot3(xb,yb,zb,'b.','markersize',10);
plot3(xy,yy,zy,'y.','markersize',10);
plot3(xk,yk,zk,'k.','markersize',10);
plot3(xg,yg,zg,'g.','markersize',10);
plot3(xr,yr,zr,'r.','markersize',10);
% make the axis pretty
axis equal
axis off
xlim([-1.2 5.2])
set(h2,'Color',[1 1 1])
hold off

Any Other Methods?

Mike and I show 2 methods to generate interlocking rings. Do you have any other ideas for doing this? Let me know here.


Get the MATLAB code

Published with MATLAB® 7.7

7 Responses to “Olympic Rings”

  1. Mike replied on :

    That’s great. I’m so used to thinking in 2-dimensions with my plots.

  2. mark replied on :

    If you want to do it as an image versus a plot then you can utilize convolution since the rings are identical. Admittedly the output doesn’t look as nice as above but I think it is a nice demonstration of the conv2 function…maybe.

    % first create a ‘ring’

    x=sin(2*pi*(1/100)*(0:99));
    y=cos(2*pi*(1/100)*(0:99));
    c=zeros(32,32);
    for i=1:100
    c(ceil(15*x(i))+16,ceil(15*y(i))+16)=1;
    end

    % then create your canvas
    A=zeros(128,128);

    % set ring spacing
    n=36;

    % convolving this set of impulses with
    % the ring will make the final output array
    % the different values will change the colors
    A(64,((0:2)*n)+20)=[1 3 5];
    A(64+15,([1/2 3/2]*n)+20)=[2 4];

    % use this to test the overlaps
    D(64,((0:2)*n)+20)=[1 1 1];
    D(64+15,([1/2 3/2]*n)+20)=[1 1];

    w=conv2(D,c,’same’);

    % find where the rings overlap
    [s,t]=find(w==2);

    f=[2 2 1 2 3 4 4 3 4 5];

    % create the final output array
    r=conv2(A,c,’same’);

    % replace with the ‘right values from left to right
    for ii=1:10
    r(s(ii),t(ii))=f(ii);
    end

    % set the color map to a white background
    % and five colors
    map=[1 1 1 ; 0 0 1 ; 1 1 0 ; 0 0 0 ; 0 1 0 ; 1 0 0]

    % display
    imagesc(r)

    colormap(map);

  3. Loren replied on :

    Mark-

    Thanks so much for sharing an entirely different approach!

    –Loren

  4. Tom Elmer replied on :

    Next I deal with the lower rings in a lazy way, introducing a discontinuity in Z. If I had more patience today, I could have come up with an undulation in Z that was more than a tilted plane or a step.

    No need to add undulations, just alternate your axis (and I added an alternating offset) then increment the angles/offsets on each ring. (Of course they’re really ellipses in 3D but the 2D projection is circular. Actually, it looks kinda neat on Y-Z view.) (I wasn’t mathematically rigorous on what the coefficients should be for N rings, but I did try it out to 28 rings.)

    N = 1000;
    angle = linspace(pi/4,9*pi/4,N);

    c=’bykgr’;
    %c=’bykgrmcbykgrmcbykgrmcbykgrmc’;
    index = 1:length(c);
    UL=( ~mod(index,2) - mod(index,2) ); %negative if Upper ring, positive if Lower ring

    h2 = figure(’color’,[1 1 1]);
    hold on
    for loop=1:length(c)
    z = cos(angle + UL(loop)*pi/4) * … %alternating axes
    (length(c)-loop)*0.1*-UL(loop) + … %alternating angles
    .05*(length(c)-loop)*-UL(loop); %alternating depth offsets
    x = cos(angle) * 0.9 + (loop-1);
    y = sin(angle) * 0.9 - ~mod(loop,2);
    plot3(x,y,z,[c(loop) ‘.’],’markersize’,10);
    end
    axis equal off
    hold off

  5. Loren replied on :

    Tom-

    Thanks for an interesting and elegant solution!

    –Loren

  6. Hung Dang replied on :

    I fix Loren’s code a little bit to be able to reuse x and y and with a shorter plot command ;)

    %% Init parameters
    R = 0.9;
    scale = 1.1;
    N = 100;
    thickness = 10;
    angle = linspace(0,2*pi,N);

    %% Plot the rings
    y = R * sin(angle);
    x = R * cos(angle);
    plot(x,y,’b',x + scale * R,y - scale * R,’k',x + 2 * scale * R,y,’r',…
    x + 3 * scale * R, y - scale * R,’g',x + 4 * scale * R,y,’k',…
    ‘LineWidth’,thickness);

    %% Make axis look better
    axis off;
    set(gca,’XLim’,[-1.2 5.2]);
    set(gcf,’Color’,[1 1 1]);

  7. Tom Elmer replied on :

    I fix Loren’s code a little bit to be able to reuse x and y and with a shorter plot command ;)

    You missed the important part of the exercise in that the rings have to be interlocking :D

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.