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

EB.gif

 

CODE

* Fun w/SAS ODS Graphics: Animated Easter Bunny from points in math-aids.com graphing worksheet;

data EasterBunny(keep=shapeID x y polyX polyY);
length shapeID $ 20. x 8 y 8;
retain shapeID;                                
infile "/folders/myfolders/EB.txt" lrecl=1000;  * File contains points to plot from math-aids.com;
input;
if _infile_=:'Shape' then
  shapeID=_infile_;
else
  do;
    i=1;
    do while(scan(_infile_, i, ' ')^='');
      x=scan(_infile_, i, '(), ');
      y=scan(_infile_, i+1, '(), ');
      i+2;                                      * List of shapes to color on final slide;
      if shapeID in ('Shape 16' 'Shape 17' 'Shape 21' 'Shape 22'   
                     'Shape 3'  'Shape 4'  'Shape 5'  'Shape 6' 
                     'Shape 9'  'Shape 10' 'Shape 11' 'Shape 12') then
        do; polyX=x; polyY=y; end;
      output;
    end;
  end;
                                                 * Lines to draw;
data line(keep=function drawspace x1 y1 x2 y2 polyX polyY);
set EasterBunny;
by shapeID notsorted;
function='line';
drawspace='datavalue';
x1=lag(x);
y1=lag(y);
x2=x;
y2=y;
if ^first.shapeID;

%macro gentemplate(final=Y);                    * Draw the bunny!;
proc template;
define statgraph ebtemplate;
  begingraph;
    dynamic linenum;
    layout overlayequated / walldisplay=none
      xaxisopts=(display=none offsetmin=0.001 offsetmax=0.001)
      yaxisopts=(display=none offsetmin=0.001 offsetmax=0.001);
      scatterplot x=x y=y / markerattrs=(size=0);
      %if &final=Y %then %do;
      polygonplot x=PolyX y=PolyY id=ShapeID / display=(fill) label=none fillattrs=(color=pink);
      ellipseparm semimajor=.5 semiminor=.5 xorigin=-2 yorigin=2.5 slope=0 / display=all outlineattrs=(thickness=2pt) fillattrs=(color=pink);
      ellipseparm semimajor=.5 semiminor=.5 xorigin=-.5 yorigin=2.5 slope=0 / display=all outlineattrs=(thickness=2pt) fillattrs=(color=pink);
      %end;
      entry halign=right linenum / valign=bottom textattrs=(size=32 weight=bold color=lightgray);
      annotate;
    endlayout;
  endgraph;
end;
run;
%mend;

* Create animated GIF with one incremental plot for each line;

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

%macro drawlines;
proc sql noprint;
select count(*) into :numlines from line;
quit;                   

%gentemplate(final=Y);                          * Display final image before drawing lines;
options animduration=1.8;
proc sgrender data=easterbunny template=ebtemplate sganno=line;
dynamic linenum=" "; 

options animduration=.04;                       * Line-by-line drawing;
%gentemplate(final=N); 
%do l=1 %to &numlines;                          * Draw incremental image with lines thus far;  
  proc sgrender data=easterbunny template=ebtemplate sganno=line(obs=&l);
  dynamic linenum="&l";
%end; 
run; 
%mend;

%drawlines;
options printerpath=gif animation=stop;
ods printer close;

DATA

Shape 1
-10 -7 -10 -8.5 -9.5 -9.5 -9 -10 -8 -10.5 -10 -7
Shape 2
-10 -7 -10.5 -6 -10 -4 -8.5 -3 -7 -2.5 -6.5 -2.5 -5.5 -3 -4.5 -4.5
-3.5 -7 -2.5 -10 -2 -12 -2.5 -14 -4 -14.5 -5.5 -14 -7 -12 -8 -10.5
Shape 3
-9.5 -5.5 -8.5 -5.5 -8 -6 -8 -7 -9 -7 -9.5 -6 -9.5 -5.5
Shape 4
-8.5 -3.5 -7.5 -4 -7 -5 -7.5 -6 -8 -5.5 -8.5 -4.5 -8.5 -3.5
Shape 5
-6.5 -3.5 -6 -3.5 -5.5 -4 -5.5 -5 -6 -5.5 -6.5 -5 -7 -4 -6.5 -3.5
Shape 6
-7 -6.5 -6 -6.5 -5.5 -7 -4.5 -8.5 -4 -10 -3.5 -12 -3.5 -13.5
-5 -13 -6 -11.5 -7.5 -9 -8 -8 -7.5 -7 -7 -6.5
Shape 7
-6.5 -2.5 -5 -2 -4.5 -2.5 -5.5 -3
Shape 8
-1 -3.5 -2.5 -5 -1.5 -5 -2 -6 -1 -6 -1.5 -7 -1 -6.5 -1 -8.5
Shape 9
6.5 -7.5 7.5 -6 8.5 -6 8.5 -6.5 8 -7.5 7.5 -7.5 6.5 -7.5
Shape 10
7.5 -8.5 8 -8 9 -7.5 10 -7.5 9.5 -8.5 8.5 -9 8 -9 7.5 -8.5
Shape 11
8 -10 8.5 -9.5 9.5 -9.5 10 -10 9.5 -10.5 8.5 -10.5 8 -10
Shape 12
0.5 -12.5 1.5 -11 3 -10 5 -8.5 6.5 -8.5 7.5 -9 7.5 -10 7 -11
5.5 -11.5 3.5 -12.5 2 -13 0.5 -12.5
Shape 13
-2 -12 -1 -12 -0.5 -11 2 -9 4 -7.5 5.5 -6.5 7 -5.5 9 -5.5
 10.5 -6.5 11 -8 10.5 -10 9 -11.5 5 -13 2 -14 0 -14 -1 -12 
