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.
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.