## Venn diagram

Occasional Contributor
Posts: 16

# Venn diagram

Hi,

I would like to draw a Venn diagram to illustrate the following situation

group A n=694

group B n=132

group n=410

group D n=6561

A and B n=74

A and C n=70

A and D n=146

Data and expected Venn diagram are attached. How can I do it by SAS (with numbers in the circles) and if it can be proportional (D is too big)? I saw some macros/codes from Global Forum... but not successful apply them.

Thank you

Super User
Posts: 13,941

## Re: Venn diagram

/*+-------------------------------------------------------+
|          SUGI 30 Sample                               |
|          SAS MAPPING: Tips and tricks                 |
|                                                       |
|    NAME: vennmap.sas                                  |
|   TITLE: Create a venn diagram with 3 overlapping     |
|          circles.                                     |
| PRODUCT: GRAPH                                        |
|                                                       |
|   NOTES: Last Update 24Feb05  ADM                     |
+-------------------------------------------------------+*/

%let name=vennmap;
filename odsout '.';

goptions reset=global;

/*********************************************************************/
/* The information below defines the how the Venn diagram will look  */
/* and how it will be labeled.  There are 3 overlapping circles.  The*/
/* top circle is #1.  The lower left circle is #2.  The lower right  */
/* circle is #3.  Overlap areas are named with all the circle numbers*/
/* that are included in the overlap.                                 */
/*********************************************************************/
/* The only thing that needs to be changed for your data are the     */
/* macro Variables below.                                            */
/*********************************************************************/

/* For our example - the following survey results:                  */
/*   39 people liked Product A                  #1                  */
/*   43 people liked Product B                  #2                  */
/*   56 people liked Product C                  #3                  */
/*   7 people liked Product A and B             #4                  */
/*   10 people liked Product A and C            #5                  */
/*   16 people liked Product B and C            #6                  */
/*   4 people liked Product A, B and C          #7                  */
/*   6 people didn't like any of the products   #8                  */

/* Text on graph for each circle  - Set your own values here*/
%let text1=Product A;  /* top circle */
%let text2=Product B;  /* lower left circle */
%let text3=Product C;  /* lower right circle */

/* Values to appear on each area  - Set your own values here */
/* This could be calculated with a datastep and call symput. */
%let value1=26;       /*#1 - #7 - (#4 - #7) - (#5 - #7)*/
%let value2=24;       /*#2 - #7 - (#4 - #7) - (#6 - #7)*/
%let value3=34;       /*#3 - #7 - (#5 - #7) - (#6 - #7)*/
%let value1_2=3;      /*#4 - #7*/
%let value2_3=12;     /*#6 - #7*/
%let value1_3=6;      /*#5 - #7*/
%let value1_2_3=4;    /*#7*/

/* colors to use - probably don't need to change */
%let color1=cx5A5AE7;
%let color2=cxE75A5A;
%let color3=cx5AE75A;

/* ID variable value for each area - probably don't need to change */
%let label1=1 Only;
%let label2=2 Only;
%let label3=3 Only;
%let label1_2=1&2 Intersect;
%let label2_3=2&3 Intersect;
%let label1_3=1&3 Intersect;
%let label1_2_3=1&2&3 Intersect;

/* Circle centers.  These are based on a radius of 25 and circles */
/* overlap at the center of the next circle.  Don't change these  */
/* unless you have a need.                                        */
%let x_center1=50;  /* 2 x radius;  just to give space on sides*/
%let x_center2=50-(25/2);       /* x_center1 - half radius */
%let x_center3=50+(25/2);       /* x_center1 + half radius */
%let y_center3=&y_center2;

/* position of outside labels */
%let x_label1=27;
%let y_label1=73;
%let x_label2=13;
%let y_label2=25;
%let x_label3=87;
%let y_label3=25;

/********************************************************************/
/* gen_respdata:  Macro to generate the response dataset.           */
/********************************************************************/
%macro gen_respdata(respdata);
/* Set ID and VALUE on each section of diagram */
data &respdata;
length area_id \$30 value \$30;
area_id="&label1"; value="&value1"; output;
area_id="&label2"; value="&value2"; output;
area_id="&label3"; value="&value3"; output;
area_id="&label1_2"; value="&value1_2"; output;
area_id="&label2_3"; value="&value2_3"; output;
area_id="&label1_3"; value="&value1_3"; output;
area_id="&label1_2_3"; value="&value1_2_3"; output;
run;

/* Add tool tips and drill down */
data &respdata;
set &respdata;
length htmlvar \$500;
htmlvar='alt='||quote(
'ID:      '|| trim(left(area_id)) ||'0D'x||
'Value:   '|| trim(left(value))
)  ||' '||
'href="somewebpage.html"';
run;
%mend gen_respdata;

