The *R* Project for Statistical Computing has a smörgåsbord of functions available to use. This is obvious to anyone who has spent 30 minutes with the program. Tableau is also equally awesome and really excels for displaying maps. Again this should be manifest for anyone who’s spent 3 minutes with the product.

*(Finished Product)*

**Steps to Mapping a District using Tableau and R.**

Tableau 8.1 now includes R integration. This is my first major application of R and Tableau. I had played around with it before, using seasonal decomposition to remove the seasonal swings, but that was mainly for a personal view of the data and not anything to display publically. This post will outline how to do something very cool by combining Tableau’s easy mapping features AND R’s powerful packages. (want to skip over all these boring instructions? here is the finished workbook)

Basic setup needed before you attempt anything in Tableau (hold your horses we’ll get there soon):

**Step 1**: Install R and R Studio.

**Step 2**: Within R Studio, install the Rserve package.

Tools -> Install Packages

Type Rser and choose Rserve (and type the “ve” if you’re the OCD – intellisense hater type).

Choose Rserve.

Install

**Step 3**: Start up Rserve from the Rstudio Console:

> library(Rserve);

> Rserve()

Step 4: Connect Tableau to your local Rserve and test the connection

Use localhost and then test the connection:

BAM! You’re ready to rock with the data rock stars! \m/ (>.<) \m/

But now onto the hard stuff in Tableau (see that didn’t take much time):

Fields you need:

- Points you want to map.
- A Group or Grouping Hierarchy (if need be just create a calculated field Group = “group”)
- Latitude
- Longitude

Tableau calculated Fields:

Size: = SIZE()

R-Derived Calculated Fields (In Tableau):

Script_PolyOrder:

SCRIPT_REAL(“X<- matrix(,nrow=.arg1, ncol=2 );X[,1]<-.arg2;X[,2]<-.arg3;”+

“Y <- (ifelse(X[,1] %in% X[chull(X)],1,0));”+

“Z <- matrix(0,ncol = 1,nrow =.arg1);Z[c(chull(X)),1] <- seq_along(chull(X));Z”,[Size],attr([Lat]),attr([Long]) )

2nd Tableau calculated Field:

Script_In_Ext:

case [Script_PolyOrder] when 0.0 then ‘aInterior’

else ‘Exterior’

end

The first field “Script_PolyOrder” simply determines the polygon order of the points. The second script then determines whether the point is interior or exterior. I forced ‘Interior’ into ‘aInterior’ to make it come before Exterior. “Why didn’t your just rename ‘Exterior’ ‘Outside’?” Okay I realize that now as I write this blog, but I was going for pure function when I wrote this Tableau file. Below are two additional optional fields, which are useful for experimenting and determining how Tableau sees things. I will go more into this later.

Script_Lat:

SCRIPT_REAL(“X<- matrix(,nrow=.arg1, ncol=2 );X[,1]<-.arg2;X[,2]<-.arg3;”+

“Y <- (ifelse(X[,1] %in% X[chull(X)],1,0));”+

“Z <- X*Y;X[,1]“,[Size],attr([Lat]),attr([Long]) )

Script_Lng:

SCRIPT_REAL(“X<- matrix(,nrow=.arg1, ncol=2 );X[,1]<-.arg2;X[,2]<-.arg3;”+

“Y <- (ifelse(X[,1] %in% X[chull(X)],1,0));”+

“Z <- X*Y;X[,2]“,[TotalItems],attr([Lat]),attr([Long]) )

**Building the Map:**

Drag the pills on the map like this:

And dual axis the 2nd Lat pill. *The dual axis part can be done later if you’d like*. *It is somewhat nice for clarity to build the different parts separately and THEN see them some together.*

Make the first Lat a Polygon. Drag “Group” onto the detail shelf. Uncheck Aggregate Measures in the Analysis Menu. Drag Script_PolyOrder onto path and WHAM you have a polygon!

Now this is the important part for visualization. Make the 2nd Lat pill the Circle (or shape if you want to) and make sure the first Lat pill is the polygon. This is important because Tableau places the 2nd pill over the top of the first one.

