Examples: Generating Animated GIF Images

About These Examples

You can find an additional example, GWBANIMA, in the Sample Library.

Example: Creating an Animated GIF with BY-Group Processing

This example generates an animated GIF from a SAS data set and two invocations of the GCHART procedure, each of which uses BY-group processing. It also generates an HTML file that enables you to view the animation.
The following figure shows the first image of the animated GIF only. After a specified time lapse, the chart for each quarter of each of the two years is displayed in turn.
Vertical bar chart of 1993 Q1 sales in Canada and Germany
Here is the example program code. As you review the code, notice the following features:
  • The GSFNAME= graphics option specifies the file reference that defines the name of the GIF file that is to be created. In this example, the value of GSFNAME= is specified as gifout, which is defined as the file gifanim1.gif in a FILENAME statement.
  • The statement goptions gsfmode=append; is included before the second invocation of PROC GCHART so that the output is appended to the same GIF file.
  • FILENAME statements specify the filename of the GIF file and the HTML file to be created by the PUT statements.
/* Specify output files for the images and the HTML code */
filename gifout  "gifanim1.gif";  /* Image output */
filename htmlout "gifanim1.htm";   /* HTML output */

/* Close the HTML destination */
ods html close;

/* Open ODS LISTING and specify the graph style */
ods listing style=harvest;

 /* Delete the previously created graphs before creating new ones */
proc greplay igout=work.gseg nofs;
    delete _all_;
run; quit;

 /* Use gifout to specify the name of the GIF file */
goptions reset=all device=gifanim gsfname=gifout
    gsfmode=replace   /* not necessary when using "BY" */
    delay=150         /* set delay between images      */
    border;

/* Create our data set by extracting information on Canada */
/* and Germany from sashelp.prdsale. */
data work.qsales;
    set sashelp.prdsale(where=(country="CANADA" or country="GERMANY")
    keep=Actual Country Product Quarter Year);
run;

/* Sort our data by quarter */
proc sort data=work.qsales;
    by quarter;
run;

/* Generate the first set of graphs */
title1 "1993 Sales";
proc gchart data=work.qsales(where=(year=1993));
    vbar3d country / sumvar=actual subgroup=product sum
    shape=hexagon;
    where product in ("BED" "TABLE" "CHAIR");
    by quarter;
run;
quit;

/* Set the GSFMODE= graphics option to append the subsequent graphs to
   the file */
goptions gsfmode=append;

/* Generate the second set of graphs */
title1 "1994 Sales";
proc gchart data=work.qsales(where=(year=1994));
    vbar3d country / sumvar=actual subgroup=product sum
    shape=hexagon;
    where product in ("BED" "TABLE" "CHAIR");
    by quarter;
run;
quit;

/* Write the trailer to the GIF file. Since we */
/* used BY-group processing, use a DATA step */
data _null_;
    file gifout recfm=n mod; 
    put "3B"x;
run;

/* Create the HTML file to view the animated GIF */
data _null_ ;
    file htmlout ;
    put "<HTML>";
    put "<HEAD>";
    put "<TITLE> GIFANIM </TITLE>";
    put "</HEAD>";
    put "<BODY>";
    put "<IMG src='gifanim1.gif'>";
    put "</BODY>";
    put "</HTML>";
run;
quit;

/* Close the LISTING destination and open the HTML destination */
ods listing close;
ods html;
Here is the code in the HTML file that is generated by the PUT statements.
<HTML>
<HEAD>
<TITLE> GIFANIM </TITLE>
</HEAD>
<BODY>
<IMG src='gifanim.gif'>
</BODY>
</HTML>
Note: Instead of embedding PUT statements in a SAS program, you can manually create your own HTML file using an editor of your choice.

Example: Creating an Animated GIF with RUN-Group Processing

This example generates an animated GIF using RUN-group processing. RUN-group processing is used to show the 1993 sales data in a specific product order: desks, tables, chairs, sofas, and beds.
The following display shows the first image of the animated GIF only.
Vertical bar chart of 1993 desk sales in Canada, Germany, and the U.S.A.
The animation iterates through the sales data for Canada, Germany, and the U.S.A. The animation waits two seconds between each image and iterates through the animation four times. The animation stops after the fourth iteration and displays the first graph (desks).
The images are generated using the GCHART procedure with RUN-group processing and WHERE clauses to select individual products. Transparency is enabled for each image, so that the Web browser background shows through the unoccupied areas of each image. PUT statements are then used to generate an HTML file that enables you to view the animation with a Web browser. The <BODY> tag in the HTML code specifies a Web browser background color of #F2F2CF, which shows through the image.
You can change the delay between each image by changing the DELAY= graphics option. You can change the number of iterations by changing or removing the ITERATIONS= graphics option. You can also remove the TRANSPARENCY graphics option or change it to NOTRANSPARENCY to see the effect that transparency has on the image.
Here is the example program code.
/* Create file references for the output */
filename gifout "gifanim2.gif";   /* Image output */
filename htmout "gifanim2.html";  /* HTML output */

/* Close the ODS HTML destination */
ods html close;

/* Open ODS LISTING and specify the graph style */
ods listing style=highcontrast;

 /* Delete the previously created graphs before creating new ones */