/*********************************************************************/
/* gen_colors:  Macro to generate the overlapping colors based on the*/
/* colors of the 3 circles.  Just averages the colors.               */
/*********************************************************************/
%macro gen_colors();
data _null_;
/* First get the rgb hex values of the 3 defined colors */
red1=  input(substr("&color1",3,2),hex2.);
green1=input(substr("&color1",5,2),hex2.);
blue1= input(substr("&color1",7,2),hex2.);
red2=  input(substr("&color2",3,2),hex2.);
green2=input(substr("&color2",5,2),hex2.);
blue2= input(substr("&color2",7,2),hex2.);
red3=  input(substr("&color3",3,2),hex2.);
green3=input(substr("&color3",5,2),hex2.);
blue3= input(substr("&color3",7,2),hex2.);

/* A factor to 'darken' the combined area colors.
values 0->1 (1=no darkening, 0=totally darkened) */
darken=.9;

/* Calculate color for 1_2 intersection, and */
/* store in macro variable */
red=   ((red1+red2)/2)*darken;
green= ((green1+green2)/2)*darken;
blue=  ((blue1+blue2)/2)*darken;
color1_2="cx"||put(red,hex2.)||put(green,hex2.)||put(blue,hex2.);
call symput('color1_2',trim(left(color1_2)));

/* Calculate color for 2_3 intersection, and */
/* store in macro variable */
red=   ((red2+red3)/2)*darken;
green= ((green2+green3)/2)*darken;
blue=  ((blue2+blue3)/2)*darken;
color2_3="cx"||put(red,hex2.)||put(green,hex2.)||put(blue,hex2.);
call symput('color2_3',trim(left(color2_3)));

/* Calculate color for 1_3 intersection, and */
/* store in macro variable */
red=   ((red1+red3)/2)*darken;
green= ((green1+green3)/2)*darken;
blue=  ((blue1+blue3)/2)*darken;
color1_3="cx"||put(red,hex2.)||put(green,hex2.)||put(blue,hex2.);
call symput('color1_3',trim(left(color1_3)));

/* Calculate color for 1_2_3 intersection, and
/* store in macro variable */
red=   ((red1+red2+red3)/3)*darken*darken;
green= ((green1+green2+green3)/3)*darken*darken;
blue=  ((blue1+blue2+blue3)/3)*darken*darken;
color1_2_3="cx"||put(red,hex2.)||put(green,hex2.)||
put(blue,hex2.);
call symput('color1_2_3',trim(left(color1_2_3)));

run;
%mend gen_colors;

/********************************************************************/
/* arc_calc:  Macro to generate arcs of various polygons            */
/* used by the venn_map macro.                                      */
/********************************************************************/
%macro arc_calc(center_x,center_y,start_angle,end_angle,direction);
do degrees=&start_angle to &end_angle by &direction;
output;
end;
%mend arc_calc;

/********************************************************************/
/* venn_map:  Generates the map dataset for the Venn diagram.       */
/********************************************************************/
%macro venn_map(mapdata);
/* Calculate the 3 arcs in each section of the diagram.  There */
/* will be 7 areas in the graph.                               */
data &mapdata;
length area_id \$30;

/* ----- Area 1 (top-most, area 1 only) ----- */
area_id = "&label1";
/* args are: center_x, center_y, start_angle, */
/* end_angle, direction */
%arc_calc(&x_center1, &y_center1, 0, 180, 1);
/* bottom/left arc of area 1 */
%arc_calc(&x_center2, &y_center2, 120, 60, -1);
/* bottom/right arc of area 1 */
%arc_calc(&x_center3, &y_center3, 120, 60, -1);

/* ----- Area 2 (Left-most, area 2 only) ----- */
area_id="&label2";
/* big/left arc of area 2 */
%arc_calc(&x_center2, &y_center2, 300, 120, -1);
/* little/right/top arc of area 2 */
%arc_calc(&x_center1, &y_center1, 180, 240, 1);
/* little/right/bottom arc of area 2 */
%arc_calc(&x_center3, &y_center3, 180, 240, 1);

/* ----- Area 3 (Right-most, area 3 only) ----- */
area_id="&label3";
/* big/right arc of area 3 */
%arc_calc(&x_center3, &y_center3, 60, -120, -1);
/* little/left lower arc of area 3 */
%arc_calc(&x_center2, &y_center2, -60, 0, 1);
/* little/left/top arc of area 3 */
%arc_calc(&x_center1, &y_center1, -60, 0, 1);

/* ----- Area 1&2 Intersection ----- */
area_id="&label1_2";
/* lower/left arc */
%arc_calc(&x_center1, &y_center1, 180, 240, 1);
/* lower/right arc */
%arc_calc(&x_center3, &y_center3, 180, 120, -1);
/* topmost arc */
%arc_calc(&x_center2, &y_center2, 60, 120, 1);

