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: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 2 replies
  • 1951 views
  • 7 likes
  • 3 in conversation