Shape 14
-4.5 -2.5 -4 -2.5 -2 -3 0 -3 2 -2.5 3 -2.5 4 -3.5 5 -5 5.5 -6 5.5 -6.5
Shape 15
5.5 -6 6 -5.5 8 -4.5 10 -3.5 11 -2 11.5 -1 11 0.5 10 1.5 9 1.5
7.5 1 6.5 0.5 6 1 5.5 0.5 5.5 -1 5 -2 4 -2.5 3 -2.5
Shape 16
0 7 0.5 9 2.5 12 5 13 6 12 5.5 11 4 9.5 2 8.5 0 7
Shape 17
-3 6 -3.5 7 -5 9.5 -6.5 11 -8 11.5 -9 11.5 -9.5 11 -9.5 10
-8.5 9 -6.5 7.5 -4 6.5 -3 6
Shape 18
-5 -2 -6 -1.5 -6.5 -1 -7 -0.5 -7 1 -6 2 -5.5 3 -5 4 -4.5 5
-3.5 5.5 -5 6.5 -7 7.5 -9.5 8.5 -11.5 9.5 -12 11 -11.5 12 -10 12.5
-9 12.5 -7 12 -5 10.5 -4 9 -2.5 7 -2 6.5 -3 6 -3.5 5.5
Shape 19
-2.5 7 -1.5 6.5 -2 7.5 -1 6.5 0 6 1.5 7.5 4 9 6 10 7.5 11
8 12.5 7.5 13.5 6 14 4 13.5 2 12 0.5 10 -0.5 8 -1 6.5
Shape 20
0 6 1.5 5 2.5 4 3 3 4 2 4.5 1 5 0 4.5 -1 4 -1.5 3 -2.5
Shape 21
-3.5 1 -3 0.5 -4 0 -5 0.5 -3.5 1 -2.5 1.5 -1.5 1.5 -1 1
-0.5 1.5 -0.5 1 -1 0.5 -1.5 0.5 -2 1 -1.5 1.5
Shape 22
-0.5 1.5 0 1.5 1.5 1.5 2.5 1.5 3 1 2 0.5 1 1 1.5 1.5
Shape 23
-1 0.5 -1 -1 0.5 -1 1 -0.5
Shape 24
-1 -1 -2 -1.5 -3 -1
2 REPLIES 2
boemskats
Lapis Lazuli | Level 10

Technically this is completely off topic as it doesn't use ODS or SAS/GRAPH, but I spent almost an hour doing it so I can't not post it now. Here's the same in JavaScript, using a slightly modified version of the original SAS code to create the SVG, and vivus.js to animate it:

 

bunny.gif

 

The SAS code to generate the SVG looks like:

 

data _null_;
  length shapeID $ 20. x 8 y 8;
  gh = 40; * grid height ;
  gw = 30; * grid width ;
  file "/pub/ht/bunny/my.svg"; * target SVG location and write header ;
  if _n_ eq 1 then 
    put '<svg width="' gw +(-1) '0" height="' gh +(-1) '0" viewBox="0 0 ' gh gw '" id="bunny">';
  infile "/pub/programs/EB.txt" lrecl=1000 end=EOF;  * File contains points to plot from math-aids.com;
  input;
  if _infile_=:'Shape' then do;
    shapeID=_infile_;
    if _n_ gt 1 then put '"/>'; * unless its the first element we will need to close last one ;
    if shapeID in ('Shape 16' 'Shape 17' 'Shape 21' 'Shape 22'   
               'Shape 3'  'Shape 4'  'Shape 5'  'Shape 6' 
               'Shape 9'  'Shape 10' 'Shape 11' 'Shape 12') then
    put '<polygon fill="none" stroke="#FF8A65" stroke-width="0.2" points="' @;
    * if this is a polygon then it is a polygon, else it is a polyline ;
    else put '<polyline fill="none" stroke="#FF8A65" stroke-width="0.2" points="' @;
  end;
  else do;
    i=1;
    do while(scan(_infile_, i, ' ')^='');
      x=scan(_infile_, i, '(), ') + ((gw / 2));
      put x +(-1) ',' @;
      y=((gh / 2) - scan(_infile_, i+1, '(), '));
      put y @;
      i+2;  
      output;
    end;
  end;
  if EOF then put '"/></svg>';
run;

 

 The Vivus JS constructor to animate it looks like:

 

new Vivus('bunny', {
    type: 'oneByOne',
    duration: 800,
    pathTimingFunction: Vivus.EASE_OUT,
});

 

If anyone wants to see the generated SVG or have a play around with the JavaScript code, the example is up on JsFiddle: http://jsfiddle.net/m3xswhnz/.

 

Hurray for long weekends.

 

Nik

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

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
  • 2045 views
  • 7 likes
  • 3 in conversation