Hi SAS Friends,
I've inherited the following code (test data and code below).
It creates .GIF output that advances in integer units ( t_days = 1, 2, 3, 4, 5, 6). However the source dataset advance in units of 0.125 ( t_days = 0.125, 0.25. 0.375. 0.5...), and for the .GIF file to be accurate, need it to advance at those smaller intervals.
Any suggestions about how to amend this code to accommodate that?
/*****************************************************************/
data test;
input t_days Cp_tot Cp_tot_2;
cards;
t_days Cp_tot Cp_tot_2
0 0 0
0.125 12.829861994 25.659723989
0.25 19.108883486 38.217766972
0.375 21.46446787 42.928935739
0.5 43.097579093 86.195158186
0.625 40.779643827 81.559287653
0.75 37.235330034 74.470660067
0.875 33.220430967 66.440861935
1 50.722202305 101.44440461
1.125 45.724999478 91.449998956
1.25 40.443085571 80.886171143
1.375 35.301262254 70.602524507
1.5 52.072140167 104.14428033
1.625 46.60087866 93.20175732
1.75 41.011472329 82.022944658
1.875 35.670183328 71.340366657
2 52.311658727 104.62331745
2.125 46.756437678 93.512875356
2.25 41.112547745 82.225095491
2.375 35.735895659 71.471791318
2.5 52.354412259 104.70882452
2.625 46.784280561 93.568561122
2.75 41.130702594 82.261405187
2.875 35.747752218 71.495504436
3 52.362171222 104.72434244
3.125 46.789371147 93.578742293
3.25 41.134053396 82.268106793
3.375 35.749966908 71.499933816
3.5 52.363642522 104.72728504
3.625 46.790354788 93.580709575
3.75 41.134716103 82.269432205
3.875 35.750417544 71.500835087
4 52.363952313 104.72790463
4.125 46.790570449 93.581140898
4.25 41.134868374 82.269736748
4.375 35.750526732 71.501053464
4.5 52.364031902 104.7280638
4.625 46.790629446 93.581258893
4.75 41.134912843 82.269825686
4.875 35.750560792 71.501121584
5 52.364058381 104.72811676
5.125 46.790650311 93.581300621
5.25 41.134929479 82.269858958
5.375 35.750574192 71.501148384
5.5 52.364069267 104.72813853
5.625 46.790659217 93.581318434
5.75 41.134936807 82.269873615
5.875 35.75058025 71.501160501
6 52.364074294 104.72814859
;
run;
/* Create macro loop to run proc sgplot */
%macro Series(start=, end=, incr=);
%do time=&start %to &end %by &incr;
proc sgplot data = Sample_2_con;
where t_days le &time;
title "C vs T";
series x = t_days y = Cp_tot;
series x = t_days y = Cp_tot_2; /* each image has two time series */
xaxis integer values = (0 to 7);
yaxis min = 0 max = 120 grid; /* set common axes */
run;
%end;
%mend Series;
/* Create animation */
ods graphics / imagefmt=GIF width=4in height=3in; /* each image is 4in x 3in GIF */
options papersize=('4 in', '3 in') /* set size for images */
nodate nonumber /* do not show date, time, or frame number */
animduration=0.5 animloop=yes noanimoverlay /* animation details */
printerpath=gif animation=start; /* start recording images to GIF */
ods printer file='[INSERT PATH HERE]\An_1.gif'; /* images saved into animated GIF */
/* ods html select none; */ /* suppress screen output */
%Series(start=0, end=6, incr=1);
ods html select all; /* restore screen output */
options printerpath=gif animation=stop; /* stop recording images */
ods printer close; /* close the animated GIF file */
Thank you very much!
Normal macro arithmetic is INTEGER only.
So just increment by 125 and then divide the result by 1000 to get steps of 0, 0.125, 0.25 , ... 6.000
%macro Series(start=, end=, incr=,divisor=1);
%do time=&start %to &end %by &incr;
proc sgplot data = Sample_2_con;
where t_days le &time/&divisor;
title "C vs T";
/* each image has two time series */
series x = t_days y = Cp_tot;
series x = t_days y = Cp_tot_2;
/* set common axes */
xaxis integer values = (0 to 7);
yaxis min = 0 max = 120 grid;
run;
%end;
%mend Series;
...
%Series(start=0, end=6000, incr=125, divisor=1000);
PS Place comments about code BEFORE the code so the person reading the code can SEE the comment before they read the code rather than wondering why the heck they coded it that way.
Normal macro arithmetic is INTEGER only.
So just increment by 125 and then divide the result by 1000 to get steps of 0, 0.125, 0.25 , ... 6.000
%macro Series(start=, end=, incr=,divisor=1);
%do time=&start %to &end %by &incr;
proc sgplot data = Sample_2_con;
where t_days le &time/&divisor;
title "C vs T";
/* each image has two time series */
series x = t_days y = Cp_tot;
series x = t_days y = Cp_tot_2;
/* set common axes */
xaxis integer values = (0 to 7);
yaxis min = 0 max = 120 grid;
run;
%end;
%mend Series;
...
%Series(start=0, end=6000, incr=125, divisor=1000);
PS Place comments about code BEFORE the code so the person reading the code can SEE the comment before they read the code rather than wondering why the heck they coded it that way.
Thank you very much, the code works properly now, which is great !.
What I still do not understand is this line :
%do time=&start %to &end %by &incr;
Is time a temporary variable of some kind?
It does not appear in the PROC SGPlot procedure, or in the source dataset. But it controls how many images are produced by the PROC SGPlot procedure, for the .GIF file.
Thanks again!
@rmacarthur wrote:
Thank you very much, the code works properly now, which is great !.
What I still do not understand is this line :
%do time=&start %to &end %by &incr;
Is time a temporary variable of some kind?
It does not appear in the PROC SGPlot procedure, or in the source dataset. But it controls how many images are produced by the PROC SGPlot procedure, for the .GIF file.
Thanks again!
TIME is a MACRO VARIABLE.
In this code it is use as the iterator variable for the macro %DO loop.
Inside the %DO loop it is used to generate part of this SAS statement:
where t_days le &time/&divisor;
So when TIME has the value 1250 and DIVISOR has the value 1000 the following SAS statement is generated and run.
where t_days le 1250/1000;
You should modify the definition of the macro %SERIES() to define TIME as a LOCAL macro variable. That will prevent the %SERIES() macro from modify any existing macro variable named TIME that might be used by the program that is calling %SERIES().
%macro Series(start=, end=, incr=,divisor=1);
%local time;
%do time=&start %to &end %by &incr;
proc sgplot data = Sample_2_con;
where t_days le &time/&divisor;
title "C vs T";
/* each image has two time series */
series x = t_days y = Cp_tot;
series x = t_days y = Cp_tot_2;
/* set common axes */
xaxis integer values = (0 to 7);
yaxis min = 0 max = 120 grid;
run;
%end;
%mend Series;
Note that the parameters of the %SERIES() macro [ START, END, INCR and DIVISOR ] are all LOCAL macro variables also.
Thank you again !, makes much more sense now and have added the %local designation for the Time variable. Robert
/*
Here is some code you could start with.
*/
%macro Series(start=, end=, incr=);
%let time=&start. ;
%do %while(%sysevalf(&time.<=&end.,boolean));
%put &=time. ;
%let time=%sysevalf(&time.+&incr.);
%end;
%mend Series;
%Series(start=0, end=6, incr= 0.125)
TIME=0 TIME=0.125 TIME=0.25 TIME=0.375 TIME=0.5 TIME=0.625 TIME=0.75 TIME=0.875 TIME=1 TIME=1.125 TIME=1.25 TIME=1.375 TIME=1.5 TIME=1.625 TIME=1.75 TIME=1.875 TIME=2 TIME=2.125 TIME=2.25 TIME=2.375 TIME=2.5 TIME=2.625 TIME=2.75 TIME=2.875 TIME=3 TIME=3.125 TIME=3.25 TIME=3.375 TIME=3.5 TIME=3.625 TIME=3.75 TIME=3.875 TIME=4 TIME=4.125 TIME=4.25 TIME=4.375 TIME=4.5 TIME=4.625 TIME=4.75 TIME=4.875 TIME=5 TIME=5.125 TIME=5.25 TIME=5.375 TIME=5.5 TIME=5.625 TIME=5.75 TIME=5.875 TIME=6
Thank you very much, I am working with this code to better understand it and see how it also provides a solution. Much appreciated, Robert
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.