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.
"Binary heart" by @Rick_SASWith 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 😍
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 16. 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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: