[This is one of those posts where I am going to show you something cool and useful, and then advise you that this is something you shouldn’t do. The URL in this post is undocumented and unsupported (by Tableau and by me) so if you are not comfortable with that, go no further. Here, there be dragons…]
Below is a conversation I have semi-regularly with customers:
Customer: Hey Alan! We love our dashboards and we’d like to use them in some printed materials we produce. Can we do that?
Alan: Of course you can. You just copy or export an image file and you have a nice PNG, JPG or BMP to work with. Whack that in there and away you go!
Customer: Yeah, we tried that. But the image file formats are produced at screen resolution and become fuzzy when printed as part of a document. Can we get something better?
Alan: OK – then try using a vector file format. You can export to EMF or PDF which produce nice scalable output?
Customer: Again, we tried that. It’s pretty good, but it doesn’t work well for embedded bitmap content like map backgrounds, and we can’t export to EMF from Tableau Server so we can’t automate the process very well. What else can we try?
Alan: Hmm… let me have a think about it.
[Walks over to the marketing team…]
Alan: Hey guys! How do you produce the nice looking images you use in your handouts and printed materials?
Marketing: We open them in Tableau Desktop on a Mac and take a screenshot to get a retina-resolution image.
Alan: Hmm…
So I started looking for a way to have Tableau produce a high resolution image in a way that could be automated, and an idea came to mind. With the new Tableau mobile applications on iOS we have offline snapshots – these are high resolution images of the dashboards/views/stories/etc. They are rendered at retina resolution so is there any way we could use these?
I started digging around and eventually I found that these applications are using a special URL to request these images:
http://<server>/vizql/sheetimage/<view_id>?:pixelratio=2
The view ID is the internal Tableau ID from the repository. You can query it from there, or you can find it by browsing to the view in Tableau Server and then searching the HTML of the page for “current_view_id”. In Chrome, just open the developer tools (F12 or CTRL-SHIFT-I) and then CTRL-F to search:
By adjusting the :pixelratio parameter we can generate higher resolution images:
:pixelratio=1
This is the standard resolution for most devices.
:pixelratio=2
This is the resolution we generate automatically for retina devices.
:pixelratio=4
But we can take this higher…
:pixelratio=10
Much, much higher.
This allows us to create high-resolution images of our dashboards. Playing around with this I’ve discovered a few traps for young players:
- You need to be logged in to a Tableau Server session to hit this URL. If you aren’t then you get the following error message:
{“result”:{“errors”:[{“code”:46}]}}
- If your dashboard contains maps, using a :pixelratio greater than 2 won’t help as the maps are generated at :pixelratio=1 and blown up so they become grainy. Using :pixelratio=2 tells Tableau to use the hi-dpi map tiles like we would on a retina device.
The final step was to find a way to automate the production of the images via script. Because this is an internal URL it isn’t part of the traditionally scriptable interfaces such as TABCMD or the REST API. However using cURL, a command-line URL transfer tool, and trusted authentication we can create a simple script to emulate a user logging in and then fetching an image from this URL:
REM – Obtain a trusted authentication ticket and load it into an environment variable. curl http://<server>/trusted -d "username=alan" > ticket.txt set /P ticket=<ticket.txt REM – Use the ticket to log in using any workable URL. The session cookie is persisted to a file. curl "http://<server>/trusted/%ticket%/workbook.xml" -L -c cookie.txt REM – Fetch the image file from the new URL using session data from the cookie file. curl "http://<server>/vizql/sheetimage/1?:pixelratio=2" -b cookie.txt -o image.png
Note that this requires trusted authentication to be configured with unrestricted tickets enabled.
Enjoy – but remember this is unsupported and the URL structure could change at any time. Make hay while the sun shines, friends!
You can also zoom your browser (ctrl-mouse-wheel) and refresh the page to get a similar but slightly different effect. The text will zoom and the vizes will re-render to look good at the larger size. This is particularly useful in presentations. I’ve also used it for applications like this – I make my screen high res, make the browser window big, zoom the browser and take a screen shot.
–DLev
Thanks DLev – great tip, especially for presentations. It’s also a simple solution for screen grabs but your screen needs to be big enough to view the whole dashboard at 200%+ zoom (which for many users won’t be possible) if you don’t want to have to stitch multiple images together.
Thanks Alan for posting this. Awesome work around for an important issue I was having, namely, it allows my exported images to be of a better resolution. I played around with DLev’s suggestion too, and it too provided me with an improved post export image. Coding may scare off some people, so though I will use your solution for myself, I will show DLev’s solution to others (namely my less tableau savvy clients/customers/users).
Reblogged this on I'm nia..
Alan, does this method work when using Tableau Public as the server or do you need to have Tableau Server set up?
Hi Jonathan.
Sorry I just saw your comment now. It doesn’t seem to work for Tableau Public, but it does work for Tableau Online. I’m not surprised that Tableau Public doesn’t work as it is somewhat different under the covers compared to Tableau Server and Tableau Online.
Hope this helps.
I am just wondering, if a high resolution bitmap is needed, wouldn’t it be the best option to export a pdf and then rasterize it, i.e. convert to a bitmap? With a pdf you can get literally any pixel count you want. I know someone said the pdf doesn’t really work, but I assume they meant embedding a pdf on the website. You can do the rasterization with numerous (free) programs, I am pretty sure Inkscape or ImageMagick will do that in no time.
Hi Matt, if you are producing .bmp aren’t you just pushing these out using the worksheet/dashboard > export menu ?
The idea I was trying to describe is that if the goal is to get a good quality raster image from your visualisation then Tableau itself is clearly not great at that task as the resolution is not very high. But Tableau does fine at exporting a PDF, which is a vector image format, which essentially means it is of perfect/infinite quality. But you can easily convert a PDF to a raster format like PNG or BMP. So to answer your question, I wouldn’t export a BMP with Tableau at all, I would export a PDF an then use a program other than Tableau to convert the PDF to whatever format you need. This is probably the most robust solution, and gives you most and easiest control over the resolution and other properties of the resulting raster image.
Is this doable through JS API?
Hi Ram,
Not directly, however you might be able to do it using one of the techniques listed here: http://www.dataplusscience.com/HighResolution.html. Invoke the viz with the :pixelratio parameter and then use the JSAPI to download the image? Worth a try – let me know if it works for you.
Cheers,
Alan
Hi Ram, I just found that we are adding this functionality to our REST API in 10.2. Not sure if this link will work for you but check it out here:
[video src="http://mkt.tableau.com/video/10.2_High-Res_Image_Endpoint.mp4" /]
So yay for progress!
Cheers,
Alan
Great post Alan! Exactly what I needed.
Thanks Alan, I have 2 questions.
1) when I append the parameter refresh=y, the image does not get refreshed with new values for filters. Any idea whats happening?
2) Also in the url can I pass in filters? the following did not work where in I have a filter called category_nm and the value Capital. It returns the whole image.
http:///vizql/sheetimage/?:pixelratio=2&category_nm=Capital.
Hi RG,
Sorry, but the URL that I’ve documented here doesn’t work like the regular REST API so you can’t pass parameters in like you are trying.
Cheers,
Alan