SAS Graph has never been my forte, but here is at least an attempt that even newbies can replicate:
data need (drop=t); do t=0 to 2*constant("pi") by 0.1; x=16*sin(t)**3; y =13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t); output; end; x=16.6; y=16.5; output; run; proc sgplot noautolegend; title 'Be my valentine'; scatter y=y x=x / markerattrs=(symbol=squarefilled color=red); lineparm x=0 y=0 slope=1 /LINEATTRS=(pattern=MediumDashShortDash thickness=5 color=red); run;
Not as nice or fancy as the others, but even graphic newbies can have/show love on Valentine's Day:
Art, CEO, AnalystFinder.com
Nice work @art297! One of the beauties with SAS... there is always something to learn!
data carsheart;
set sashelp.cars;
heartsymbol='Heart';
run;
proc sgplot data=carsheart noautolegend;
symbolimage name=Heart image="C:\Users\ptimusk\Dropbox\SASUniversityEdition\myfolders\symbolheartlarge.png" ;
styleattrs datasymbols=(Heart);
reg x=EngineSize y=mpg_city / group=heartsymbol lineattrs=(color=black pattern=dash)
;;
run;
C:\Users\ptimusk\Dropbox\SASUniversityEdition\myfolders\symbolheartlarge.png
I borrowed code from Sanjay Matange 's blog and used a creative commons cupid heart symbol
https://blogs.sas.com/content/graphicallyspeaking/2015/01/14/marker-symbols/
/* Love is often unnecessarily complicated, just like this code! */
data _null_;
retain SheLovesMe Valentine;
input Kiss @@;
length Valentine $20.;
do Enamored = 1 to Kiss;
Cupid + 1;
Valentine = Cats( Valentine, SheLovesMe, SheLovesMe*3 );
if not mod( Cupid, 10 ) then do;
call execute('%put ERROR-' || translate( Valentine, " < ", "01." ) || ';');
Valentine = "";
end;
end;
SheLovesMe = not SheLovesMe;
cards;
1 3 2 3 1 30 1 8 3 6 5 4 7 2 14
;
run;
Oh @Cowboy_Coffee your poetic SAS code is just as lovely (or perhaps more) than the output... charming choice of variable names
Cheers,
Michelle
P.S. Welcome to the SAS Community too - a beautiful first post!
Well done @Cowboy_Coffee! I like how this entry relies on errors to express its message of love -- just like real life.
Also, I learned something new! I didn't know that you could use the minus symbol to suppress the prefix ERROR in your custom error messages!
%put ERROR: This is an error that includes the prefix "ERROR";
%put ERROR- This is an error that suppresses the prefix "ERROR";
Back to the serious datavizzes tomorrow. But first, a Wi-Fi inspired SAS ODS Graphics animated GIF valentine.
* Fun w/SAS ODS Graphics: Radiate Love Valentine (inspired by WiFi-like heart at bestanimations.com);
data heart; * Unicode heart at bottom of valentine;
xH=3; yH=2; txtH=unicode('\u2764');
data mask; * Points for polygon points used to mask parts of circles to create arcs;
id=1; input xP yP@@;
cards;
3 2 -1 6 -1 0 7 0 7 6 3 2
;
data valentine; set heart mask; * Merge points;
ods _all_ close; * Plot valentine (animated GIF with 4 frames);
options papersize=('5 in', '5 in') printerpath=gif animation=start animloop=YES NOANIMOVERLAY nodate nonumber;
ods printer file='/folders/myfolders/RadiateLoveValentine.gif';
ods graphics / width=5in height=5in imagefmt=GIF antialias;
%macro valentine;
%do frame=1 %to 4;
%if &frame=1 | &frame=4 %then options animduration=.4; %else options animduration=.15;;
proc sgplot data=valentine noautolegend noborder pad=0 aspect=1 nowall subpixel;
styleattrs backcolor=cxffbcd9; /* Cotton candy pink */
%if &frame>=2 %then /* Different-sized circles centered at 3,2 create wifi-like signals */
ellipseparm semimajor=1.25 semiminor=1.25 / xorigin=3 yorigin=2 clip outline lineattrs=(color=white thickness=30pt);;
%if &frame>=3 %then
ellipseparm semimajor=2 semiminor=2 / xorigin=3 yorigin=2 clip outline lineattrs=(color=white thickness=30pt);;
%if &frame>=4 %then
ellipseparm semimajor=2.75 semiminor=2.75 / xorigin=3 yorigin=2 clip outline lineattrs=(color=white thickness=30pt);;
polygon x=xP y=yP id=id / fill fillattrs=(color=cxffbcd9); /* Mask circles at 45 degree angles to create wifi arcs */
text x=xH y=yH text=txtH / textattrs=(family="Arial Unicode MS" size=108pt color=red) position=center vcenter=bbox contributeoffsets=none strip;
xaxis display=none offsetmin=0 offsetmax=0 min=.4 max=5.6 values=(.4 5.6); * Suppress labels/ticks on axes, set bounds;
yaxis display=none offsetmin=0 offsetmax=0 min=.4 max=5.6 values=(.4 5.6);
run;
%end;
%mend;
%valentine;
options printerpath=gif animation=stop;
ods printer close;
"The signal strength of my love for you is strong. Connect to my network with the password B3-M1ne."
/*
Canadian Census Population Census Data (1971-2017)
Inverted pyramid plotted to see which
year yeilds the ideal heart shape.
(Code was initially written for just one year plot)
Data and output file attached
Author: Aroop Ghosh
Date: Feb 13, 2018
*/
libname dat '~/dat/';
options mprint;
/* Age Interval */
%macro agecat(n);
proc format;
value agef
%do i=0 %to 99 %by &n;
%let j= %eval(&i+(&n-1));
&i - &j = "&i - &j"
%end;
;
run;
%mend;
%agecat(5);
%macro period(yr);
data selyr;
set dat.pop
(rename=('Age group (5,6)'n=Age_c sex = gender "&yr"n=y&yr));
keep Age_c gender y&yr;
run;
data x&yr (drop=age_c First_Pos First_Length);
set selyr;
length Age 8;
call scan(Age_c, 1, First_Pos, First_Length);
Age=input(compress(substrn(Age_c, First_Pos, First_Length)),3.0);
run;
proc sort;
by age gender;
run;
proc transpose data=x&yr out=t&yr
(drop=_name_ _label_ rename=( 'Both sexes'n = Total));
id gender;
by age;
var y&yr;
run;
Proc summary data=t&yr;
* nway;
class Age;
var Total Males Females;
output out=S&yr (drop=_:)
sum=;
format Age agef.;
run;
data _null_;
set s&yr;
where age=.;
call symput("Mtot",Males);
call symput("Ftot",Females);
run;
%put Males total - &mtot;
%put Females total - &ftot;
Data p&yr;
set s&yr;
where age^=.;
P_Male=Males/&mtot*100;
P_Female=(Females/&ftot)*-100;
run;
proc format;
picture ve
low - < 0 = '09%'
0 < - high = '09%';
run;
proc sgplot data=p&yr;
format P_Male P_Female ve. age agef.;
hbar Age / response=P_Male
fillattrs=(color=blue) transparency=.8
legendlabel="Population Male &yr" name="Males";
hbar Age / response=P_Female
fillattrs=(color=red) transparency=.8
legendlabel="Population Female &yr" name="Females";
keylegend "Males" "Females";
xaxis display=(nolabel) grid;
yaxis display=all discreteorder=data;
label Age ='Age Distribution';
title "Population Pyramid Canada: &yr";
title2 '(Age Category Shown As a Percentage of Total for Each Gender)';
footnote justify=left 'Source: Statistics Canada, CANSIM';
run;
%mend;
%macro cycle;
%do yr=1971 %to 2017;
%period(&yr);
%end;
%mend;
%cycle;
I guess 1973 was a good year for Love in Canada?
SAS Blog just published a new post using my idea and technique:
Aroop
*/ Happy Valentines day - Be loved;
proc format;
value x 1='d' .5='e' 0='v' -.5='o' -1='L' other=' ';
value y -2='*' -1='e' 0='B' other=' ';
run;
data h;
pi = constant("PI");
do r = 0 to pi by .02;
x = cos(r)*.5+.5;y1 = sin(r);y0 = 2.5*sin(r/2+pi);output;
x=-x;output;
end;
run;
proc sort ;by x;run;
proc sgplot data=h;
band x=x upper=y1 lower=y0/fillattrs=(color=CXFF0000);
format x x. y1 y0 y.;
xaxis valueattrs=(color=CXFF0000 weight=bold size=30 family="Brush Script MT");
yaxis valueattrs=(color=CXFF0000 weight=bold size=30 family="Brush Script MT");
run;
Thanks to all for the wonderful contributions! You all have demonstrated your romantic nerd skills admirably.
Thanks especially to @tc, @Estelalutero, @MichelleHomes, @ghosh, @Cowboy_Coffee, @art297, @ptimusk, @jl3, @OliviaWright, and @chinki.
I've captured all of the entries in a gallery on the blog post.
%let k = 6;
data Rose;
do theta = 0 to 2*constant("pi") by 0.05;
r = cos(&k * theta);
x = r*cos(theta);
y = r*sin(theta);
output;
end;
run;
ods graphics / imagefmt = GIF width=4in height= 3in ;
ods printer file="C:\Users\rbemile\Documents\SASStuff\Output\rose_card.gif";
ods html select none;
title color=red "I wish you A Happy Valentine's Day";
footnote color = red "From Me";
proc sgplot data=Rose aspect=1;
series x=x y=y / lineattrs= graphfit;
xaxis min=-1 max=1;
yaxis min=-1 max=1;
run;
options printerpath=gif;
ods printer close;
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.