/* ----- Area 2&3 Intersection ----- */
area_id="&label2_3";
/* lower/left arc */
%arc_calc(&x_center3, &y_center3, 180, 240, 1);
/* lower/right arc */
%arc_calc(&x_center2, &y_center2, -60, 0, 1);
/* topmost arc */
%arc_calc(&x_center1, &y_center1, 300, 240, -1);

/* ----- Area 1&3 Intersection ----- */
area_id="&label1_3";
/* topmost arc */
%arc_calc(&x_center3, &y_center3, 60, 120, 1);
/* lower/left arc */
%arc_calc(&x_center2, &y_center2, 60, 0, -1);
/* lower/right arc */
%arc_calc(&x_center1, &y_center1, 300, 360, 1);

/* ----- Area 1&2&3 Intersection (center) ----- */
area_id="&label1_2_3";
/* upper/right arc */
%arc_calc(&x_center2, &y_center2, 0, 60, 1);
/* upper/left arc */
%arc_calc(&x_center3, &y_center3, 120, 180, 1);
/* lower/bottom arc */
%arc_calc(&x_center1, &y_center1, 240, 300, 1);
run;
%mend venn_map;

/********************************************************************/
/* gen_anno:  Generate a centroid for each polygon and place value  */
/* at the centroid.  Also, place labels outside.                    */
/********************************************************************/
%macro gen_anno(anno_values,anno_labels,mapdata,respdata);
proc sql;
/* Get the average x/y center coordinates of each piece */
create table centroid as
select unique area_id, avg(x) as x, avg(y) as y
from &mapdata group by area_id;
/* Merge the centers with the 'response' data */
create table &respdata as
select unique &respdata..*, centroid.x, centroid.y
from &respdata left join centroid
on &respdata..area_id = centroid.area_id;
quit;
run;
data &anno_values;
set &respdata;
length text \$20 style \$12 function \$12 color \$12;
xsys='2'; ysys='2'; hsys='3'; when='A';
function='label'; position='5'; style='"arial/bo"';
size=4; color='white';
text=trim(left(value));
run;

/* Place labels outside circles */
data &anno_labels;
length text \$20 style \$12 function \$12 color \$12;
xsys='2'; ysys='2'; hsys='3'; when='A';
function='label'; style='"arial/bo"'; size=4; color='black';
text="&text1"; position='4'; x=&x_label1;y=&y_label1; output;
text="&text2"; position='4'; x=&x_label2;y=&y_label2; output;
text="&text3"; position='6'; x=&x_label3;y=&y_label3; output;
run;
%mend;

%macro do_map(mapdata, respdata, anno_labels, anno_values);
%*GOPTIONS DEVICE=gif;

%* ODS LISTING CLOSE;
%* ODS HTML path=odsout body="&name..htm"
style=minimal
;

goptions htitle=6pct htext=4pct ftitle="arial/bo" ftext="arial";
goptions cback=white border;

title "Product Taste Test - Venn Diagram";
title2 "Consumers who liked each product";

/* Use the 'midpoints=' gmap option to guarantee the colors will
be assigned in the desired order (otherwise they will be
assigned alphabetically by &labeln values. */
pattern1 v=s c=&color1;
pattern2 v=s c=&color2;
pattern3 v=s c=&color3;
pattern4 v=s c=&color1_2;
pattern5 v=s c=&color2_3;
pattern6 v=s c=&color1_3;
pattern7 v=s c=&color1_2_3;

proc gmap map=&mapdata data=&respdata anno=&anno_labels all;
id area_id;
choro area_id /
nolegend
/* This forces the colors to be in the same order of the */
/* pattern statement.                                    */
midpoints=
"&label1"
"&label2"
"&label3"
"&label1_2"
"&label2_3"
"&label1_3"
"&label1_2_3"
coutline=black
woutline=2
anno=&anno_values
html=htmlvar
des=""
name="&name";
run;

quit;
%* ODS HTML CLOSE;
%* ODS LISTING;
%mend;

/********************************************************************/
/* Do the real work here.                                           */
/********************************************************************/
%gen_respdata(respdata);  /* create/prepare response dataset */
%gen_colors();            /* set up colors */
%venn_map(mapdata);       /* create map dataset */
%gen_anno(anno_values, anno_labels, mapdata, respdata);/*annotate data*/
%do_map(mapdata, respdata, anno_labels, anno_values); /* draw map */

Super User
Posts: 8,216

## Re: Venn diagram

You might also want to take a look at the macro provided in the following paper: http://support.sas.com/resources/papers/proceedings13/243-2013.pdf

Occasional Contributor
Posts: 16

Thank you!

Posts: 5,625

## Re: Venn diagram

In case you wonder what a diagram respecting the circle and intersection areas would look like, here it is...

Done with FCMP, MDS and SGANNO (i.e. a lot of overkill !)

PG

PG
Discussion stats
• 4 replies
• 1536 views
• 7 likes
• 4 in conversation