After reading @Jay54's Pie Charts Redux, spotting Flag Print Dinner Paper Plates at Target, and seeing American Flag Doughnuts, what was I supposed to do - not try to create a (two-outcome) Stars-and-Stripes-Forever Donut Chart macro? Have a nice 4th of July!
* Fun w/SAS ODS Graphics, Stars-and-Stripes-Forever Donut Charts;
%macro RedWhiteAndBlueDonut(YES=, DONUTHOLE=); /* Specify % for Yes wedge and text to apppear in center */
ods graphics on / height=5in width=5in;
data stars(keep=x y); /* Generate x/y points for white stars on blue background */
do y=-15 to 15; /* 31 rows of 31 stars */
do x=-15 to 15;
output;
end;
end;
data stripes(keep=spolygon sx sy red); /* Generate x/y points for polygons for stripes */
pi=constant('pi');
pctyes=&YES/100; /* Convert to decimal */
if pctyes<.4999 then do; /* Stripes for top half of circle if needed (YES<50%) */
red=1; /* Alternate red and white stripes */
do stripe=.25 to 16.25 by 1; /* Top semicirlce, center YES wedge at top middle */
StartRadians=90/360*2*pi-.50*pctyes*2*pi; /* Need to create diagonal edges for polygon stripes along wedges */
spolygon+1; /* Stripe plygons for left side of NO wedge */
sy=stripe; sx=-15; output; /* Upper left x/y point */
sy=stripe; sx=-(abs(sy)/sin(startradians))*cos(startradians); output; /* Upper right x/y point */
sy=max(stripe-1,0); sx=-(abs(sy)/sin(startradians))*cos(startradians); output; /* Lower right x/y point */
sy=max(stripe-1,0); sx=-15; output; /* Lower left x/y point */
spolygon+1; /* Stripe polygons for right side of NO wedge */
sy=stripe; sx=(abs(sy)/sin(startradians))*cos(startradians); output; /* Upper left x/y point */
sy=stripe; sx=15; output; /* Upper right x/y point */
sy=max(stripe-1,0); sx=15; output; /* Lower right x/y point */
sy=max(stripe-1,0); sx=(abs(sy)/sin(startradians))*cos(startradians); output; /* Lower left x/y point */
red=^red; /* Alternate red and white stripes */
end;
end;
lowerwedge=min(1-pctyes,.49999); /* Stripes for lower half of circle if needed (YES<100%) */
if lowerwedge>0 then do;
red=0; /* Alternate red and white stripes */
do stripe=-14.75 to .25 by 1; /* Bottom semicirlce, center NO wedge at bottom middle */
StartRadians=90/360*2*pi-.50*lowerwedge*2*pi; /* Need to create diagonal edges for polygon stripes along wedges */
spolygon+1; /* Stripe polygons for NO wedge */
sy=min(stripe,0); sx=-(abs(sy)/sin(startradians))*cos(startradians); output; /* Upper left x/y point */
sy=min(stripe,0); sx=-sx; output; /* Upper right x/y point */
sy=(stripe-1); sx=(abs(sy)/sin(startradians))*cos(startradians); output; /* Lower right x/y point */
sy=(stripe-1); sx=-sx; output; /* Lower left x/y point */
red=^red;
end;
end;
data text; /* Text for donut hole */
tx=0; ty=0; text="&DonutHole"; output;
data StarsAndStripes; /* Combine stars, stripes, text */
set stars stripes text;
data mapStripes; /* Attribute map to assign colors to stripes */
ID="Red"; value=1; linecolor="CXB22234"; fillcolor="CXB22234"; output;
ID="Red"; value=0; linecolor="WHITE"; fillcolor="WHITE"; output;
/* Draw stars-and-stripes-forever donut chart! */
proc sgplot data=StarsAndStripes noautolegend noborder pad=0 nowall dattrmap=mapStripes;
styleattrs backcolor=CX3C3B6E; /* "Old Glory Blue" background color */
symbolchar name=uniStar char='2605'x; /* Unicode value for 5-pointed star */
xaxis display=none offsetmin=0 offsetmax=0 values=(-15 15); * Supress axes display;
yaxis display=none offsetmin=0 offsetmax=0 values=(-15 15);
scatter x=x y=y / markerattrs=(symbol=unistar color=CXFFFFFF size=18pt); * Stars (White);
polygon x=sx y=sy id=spolygon / group=red fill nooutline attrid=Red; * Stripes (Red & White);
ellipseparm semimajor=9 semiminor=9 / slope=0 /* Inner circle of donut (white) */
xorigin=0 yorigin=0 fill fillattrs=(color=white);
ellipseparm semimajor=9 semiminor=9 / slope=0 /* Inner circle line */
xorigin=0 yorigin=0 lineattrs=(color=black thickness=1pt);
text x=tx y=ty text=text / splitchar='*' strip splitpolicy=splitalways textattrs=(size=16pt weight=bold); * Donut hole text;
ellipseparm semimajor=20 semiminor=20 / slope=0 /* Outer circle with really thick line to "crop" stars/stripes image into circle */
xorigin=0 yorigin=0 lineattrs=(color=white thickness=128pt);
run;
%mend;
* Fun Facts about the 4th of July: themuse.com/advice/34-fun-facts-about-the-4th-of-july;
%RedWhiteAndBlueDonut(YES=32, DONUTHOLE=WATCH*4TH OF JULY PARADE?*YES: 32% NO: 68%);
%RedWhiteAndBlueDonut(YES=63, DONUTHOLE=ATTEND*FIREWORKS DISPLAY?*YES: 63% NO: 37%);
I love how you shared your inspiration for the Stars-and-Stripes donut charts and the very cool code!
Always impressed with your SAS ODS Graphics fun.
Thanks for sharing - especially on your holiday!
Cheers,
Michelle
I wish everyone, including myself, commented their code this well!
SAS giving us a way to add end-of-line comments would definitely help better commenting.
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!
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.