“R you nuts?” is what my colleague asked me when I once proposed this little hack. He’s not completely wrong, we’ll get to that later…
The task I was presented with was to embed the graphical output from an R package in a Tableau dashboard. Of course it’s possible to run R code from within Tableau Calculated 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 via Rserve into a Table Calculation in Tableau. So what about some of the complex graphics R can produce? Sure, you can try to rebuild those natively in Tableau based on the data returned from the code. But what if a) you’re too lazy to do that (and also it’s all just about rapid prototyping something anyways), or b) the visualization is just too complex (think 3D brain models)?
If you think about it, what I’m proposing here is both super simple and ridiculously hacky. We’re going to run R code from some calculated field just like we always do. That way we can leverage all the easy-to-use interactivity of a Tableau dashboard to affect what the R code does with the data, e.g. by changing parameters or selecting subsets of the data. The R code will then do its thing and produce some result. Only, the result in this case isn’t a vector of data (it can be, in addition to what we’re going to talk about next, though!) but a plot of some kind. Now here’s the nasty bit: within our R code we will persist that plot to disk using a well-bespoke filename and location. (Feel free to close this browser tab now with a judgemental look on your face.) Since the SCRIPT_*()
functions in Tableau have to see some results coming back from the code we can send some dummy data like n 0
s or 1
s (n being the length of the input vectors – remember that all input vectors and the output vector have to be the same length – or just one of the input vectors back. Here’s a minimal example of what the Calculated Field with the R code could look like:
SCRIPT_REAL(" png('C:/ProgramData/Tableau/Tableau Server/data/tabsvc/httpd/htdocs/rplot/rplot.png', width = 500, height = 500) plot(.arg1, .arg2) dev.off() return(rep(1, length(.arg1))) ", AVG([Discount]), SUM([Profit]))
When displaying the image on the dashboard we then need to make sure it’s updated whenever the code was rerun and some parameters have changed. So a regular image container is not really useful here. The trick is to host this image on a web server as part of a website that refreshes itself in regular intervals. And of course that’s total overkill, especially if you’re actually in a quick prototyping phase and didn’t just pretend you were. Where to get a web server quickly and easily? One easy and free solution is XAMPP, a cross-platform Apache distribution containing (among other components) a web server. Another one is Fenix. If you’re a bit more adventurous and tech-savvy you could use nginx or npm. Or, since we’re talking about R scripts here, you could run a simple HTTP server in R or even in Python (OK, that last one is just silly…) And then there is one option which is really only for testing purposes and should never ever be used in a productive scenario. Also, it only applies if you have a running instance of Tableau Server at hand. Only few people are aware that Tableau Server is running a fully-fledged http server that you can (but shouldn’t) bend to your wishes. Like, say, for serving our R plot. You can find it if you navigate to C:\ProgramData\Tableau\Tableau Server\data\tabsvc\httpd\htdocs
on a Windows machine or whatever it is on Linux (possibly /var/opt/tableau/tableau_server/data/tabsvc/httpd/htdocs/
). May I suggest you create a subfolder there for your stuff? And also, please note that this is totally unsupported of course and ideally shouldn’t be done at all.
Once we have a place to put the image we need some HTML page to embed that image into, which refreshes itself. For the latter part we’re leveraging the magic that is http-equiv="refresh"
, so in its simplest form that website could look something like this:
<html> <head> <meta http-equiv="refresh" content="5"> </head> <body> <img src="./rplot.png" alt="My R Plot" height="500" width="500"> </body> </html>
Needless to say that you have to modify the actual path and filename in the src
parameter as well as the height
and width
parameters to fit your needs. This file should be saved into the above-mentioned htdocs
folder (don’t forget the subdirectory for your stuff!) and we’re done. On the Tableau end we need to embed a website container with a link to that HTML document and you’re done.
Getting back to my colleague’s loving comment regarding my failed state of mind: Yes it works, surprisingly good even, considering the little work that was necessary to achieve the goal. But please be warned that this approach will cause some significant load on the server you use to host the HTML page and the embedded R plot image. You can define exactly how much load you want to generate by modifying the content
parameter in the meta
tag (I set it to five seconds on line three in the example above). Still, don’t do it. Unless you really need to or want to, and are happy with being bullied by your colleagues. I uploaded the files from the minimal example I’ve shown above for your reference so you don’t have to start from scratch: https://app.box.com/v/rplotsintableau