**Shelf Examples:**

BAD shelf / Bad Vis example:

Good Shelf / Good Viz Example:

Now you have an outline for the “Group” and the interior points for that group do not matter to the polygon. Thus preventing any sort of jagged border that looks ugly.

**Last Step:**

Drag the calculate field Script_In_Ext onto the page shelf. Check “Show History”. Move the page shelf to the last page “Ext”. Adjust the “Fade” to fade out the previous. Now you are finished and it should look amazing. Keep reading if you want to know the details of how it was achieved:

**Alternate strategy:**

There is an another option I toyed with: http://community.tableausoftware.com/thread/140023

Basically if you already know your polygon order, and do not wish to have a dynamic polygon drawing, you can ignore using the page shelf and R entirely. Create a uniqueID which separates interior points from themselves and groups exterior points into the same group.

UniqueID

case [Script_In_Ext] when ‘In’ then “Str”+str(Attr([LowerHierarchy]))

else “D” + str(attr([NextLevelUpHierarchy]))

end

Add this to the shelf in place of your lowest hierarchy. In essence this calculated field dumps interior points into their own unique 1-point polygon and groups all the exterior points into 1 polygon. This was the first way I solved it, but looking back this is slightly more complicated AND requires me to know the polygon order. Adding in the polygon order in Excel is another post but it is possible and maybe preferable in some circumstances.

One benefit of this is by integrating R somewhere earlier in the pipe (Say with Rexcel or KNIME) you don’t need to bog down the visualization server with calculations (and recalculations). This is a good solution for many cases.

**Tableau and R**

Tableau wants to see Matrices and vectors from R. You can only pass 1 column of a matrix back to Tableau.

Lets go over Script_Lat. In this calculated field, you will pass the latitude and longitude to R, and get R to pass back the Latitude. This is purely illustrative and not needed to actually function

SCRIPT_REAL(“X<- matrix(,nrow=.arg1, ncol=2 );X[,1]<-.arg2;X[,2]<-.arg3;”+

“Y <- (ifelse(X[,1] %in% X[chull(X)],1,0));”+

“Z <- X*Y;X[,1]“,[Size],attr([Lat]),attr([Long]) )

First function:

X<- matrix(,nrow=.arg1, ncol=2 );

This creates a matrix X with a variable number of rows and 2 columns. This number of rows is based on the Size calculated field, which is the first argument after the R code in the Tableau

2nd & 3rd Functions:

X[,1]<-.arg2;

X[,2]<-.arg3;

Load Column 1 of matrix X with the 2nd argument, which is latitude, and load longitude into the 2nd column.

4th Function the confusing part:

Y <- (ifelse(X[,1] %in% X[chull(X)],1,0));

Basically save a matrix Y of the results of an if-then statement of points of X that are in the Convex Hull results of X. I know it’s hard to describe:

http://stackoverflow.com/questions/22072194/basic-r-how-to-populate-a-vector-with-results-from-a-function

http://stackoverflow.com/questions/22096182/r-retain-order-from-a-vector-apply-it-to-another-vector

5th function:

Z <- X*Y;

Save a Matrix Z which is matrix X and vector Y note that this is an “Element-Wise Multiplication” and not true matrix multiplication. This zeros outs any Interior points leaving only exterior points. The Tableau calculated field then uses this. This is a screen grab of Z within RStudio using random data showing zeros for the interior points.

6th function:

X[,1]

Now return Latitude back. X[,1] X[,2] or Z[,1] . This is the last step Tableau expects to see. Finished Calc’d field in Tableau:

**Possible Errors:**

You may get this error (possibly many times ) :

Press details. It could be that you need to start Rserve. Or you could need re-do the Size field (configuring the size field was difficult, play with Aggregate Measures / use Tableau’s Total fields or generally adjust so you’re sending R the correct # of elements to R). Or you did some sort of error within R. If the problem is R syntax, I suggest following the trail within RStudio to determine the error. Use this to generate random points and start debugging:

X <- matrix(stats::rnorm(100), ncol = 2)