Tableau introduced the R
integration in version 8.1 back in 2013. That’s awesome because it opens up to Tableau the whole range of analytical functionality R
offers. Most of the time the R code being triggered from within Tableau is rather short, such as a regression, a call to a clustering algorithm or correlation measures. But what happens when the code you want to run out of Tableau is getting longer and more complicated? Are you still bound to the “Calculated Field” dialog window in Tableau? It’s nice but it’s tiny and has no syntax coloring or code completion for our precious R
code.
But things will get arduous when trying to write longer code. So why not write the code externally in your favorite R
IDE (something I recommend doing anyways – even with shorter scripts!), save it to a .R
file and reference that code from Tableau’s calculated field? Sounds like a great idea, and it’s totally possible. Let’s try it out, shall we?
The simple and straightforward attempt
First attempt: Let’s just outsource the exact code we used in the calculated field to the .R
file and run source()
within the Tableau calculated field. Here’s the code which I then saved into a file called Rcode.R
in my Windows machine’s Downloads
folder:
model <- lm(.arg1 ~ .arg2) print(summary(model)) predict(model, interval = 'prediction')[, 1]
And here’s the accompanying formula for Tableau – please note that the path within the setwd()
function needs to be modified according to where you put your R
code file:
SCRIPT_REAL(" setwd('C:/Users/kgreger/Downloads') source('Rcode.R') ", SUM([Profit]), SUM([Sales]))
Did it work?
Nope, that’s not it.
The slightly more involved attempt
Next let’s try to call the external R
code file and pass the input data from Tableau as command line parameters. This is the slighly modified R
code – note that the first command line parameter commandArgs[1]
is the name of the script itself, hence we use arguments 2 and 3 here:
model <- lm(commandArgs[2] ~ commandArgs[3]) print(summary(model)) predict(model, interval = 'prediction')[, 1]
And the accompanying formula for Tableau:
SCRIPT_REAL(" setwd('C:/Users/kgreger/Downloads') system(paste('Rcode.R', .arg1, .arg2)) ", SUM([Profit]), SUM([Sales]))
Did it work?
Still not quite what we want. The problem here is that paste()
ing together an atomic string ("Rcode.R"
) and two vectors with length greater than 1 results in a non-atomic vector – which system()
can’t handle. You can check that yourself by running this R
code snippet:
str(paste("text", c("a", "b")))
A possible solution would be to translate the two input vectors into strings such as "c(10, 20, 30)"
, pass these to the R
code file and re-translate them into proper vectors. Sounds like a lot of work, both in terms of implementing it (which is why I didn’t even try that) and also in terms of what Tableau, RServe
and R
would have to deal with. Just imagine how long these two vectors would be with the 5,009 elements as shown in the workbook that accompanies this blog post… (Right click > Save target as...
)
The not so straight-forward but pretty slick (and working!) attempt
OK, so let’s think about what’s actually happening here to see if we can find a better solution for this. What we want to do is run code that’s written in an external file (our Rcode.R
), but use data from Tableau, which only lives in the Tableau fields or the meta-fields .argn
. If you think about it, that sounds like function call. And that’s actually the solution to our problem!
So within the R
file we wrap our code in a user defined function, like this – I decided to give it a prefix with my initials and the name of the main function it’s using, here lm
, hence kg.lm
:
kg.lm <- function(y, x) { model <- lm(y ~ x) print(summary(model)) predict(model, interval = 'prediction')[, 1] }
This is really neat, now we just have to modify the call from the calculated field in Tableau to use our newly created function:
SCRIPT_REAL(" setwd('C:/Users/kgreger/Downloads') source('Rcode.R') kg.lm(y = .arg1, x = .arg2) ", SUM([Profit]), SUM([Sales]))
Did it work this time?
Now ain’t that pretty? It totally worked! And neither the R
code nor the syntax in Tableau’s calculated field became significantly longer or more complex. There’s a few other nice aspects about externalizing your R
code this way (this starts to sound like one of those home shopping shows on TV…):
- You can re-use your R code in multiple calculated fields within one workbook or even across multiple workbooks and still have only one place to manage/edit/update the code. Imagine you developed a nice machine learning model with a few hundred lines of code and suddenly discover a bug – you wouldn’t want to have to browse through all your workbooks using this model to correct the bug there, would you?
- You can put many of these user defined functions in one single
R
file,source()
this in your calculated fields and use just the functions you need. - The previous fact is especially interesting regarding the fact that you can preload external
R
resources when firing up yourRServe
session. This needs to be done in a file calledRserv.cfg
, which needs to be placed in theRServe
folder:DRIVE:\INSTALLATION_PATH\R\R-VERSION_NUMBER\library\Rserve\libs\x64
(or\i386
if you’re on a 32-bit machine) – the parts in italics need to be set accordingly. There’s a lot of documentation about what can go in theRserv.cfg
file, but for our purposes here it is sufficient to put the following line for each externalR
code file you’d like to preload:source C:/MyFolder/sample.R
And there you go: Running code from an external .R
file in Tableau’s calculated fields. Enjoy and let me know if you run into problems or know an even easier way of doing this. If you want to skip all the hard work and just look at the ready-made thing, feel free to download the workbook that accompanies this blog post… (Right click > Save target as...
)
Hi,
Thanks for the article. I am facing an error even with the final version of the code.
The error is as follows :-
An error occured while communicating with the Rserve service.
Error : ‘\U’ used without hex digits in character string starting “”C:\U”
P.S. : I am able to run R codes internally from Tableau. the error is specific to calling external functions from .R files.
Try using either forward slashes
/
or masked backslashes\\
.Hi,
Great article.
I would like to ask, is there any way to catch errors in SCRIPT_REAL function in Tableau?
My script is below. It works in most of the cases but sometimes I get the following error:
Error in x[1L:after] : only 0’s may be mixed with negative subscripts
Script:
SCRIPT_REAL(“library(forecast);
time <- ts(.arg1,start=c(2013,1), frequency=52);
fcast <- forecast(time, h=.arg2[1]);
n<-length(.arg1);
append(.arg1[(.arg2[1]+1):n],fcast$mean, after = n-.arg2[1]);"
,[RUNNING_RESOLVED],[Days Ahead])
Regards,
Mircea
Hi Mircea!
Debugging in R is always challenging – especially with the R code embedded in a Tableau SCRIPT_ function. My only advice would be to check your code in standalone R (preferably a nice IDE like R Studio) for bugs and to make heavy use of outputting messages and temporary data dumps to the console while testing your code. Hopefully this will help you find the bug in your code.
// Konstantin
Thank you for the tip! This really helps! great work!
You’re welcome. Enjoy!
Hi,
Thanks a lot for the article.I am struggling to run my R code in Tableau.
I have some R code and the output is data frame.I just want to display the output of r code as a data frame but in tableau. Please let me know how can i run my r code in Tableau as we do in R studio.
The biggest problem in your case is probably that your’re trying to return more than one column from your R script back into Tableau. That’s currently not supported, I’m afraid.
There are a few (hacky, admittedly) ways to work around this limitation, though. I presented one of them in my Hands-On Training Session on R at Tableau Conference 2017 in Las Vegas, which involves pasting the contents of, say, column 1 and column 2 by a character you’re absolutely sure will not occur in either of those columns (I often use the tilde ~ for these), which will result in only one return vector. This can then be split up in Tableau into two columns and evaluated independently.
Seeing it written here in just two sentences probably doesn’t make too much sense, so I’ll try to put together a full blog post on how to do that, soon. In the meantime feel free to google it – it’s been suggested and used by many people before me.
Hi Greger,
Thanks for the blog.
Is there a way we can publish R-Tableau integrated dashboard in Tableau Server?
My pleasure. It’s absolutely possible to do that, yes! You can find all the necessary information in the Online Help.
[…] fields, you can read more about it in official Tableau resources here, here, and here and also here on my blog. But part of the game is that there is only one vector of data being returned from the R session […]