BookmarkSubscribeRSS Feed
tc
Lapis Lazuli | Level 10 tc
Lapis Lazuli | Level 10

Fold line of length 2*PI*r into a circleFold line of length 2*PI*r into a circle

Inspired by a @Rick_SAS  blog post, here's a last-minute PI Day chart (hey, it's still PI Day in Hawaii! Smiley Happy).

 

*==> Fun w/SAS ODS Graphics: Fold line of length 2*PI*R into a circle;

data circle;                                          * Calc x/y points for circle of N points; 
retain xR yR xRO 0 yRO 1 tR "r=1";                    * Used to draw unit circle radius;
seq=0; xo=-constant("pi"); yo=-1; x=-xo; y=yo; output; x=.; * Starting line segment of length 2*PI;                                    
N=40;                                                 * Number of line segments in circle (40+ is good, multiples of 4);
d=constant("pi");                                     * Loop for points on right side of circle;
do a=-2*constant("pi")/4 to 2*constant("pi")/4 by 2*constant("pi")/N;    
  x=cos(a);                                           * Assume unit circle with radius=1;      
  y=sin(a);
  xo=cos(lag(a));                                     * Prior x/y point;
  yo=sin(lag(a));
  if xo^=. then do;                                   * Output circle line segments;
    seq+1;
    d=d-2*constant("pi")/N;                           * "Unused" line segment (drawn perpindicular to last points on circle);
    m=-1/(y/x);                                       * Slope of tangent to current point on circle;
    if m=. then do;                                   * Slope=infinity (x=0)?;
      xT=x;                                           * Yes, calculate x/y endpoint of "unused" line;
      yT=y+d;
      end;
    else do;                                          * No, calculate x/y endpoint of "unused" line; 
      xT=x+sign(m)*d/sqrt(1+m**2);                    * Slope determines x direction;
      yT=y+abs(m)*d/sqrt(1+m**2);                     * y direction always positive;           
      end;  
    output; 
    x=-x;                                             * Negate x values for left side of circle;
    xo=-xo;
    xT=-xT;
    output;
    end;
end;

proc sql;                                             * Determine frames needed for GIF;
create table framenums as select distinct seq as frame from circle;

create table frames as                                /* Create frames with needed points */ 
select frame, seq, x, y, xo, yo, xR, yR, tR, xRO, yRO,
       case when f.frame=c.seq then xT end as xT, case when f.frame=c.seq then yT end as yT
from framenums f, circle c where f.frame>=c.seq and (f.frame=0 or c.seq>0) order by 1, 2;

ods _all_ close;                                      * Animated GIF setup;
options papersize=('5 in', '5 in') printerpath=gif animation=start 
        nodate nonumber animloop=YES NOANIMOVERLAY animduration=.5;
ods printer file='/folders/myfolders/piDayV2.gif';
ods graphics / width=5in height=5in imagefmt=GIF;

%macro genCircle(start=, stop=, dur=);
options nobyline animduration=&dur;                   * Create plots;
proc sgplot data=frames aspect=1 noautolegend;
by frame;
where &start<=frame<=&stop;             
vector x=xR y=yR / xorigin=xRO yorigin=yRO            /* Radius */
       noarrowheads  datalabel=tR datalabelpos=bottom lineattrs=(pattern=shortdash);  
vector x=x y=y / xorigin=xo yorigin=yo noarrowheads;  /* Segments of circles */
vector x=x y=y / xorigin=xT yorigin=yT noarrowheads;  /* Remaining "unused" line segment */
xaxis display=(nolabel) min=-3.25 max=3.25 offsetmin=.01 offsetmax=.01 
      values=(-3.14 -2 -1 0 1 2 3.14) valuesdisplay=("-(*ESC*){Unicode pi}" "-2" "-1" "0" "1" "2" "(*ESC*){Unicode pi}");
yaxis display=(nolabel) min=-3.25 max=3.25 offsetmin=.01 offsetmax=.01
      values=(-3.14 -2 -1 0 1 2 3.14) valuesdisplay=(" " "-2" "-1" "0" "1" "2" " ");
inset "2(*ESC*){Unicode pi}r" / position=top textattrs=(size=18pt);   
inset "Circumference" / position=bottom textattrs=(size=18pt);    
run;
%mend;
%genCircle(start=0, stop=0, dur=.5);                  * Start frame (.5 seconds);
%genCircle(start=0, stop=20, dur=.15);                * Draw circle (.15 seconds/frame);
%genCircle(start=20,stop=20, dur=.5);                 * Final frame (.5 seconds);

options printerpath=gif animation=stop;               * Animated GIF wrapup;
ods printer close;

 

2 REPLIES 2
Rick_SAS
SAS Super FREQ

Using an invisible REFLINE to get custom labels is a neat trick. You can achieve the same result by using the 

VALUES and VALUESDISPLAY option on the XAXIS and YAXIS statements. No need for invisible lines.

tc
Lapis Lazuli | Level 10 tc
Lapis Lazuli | Level 10

Right, you are, Rick! Modified above code/image (tossed in a radius line and titles, too).

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 2 replies
  • 1024 views
  • 9 likes
  • 2 in conversation