Graphically Speaking

# Funnel Graphs

Funnel graphs are useful to track the number of visitors passing through various pages of a website or the number of patients in a study. The graph shows visually the retention of users or subjects in a study across levels of a marketing cycle or the study.

One common representation of the Funnel Chart or Funnel Graph found on the web is shown below. This graph depicts the number of customers across different stages on a web site selling some product. In this example, 268,514 customers enter the web site home page. Then, 142,091 go to the “Store” page, and so on.

In this example, the slopes of the sides of the funnel is constant (maybe some predetermined angle, say 30 degrees), and the number of customers appears to be represented by the volume of each segment. The number of customers reaching “Store” are only 52.9% of the ones that visited the web page, but this is not “visually” clear. The thickness of the segment varies, a closer examination of the visual is needed to see where the loss of customers is happening.

It has been empirically shown in published studies that the most effective way to make visual comparison of magnitude is by using linear distances from a common baseline. Linear distance from non common baselines is also very effective. Comparisons of areas is much less effective. Following this idea, I decided to take a different approach, where the thickness of each segment is held constant, and the width is varied by the number (or percent) of people in a stage. For this case, I made up some data shown below.

The data contains the percent of subjects in a study level, starting with 100% down to 10%. Level numbers are shown. A simple bar chart can be easily created, but we want a “Funnel” shape. So, Mid, Low and High values are computed to place each bar aligned in the center as shown below. The value for each bar is displayed in the middle. A HIGHLOW plot is used to create the graph.

SGPLOT code:

proc sgplot data=funnel nowall noborder noautolegend;
highlow y=level low=low high=high / type=bar dataskin=matte;
text y=level x=mid text=value / textattrs=(size=12) strip;
yaxis reverse display=none;
xaxis display=none;
run;

This simple graphs works quite well visually showing the data and providing a feel for the severe or gentle drop off of customers by stage. A similar graph is shown below for a different data with more severe loss of customers after stage 1. Only the data is different, the program code is the same as above.

Now, let us take the next step to create a graph that looks more like a “Funnel”. We will do this by generating trapezoidal polygons for each level from the data. The the upper width of the trapezoid represents the value of the upper segment and the lower width of the trapezoid represents the value of the next lower segment. The bottom segment is rectangular.

The step for creating the funnel shape can be made into a macro. But, I admit I was a bit lazy, and I just included the code in the link below. The generated data snippet is shown below. Note, four observations are generated for each original observation in the data, with common “ID” to define the trapezoid. X and Y values are generated for each vertex of the trapezoid

Here are the Funnel Graphs for the two data sets used above. Note how the shape of the Funnel gives a good feel for the progress of customers through the site. It could be concluded that the top level web page in the second case is less inviting to the customers to click on subsequent links.

SGPLOT Code:

proc sgplot data=funnel3 nowall noborder noautolegend;
polygon x=x y=y id=id / label=val fill dataskin=sheen;
yaxis reverse display=none;
xaxis display=none;
run;

Note the use of the POLYGON plot to display each segment. DATASKIN=SHEEN produces the bevelled edges for each polygon automatically. The polygon LABEL option itself is used to display the value.

A further enhancement can be added to color each level by a response (or traffic) for the level. A simple Range Attribute Map can be used as defined below. Here the color range varies between DarkBlue for response value of 0 and LightBlue for response value of 100.

A TEXT plot is used to display the segment value, and is shifted to the upper edge of the segment. Also, BACKLIGHT option is used to ensure display of the values regardless of the segment color. Click on the graph for a higher resolution image.

data rangeMap;
id=’a’;
min=0; colormodel1=’DarkBlue’;
max=100; colormodel2=’LightBlue’;
output;
run;

proc sgplot data=funnel3 nowall noborder noautolegend rattrmap=rangeMap;
polygon x=x y=y id=id / fill dataskin=sheen colorresponse=val rattrid=a;
text x=mid y=yval text=val / backlight=0.25;
yaxis reverse display=none;
xaxis display=none;
run;

#### Full SAS 9.4 SGPLOT code:

%let gpath=’.’;
%let dpi=200;
ods html close;
ods listing gpath=&gpath image_dpi=&dpi;

/*–Create Funnel Data–*/
data funnel;
input Level Value;
low=50-value/2;
high=50+value/2;
mid=50;
datalines;
1 100
2 90
3 75
4 50
5 30
6 15
7 10
;
run;

/*ods html;*/
/*proc print;run;*/
/*ods html close;*/

/*–Funnel Bar Chart–*/
ods graphics / reset width=5in height=3in imagename=’Funnel_Bar’;
proc sgplot data=funnel nowall noborder noautolegend;
highlow y=level low=low high=high / type=bar dataskin=matte;
text y=level x=mid text=value / textattrs=(size=12) strip;
yaxis reverse display=none;
xaxis display=none;
run;

proc sort data=funnel out=funnel2;
by descending value;
run;

/*ods html;*/
/*proc print;run;*/
/*ods html close;*/

/*–Create Polygon data for Funnel–*/
data funnel3;
keep x y id val mid yval;
retain thk 0.48 off 0.25;
retain prevLow prevHigh prevLevel prevValue id val yval;
set funnel2 end=last;
if _n_ = 1 then do;
prevLow=low;
prevHigh=high;
prevLevel=level;
prevValue=value;

/*–Script first node top vertices–*/
id=Level; Val=Value; yval=id-off;
x=prevLow; y=Level-thk; output;
x=prevHigh; y=Level-thk; output;
end;
else do;
/*–Script previous node bottom vertices–*/
x=high; y=prevLevel+thk; output;
x=low; y=prevLevel+thk; output;

/*–Script this node top vertices–*/
id=Level; Val=Value; yval=id-off;
x=low; y=Level-thk; output;
x=high; y=Level-thk; output;

prevLow=low;
prevHigh=high;
prevLevel=level;
prevValue=value;

end;

if last then do;
/*–Script last node bottom vertices–*/
x=high; y=prevLevel+thk; output;
x=low; y=prevLevel+thk; output;

end;
run;

/*ods html;*/
/*proc print;run;*/
/*ods html close;*/

/*–Funnel Bar Chart–*/
ods graphics / reset width=5in height=3in imagename=’Funnel_Poly’;
proc sgplot data=funnel3 nowall noborder noautolegend;
polygon x=x y=y id=id / label=val fill dataskin=sheen;
yaxis reverse display=none;
xaxis display=none;
run;

/*–Define a Range Attr Map–*/
data rangeMap;
id=’a’; min=0; max=100;
colormodel2=’LightBlue’;
colormodel1=’DarkBlue’;
output;
run;
/*–Funnel Bar Chart with Range Attr Map–*/
ods graphics / reset width=5in height=3in imagename=’Funnel_Poly_Range’;
proc sgplot data=funnel3 nowall noborder noautolegend rattrmap=rangeMap;
polygon x=x y=y id=id / fill dataskin=sheen colorresponse=val rattrid=a;
text x=mid y=yval text=val / backlight=0.25;
yaxis reverse display=none;
xaxis display=none;
run;