Do you remember last year when a SAS communities member asked for help in crafting a marriage proposal? (No? Take minute to go read the thread -- it's worth it! )
The question and responses inspired us. We know that SAS users, when given a challenge and the chance to help someone, rush to use their superpowers for Good. And while "creating a marriage proposal" is probably not a business objective in your SAS life, the techniques learned along the way can have many uses other than just popping the question.
With Valentine's Day is approaching (February 14 -- don't forget!), we'd like to channel that creativity and knowledge into a fun challenge: creating Valentine's Day greetings with SAS tools! To participate, respond to this post with code and/or images of your SAS-generated Valentines. It's not a contest -- not exactly -- but we'll definitely take the best submissions and do something fun with them. And even if you don't have a Valentine to add, please click Like on any of the replies that you...well...like.
Looking for inspiration?
Remember, include your code (if applicable) -- use the code button (the SAS running man) to add/format it. And add screenshots/images with the Photos button.
(Communities tip: Try not to add file attachments if you can avoid it -- sometimes these are difficult for visitors to view.)
See also:
A Valentine Challenge: Express your ❤️ with SAS
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.
Inspired by the many great Valentines day posts I thought I'd create a variation of @GraphGuy's traditional SAS/GRAPH PROC GMAP Heart and dust off my annotate skills to create the following...
Code below...
%let name=valentines_graph;
filename odsout '.';
%let pink=cxFF3333;
%let darkgray=gray66;
data heart_data;
do x=-2 to 2 by .05;
y=sqrt(1-(abs(x)-1)**2);
output;
end;
do x=2 to -2 by -.05;
y=arcos(1-abs(x))-3.14;
output;
end;
run;
data heart_data; set heart_data;
/* set the undefined values to zero */
if y=. then y=0;
/* re-shape the deep parts of the 'V' just a tiny bit */
if round(x*100)=0 then y=y+.2;
/* an id variable for gmap */
idvar='heart';
my_html=
'title='||quote('I Love SAS!')||
' href='||quote('https://blogs.sas.com/content/sgf/2018/01/22/sas-language-valentines/');;
run;
data anno_pi;
length function $8;
xsys='2'; ysys='2'; hsys='3'; when='a'; color="&darkgray";
function='move'; x=-0.75; y=-1.25; output;
function='draw'; x=-0.75; y=0.0; output;
function='move'; x=-1.25; y=0.0; output;
function='draw'; x=1.25; y=0.0; output;
function='move'; x=0.75; y=0.0; output;
function='draw'; x=0.75; y=-1.25; output;
run;
goptions device=png;
goptions noborder;
ODS LISTING CLOSE;
ODS HTML path=odsout body="&name..htm"
(title="Valentine's Heart SAS Graph") style=htmlblue;
goptions gunit=pct ftitle='albany amt/bold' ftext='albany amt/bold' htitle=3.5 htext=3.5 ctext=&darkgray;
title1 ls=1.5 c=&darkgray "My " c=&pink "love" c=&darkgray " for you";
title2 ls=1.5 c=&darkgray "is like the decimals of pi";
footnote ls=1.5 c=&darkgray bold "...never ending";
*title2 h=8 ' ';
pattern1 v=s c=&pink;
proc gmap data=heart_data map=heart_data anno=anno_pi;
id idvar;
choro idvar / nolegend
coutline=&darkgray
html=my_html
des='' name="&name";
run;
quit;
ODS HTML CLOSE;
ODS LISTING;
Cheers,
Michelle
Here's my stab at this challenge, featuring little misshapen hearts made out of scatter plot dots. ❤️
And here's the code:
data love;
input time love;
datalines;
0 0
1 1
1.12 1.12
.88 1.12
2 2
3 3
3.12 3.12
2.88 3.12
4 4
5 5
5.12 5.12
4.88 5.12
6 6
7 7
7.12 7.12
6.88 7.12
8 8
9 9
9.12 9.12
8.88 9.12
10 10
11 11
11.12 11.12
10.88 11.12
12 12
13 13
13.12 13.12
12.88 13.12
14 14
15 15
15.12 15.12
14.88 15.12
16 16
17 17
17.12 17.12
16.88 17.12
18 18
19 19
;
run;
proc template;
define statgraph sgdesign;
dynamic _TIME2 _LOVE;
begingraph / designwidth=629 designheight=482;
entrytitle halign=center 'Love Over Time' / textattrs=(family='Monotype Corsiva' size=24 );
layout lattice / rowdatarange=data columndatarange=data rowgutter=10 columngutter=10;
layout overlay / wallcolor=CXFFCCCC xaxisopts=( label=('TIME') labelattrs=(family='HeiT' size=16 ) linearopts=( tickvaluepriority=TRUE tickvalueformat=BEST6.)) yaxisopts=( label=('LOVE') labelattrs=(family='HeiT' size=16 ) linearopts=( tickvaluepriority=TRUE tickvalueformat=BEST6.));
scatterplot x=_TIME2 y=_LOVE / name='scatter' markerattrs=(color=CXFF0000 symbol=CIRCLEFILLED size=7 weight=bold );
endlayout;
endlayout;
endgraph;
end;
run;
proc sgrender data=WORK.LOVE template=sgdesign;
dynamic _TIME2="TIME" _LOVE="LOVE";
run;
Interesting idea to use the Circlefilled symbol to create a heart.
The Symbol font has a "Heart" shape (0xA9). Another way would be to use SYMBOLCHAR to define a heart symbol to use it directly
Ha ha.. With this challenge I took a "word harder, not smarter" approach.. That's the saying right?:)
I was using ODS Graphics Designer which sadly does not have a heart as a symbol option. But I will take this into consideration for my next valentine. 🙂
data val;
Infile Datalines;
informat vert 2. horz 2.;
input vert horz;
Datalines;
1 6
2 5
2 6
2 7
3 4
3 5
3 6
3 7
3 8
4 3
4 4
4 5
4 6
4 7
4 8
4 9
5 2
5 3
5 4
5 5
5 6
5 7
5 8
5 9
5 10
6 1
6 2
6 3
6 4
6 5
6 6
6 7
6 8
6 9
6 10
6 11
7 1
7 2
7 3
7 4
7 5
7 6
7 7
7 8
7 9
7 10
7 11
8 1
8 2
8 3
8 4
8 5
8 6
8 7
8 8
8 9
8 10
8 11
9 2
9 3
9 4
9 5
9 6
9 7
9 8
9 9
9 10
10 3
10 4
10 5
10 7
10 8
10 9
11 4
11 8
run;
options pageno=1 linesize=min pagesize=35;
proc plot data=val;
plot vert*horz='v' /vpos=27;
run;
That's old school, @jl3! I've taken the liberty of posting the output.
vert | | | | | 11 + v v | 10 + v v v v v v | 9 + v v v v v v v v v | 8 + v v v v v v v v v v v | 7 + v v v v v v v v v v v | 6 + v v v v v v v v v v v | 5 + v v v v v v v v v | 4 + v v v v v v v | 3 + v v v v v | 2 + v v v | 1 + v | ---+----+----+----+----+----+----+----+----+----+----+-- 1 2 3 4 5 6 7 8 9 10 11
Yes Chris.
With apologies to Robert Indiana, here's a simple SAS ODS Graphics-generated valentine!
* Fun w/SAS ODS Graphics: Valentine's Day L-O-V-E;
data love1; * Letters L-V-E in upper left, lower left/right quadrants;
x1=1; y1=2; txt1='L'; n+1; output;
x1=1; y1=1; txt1='V'; n+1; output;
x1=2; y1=1; txt1='E'; n+1; output;
data love2; * Unicode heart ("O") in upper right quadrant;
x2=1.9; y2=1.95; txt2=unicode('\u2764'); output;
data love3; * Valentine message in center of heart;
x3=1.9; y3=1.95; txt3="BE*MINE"; output;
data love4; * Points for filled polygons for each quadrant;
input id@; do i=1 to 4; input x4 y4@; output; end;
cards;
1 0 1.53 1.5 1.53 1.5 3 0 3 "L"
2 1.5 1.53 3 1.53 3 3 1.5 3 "O"
3 0 0 1.5 0 1.5 1.53 0 1.53 "V"
4 1.5 0 3 0 3 1.53 1.5 1.53 "E"
;
data love; * Put it all together;
set love1 love2 love3 love4;
* Plot a Valentine!;
ods graphics on / reset=index imagefmt=gif antialias height=5in width=5in;
proc sgplot data=love noautolegend noborder pad=0 aspect=1;
* 1. Colored quadrants (use transparency to create lighter version of letter colors);
polygon x=x4 y=y4 id=id / colormodel=(blue red green orange) transparency=.85 nooutline fill colorresponse=id;
* 2. L-V-E letters;
text x=x1 y=y1 text=txt1 / position=center vcenter=bbox contributeoffsets=none colormodel=(blue green orange)
textattrs=(family="Cumberland AMT" size=258pt weight=bold) colorresponse=n;
* 3. "Outer" heart ("O" letter), tilted;
text x=x2 y=y2 text=txt2 / position=center vcenter=bbox contributeoffsets=none rotate=-45
textattrs=(family="Arial Unicode MS" size=202pt weight=bold color=red);
* 4. Smaller "inner" heart (inside "O" letter), tilted;
text x=x2 y=y2 text=txt2 / position=center vcenter=bbox contributeoffsets=none rotate=-45
textattrs=(family="Arial Unicode MS" size=106pt weight=bold color=pink);
* 5. "BE MINE" message on "inner" heart, tilted;
text x=x3 y=y3 text=txt3 / position=center vcenter=bbox contributeoffsets=none splitchar='*' splitpolicy=splitalways
textattrs=(size=14pt weight=bold color=red) rotate=-45;
xaxis display=none offsetmin=0 offsetmax=0 values=(.5 2.45); * Suppress labels/ticks on axes, set bounds;
yaxis display=none offsetmin=0 offsetmax=0 values=(.5 2.55);
Awesome and very creative and aesthetic. Nice to see you make this visual using SGPLOT with fairly compact code.
data data1;
input love time_year age;
datalines;
10 1 20
11 2 21
12 3 22
13 4 23
14 5 24
15 6 25
16 7 26
17 8 27
18 9 28
19 10 29
20 11 30
;
run;
ods pdf file='C:\Users\**bleep**\Google Drive\Computational Statistics\work1.pdf';
title "SAS Valentine";
proc g3d;
scatter love*time_year=age / color='red' shape='HEART' size=3 ctext='red' caxis='red' ;
run;
quit;
ods pdf close;
LOVEly chart @chinki! It's also lovely to see that you're a new SAS Support Communities member. May your initiative encourage others. Yeah!
Kind Regards,
Michelle
P.S. Participation in the community is a great way to earn some SAS Global Forum 2018 conference swag!
Thank you! Michelle
Yes, I am new to this community and enjoying SAS.
To paraphrase Bobby Hill, "After seeing @Rick_SAS's Binary Heart and M&Ms posts, well, what was I supposed to do? Not code a SAS ODS Graphics I-Heart-M&Ms Valentine?"
* Fun w/SAS ODS Graphics: I Heart M&Ms Valentine;
data red(keep=x y m s rename=(x=x1 y=y1)) white(keep=x y m s rename=(x=x2 y=y2));
retain m "m" s 1; * M&M letter ("m"), M&M size (1);
do y=15 to 1 by -1; * Read in 15x15 M&M valentine layout template from inline data;
input mms $15.; * X=Background M&M (red), *=Heart M&M (white);
do x=1 to 15; * Output points for plot;
if substr(mms,x,1)="X" then output red;
else output white;
end;
end;
cards;
XXXXXXXXXXXXXXX
XXXXXXXXXXXXXXX
XXX***XXX***XXX
XX*****X*****XX
X*************X
X*************X
X*************X
XX***********XX
XXX*********XXX
XXXX*******XXXX
XXXXX*****XXXXX
XXXXXX***XXXXXX
XXXXXXX*XXXXXXX
XXXXXXXXXXXXXXX
XXXXXXXXXXXXXXX
;
data mms; * Put M&Ms all together;
set red white;
* Plot M&Ms valentine!;
ods graphics on / reset=index imagefmt=png antialias=on height=5in width=5in dataskinmax=500;
proc sgplot data=mms noautolegend noborder pad=0 aspect=1 nowall subpixel;
styleattrs backcolor=rose;
* 1. Background M&Ms (red);
bubble x=x1 y=y1 size=s / dataskin=gloss bradiusmin=15 fill fillattrs=(color=red);
text x=x1 y=y1 text=m / textattrs=(family="Albany AMT Bold" size=12pt color=white weight=bold) position=center vcenter=bbox contributeoffsets=none strip;
* 2. Heart M&Ms (white);
bubble x=x2 y=y2 size=s / dataskin=gloss bradiusmin=15 fill fillattrs=(color=white);
text x=x2 y=y2 text=m / textattrs=(family="Albany AMT Bold" size=12pt color=deeppink weight=bold) position=center vcenter=bbox contributeoffsets=none strip;
xaxis display=none offsetmin=0 offsetmax=0 min=.4 max=15.6 values=(.4 15.6); * Suppress labels/ticks on axes, set bounds;
yaxis display=none offsetmin=0 offsetmax=0 min=.4 max=15.6 values=(.4 15.6);
Awwww @tc... so glad you did! A magnificent map of m&ms 😍
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.