proc greplay igout=Work.Gseg nofs;
    delete _all_;
run; quit;

 /* Set graphics options */
goptions reset=all device=gifanim gsfmode=replace gsfname=gifout noborder
    transparency        /* Let the browser background show through */
    disposal=background /* Restore the background between images */
    delay=200           /* Wait 2 seconds between each image */
                        /* (200 x 0.01s) */
    iterations=4        /* Run the animation four times */
    gsfname=gifout gsfmode=replace;

/* Generate the graphs using RUN-group processing */
title1 "1993 Sales";
proc gchart data=sashelp.prdsale(where=(year=1993));
    title2 "Desks";
    vbar3d country / sumvar=actual;
    where product="DESK";
run;

/* Set the GSFMODE= graphics option to append the remaining graphs */
goptions gsfmode=append;

    title2 "Tables";
    vbar3d country / sumvar=actual;
    where product="TABLE";
run;
    title2 "Chairs";
    vbar3d country / sumvar=actual;
    where product="CHAIR";
run;
    title2 "Sofas";
    vbar3d country / sumvar=actual;
    where product="SOFA";
run;

/* For the last graph, set the GEPILOG= graphics option to */
/* append the trailer */
GOPTIONS GEPILOG="3B"X;

/* Generate the last graph */
    title2 "Beds";
    vbar3d country / sumvar=actual;
    where product="BED";
run;
quit;

/* Create the HTML file to view the animated GIF */
data _null_ ;
    file htmout ;
    put "<HTML>";
    put "<HEAD>";
    put "<TITLE> GIFANIM </TITLE>";
    put "</HEAD>";
    put "<BODY STYLE='background:#F2F2CF'>";
    put "<IMG STYLE='border:none' src='gifanim2.gif'>";
    put "</BODY>";
    put "</HTML>";
run;
quit;

/* Close the LISTING destination and open the HTML destination */
ods listing close;
ods html;

Example: Creating an Animated GIF with the GREPLAY Procedure

This example uses the GREPLAY procedure to combine several graphs stored in a catalog into an animated GIF. The GCHART procedure, with BY-group processing, generates the graphs and stores them in a catalog. The GREPLAY procedure is then used to create an animated GIF that plays the graphs in a specific product order: desks, tables, chairs, sofas, and beds.
The following display shows the first image of the animated GIF only.
Horizontal bar chart of 1993 desk sales in Canada, Germany, and the U.S.A.
The animation iterates through the 1993 sales data for Canada, Germany, and the U.S.A. The animation waits two seconds between each image and iterates through the animation continuously.
Here is the example program code.
/* Create file references for the output */
filename gifout "gifanim3.gif";   /* Image output */
filename htmout "gifanim3.html";  /* HTML output */

/* Create catalog Mygraphs */
libname Mygraphs "C:\";

/* Close the ODS HTML destination */
ods html close;

/* Open ODS LISTING and specify the graph style */
ods listing style=harvest;

 /* Delete the previously created graphs before creating new ones */
proc greplay igout=Mygraphs.Sales nofs;
    delete _all_;
run; quit;

/* Create our data set by sorting sashelp.prdsale by product */
proc sort data=sashelp.prdsale out=Work.sales;
    by product;
run;
quit;

 /* Set graphics options */
goptions reset=all device=gif noborder nodisplay;

/* Generate the graphs */
title1 "1993 Sales";
proc gchart data=work.sales(where=(year=1993)) gout=Mygraphs.Sales;
    pie3d country / sumvar=actual type=mean;
    by product;
run;
quit;

 /* Specify the replay options */
goptions reset=all device=gifanim noborder
    disposal=background /* Restore the background between images */
    delay=200           /* Wait 2 seconds between each image */
                        /* (200 x 0.01s) */
    gsfname=gifout gsfmode=replace;
/* The graphs are to be replayed in the following product order: */
/* desks, tables, chairs, sofas, and beds */
/* This means that we have to replay the GRSEGs in the following order:*/
/* GCHART2, GCHART4, GCHART1, GCHART3, and GCHART */
/* Replay the first graph */
proc greplay igout=Mygraphs.Sales nofs;
    replay GCHART2;
run;
quit;

/* Set the GSFMODE= graphics option to append the remaining graphs */
goptions gsfmode=append;

/* Replay the remaining graphs */
proc greplay igout=Mygraphs.Sales nofs;
    replay GCHART4 GCHART1 GCHART3 GCHART;
run;
quit;

/* Write the trailer to the animated GIF file. */
/* Since we used BY-group processing, use a DATA step */
data _null_;
   file gifout recfm=n mod; 
   put "3B"x;
run;

/* Create the HTML file to view the animated GIF */
data _null_ ;
    file htmout ;
    put "<HTML>";
    put "<HEAD>";
    put "<TITLE> GIFANIM </TITLE>";
    put "</HEAD>";
    put "<BODY>";
    put "<IMG STYLE='border:none' src='gifanim3.gif'>";
    put "</BODY>";
    put "</HTML>";
run;
quit;

/* Close the LISTING destination and open the HTML destination */
ods listing close;
ods html;