Notice – if you are thinking of using this technique, please be a good citizen and keep your tile scraping to a minimum. I’ve had our product team tell me that aggressive use of this script hammers our tile servers, so to avoid this please don’t siphon to a deep level over a wide area. Let’s all play nicely together and we’ll get along.
A couple of weeks ago I saw a request from a customer asking if it was possible to have more detail in the Tableau offline map tile cache – that is the set of tile images that is included as part of a Tableau install and used when you select Map menu -> Background Maps > Offline.
Off the back of this request I did a little experimentation to see if it was possible to make the offline tile cache larger. Turns out it is possible and not terribly difficult, but it is (of course) unsupported.
The offline tile cache (for 64-bit Tableau Desktop) is in C:\Program Files\Tableau\Tableau 8.1\Local\Maps with subdirectories for languages. Under US is the English version which is where I was working. Under the normal directory you will find a series of nested folders that reflect the zoom level, each containing the tiles. Out of the box, Tableau provides tiles to zoom level 5 globally.
I have created two Python scripts. The first “get_tiles_globally.py” pulls tiles for the entire globe to a nominated depth. Edit the file to select which tiles you want to use (grey or original) and the depth to which you want to generate. Note that this is an exponential problem and each level has 2^n tiles so by the time you get to level 7 (for example) you will have 32K tiles. This makes the tile cache much larger and takes quite some time to generate so please be thoughtful of our tile servers.
To save some time and bandwidth, I have already generated tiles down to level 7 globally (i.e. 2 further levels of drill) and you can pull them from here:
It also turns out that we can selectively extract parts of the globe to a deeper level and if we are just drilling in on a smaller region this is a good way to have zoom level 8+ tiles. See the second Python script “get_tiles_bounded.py” – edit this to select the tile format, the zoom levels as well as a bounding box expressed in lat/long. It will pull the tiles just in this area.
Of course, this is:
- Unsupported – if this breaks, you can’t call support (or me 🙂 ) so you better keep a backup of your original tile folder;
- Going to break between upgrades – you must remember to back the cache up and reapply;
- Very slow to populate globally below level 6 and even in defined regions below level 10;
- Totally freaking awesome as we could use this technique to get other tile formats, potentially from other tile providers – offline aerial photography tiles, anyone?
PS: In case you are wondering where the URLs came from, they were the result of using Fiddler2 to watchTableau Desktop make requests. It will be a trivial exercise to find the URLs for other tile types in case you need other languages, levels of detail or if you intend to pull from a completely different tile provider.
Very clever Alan. Nice work!
– is that comptible with Tableau 8.2
– can it work on Tableau server? (our servers do not have internet access)
1. Yes, this will work for 8.2. The directory where you put the files is C:\Program Files\Tableau\Tableau 8.2\Local\Maps (for the 64-bit version) – just follow the directory structure in from there to set the correct language set.
2. Yes, this works for Tableau Server. The directory where you need to put the files is C:\Program Files\Tableau\Tableau Server\8.2\vizqlserver\local\maps
Sorry if I insist,
On Tableau Server, I have copied the “grey” file in the directory you told me. I have un zipped the file so that the tree is …\8.2\vizqlserver\local\maps\grey\…
The maps are not displayed.
Do I need to change parameters on Tableau Server?
Do I need to force the use of Tableau Classic maps with Tableau Desktop ?
Sure – happy to clarify. If you look in C:\Program Files\Tableau\Tableau Server\8.2\vizqlserver\local\maps\US\normal you’ll find a set of directories labelled 1 through 5. These are the zoom level folders and they are the ones we want to replace. Move these out to another location or delete them if you are not as conservative as me 🙂 and then open the grey.zip file. Go into the grey directory and you’ll find a new set of folders labelled 1 through 10. Copy these into C:\Program Files\Tableau\Tableau Server\8.2\vizqlserver\local\maps\US\normal as replacement for the original files.
In order to have the workbooks use these set of cached tiles you can have the workbook authors create their workbook with the offline maps options selected, but this requires them to do this every time. The other option is to “trick” Tableau Server into redirecting requests for online map tiles to the offline cache. You can do this by replacing online.tms and tableau.tms files in C:\Program Files\Tableau\Tableau Server\8.2\vizqlserver\mapsources\ with a copy of the offline.tms file in the same directory.
Hope this clarifies.
Pingback: Redirecting map tile requests | Alan@Tableau
thanks for taking the time to reply.
I have copied the png files under the Tableau Server\8.2\vizqlserver\local\maps\US\normal directory, and have replaced the online.tms and tableau.tms by the offline.tms file.
I still don’t have the maps.
Here is the content of the new online.tms file.
It seems that I can’t paste a xml content…
can you please explain in more detail how to set the bounding box expressions to match a requested area? Let’s assume, I want to only capture offline map tiles for whole Germany, how would I need to set those boundaries?
Thanks, appreciate your help!
First you need to work out what the bounding box is for the area of the world you want to extract. You asked about Germany so according to http://isithackday.com/geoplanet-explorer/index.php?woeid=23424829) the required bounding box is:
NE 55.05814, 15.04205
SW 47.27021, 5.86624
You would use these values in the Python script:
#bounding box to fetch
The script then has the logic to convert these lat/lon coordinates into slippy tile numbers. Note that the map tile URLs have likely changed since this post was originally made so you need to update the URLs as follows:
baseURL = ‘http://maps.tableausoftware.com/tile/d/mode=named%7Cfrom=tableau1_2_base/mode=named%7Cfrom=tableau1_2_admin0_borders/mode=named%7Cfrom=tableau1_2_place_labels/ol/’
baseURL = ‘http://maps.tableausoftware.com/tile/d/mode=named%7Cfrom=tableau2_2_base/mode=named%7Cfrom=tableau2_2_admin0_borders/mode=named%7Cfrom=tableau2_2_place_labels/ol/’
baseURL = ‘http://maps.tableausoftware.com/tile/d/mode=named%7Cfrom=tableau3_2_base/mode=named%7Cfrom=tableau3_2_admin0_borders/mode=named%7Cfrom=tableau3_2_place_labels/ol/’
Hope this helps.
Perfect, thank you so much for clarifying this.
Can you change the background color from White to black similar to the option when Online maps are enabled? Why is the map only white and cannot be changed when map option is switched to off??
The offline maps don’t have multiple styles – only the “light” style by default. If you want a different style, then you can download a different set of offline tiles using the techniques in this blog post (in fact you could pull just about any format now that we have MapBox integration).
First off all thanks for this post.
1. what is the URL we should use now if we want to focus only on specific area?
2. can we change the map image format (e.g. without any labeling on the map)?
3. any limitation on the map level drill down?
To work out the URL format you need, I suggest you use a tool like Fiddler4 to browse the HTTP traffic between Tableau Desktop and the map service. You will see it creates requests like the following:
By adjusting the layers and style in the “Map Layers” dialogue you can get the appropriate URL format.
If you want to focus on a specific area, then the “get_tiles_bounded.py” script is the one you want – you pass in the lat/lon details of the bounding box around the area you want to fetch tiles for. You can specify the tile level you want to fetch – this is a value from 1 through to 16 (the deepest). Be aware that as you increase the zoom level, the number of tile images returned increases exponentially.
Hope this helps.
Hi Alan, Amazing explanation and it was very easy to get the files ! Can we also download the data layers along with the tiles? I am looking for a specific data layer called household.
Thanks – glad this is helpful to you. I haven’t tried this personally but it looks like you can download the data layers as part of the tile raster files we download. The URLs has a more complex format – e.g.:
I suggest you use a tool like Telerik Fiddler2 (how I captured the above URL) to analyse the URL structure over a few requests, then see if you can use it in the Python scripts I provided.
Hope that helps.
Thank you Alan ! This is helpful. Also is there a way to know the level of the map when showing that on a worksheet? I.E I know that I need a specific view of the map but do not know what the level of view is, how do I find it?
Hi Rajshankar. Unfortunately there is no way to get this. The map zoom level isn’t something that is exposed to you in any way.
Is there a method to pass additional parameters in the request, namely the street, road and city layers?
Yes you can. Set the tiles the way you want them in Tableau and then use a tool like Fiddler to observe the HTTP requests being sent to the tile servers. This will show the URL structure for the tiles with the layers on.
Hi Alan, the link to the code has been expired. Would you mind uploading them again like to Google Drive? Thank you very much!
Sure – I’ve reposted them here:
Please make sure you keep your scraping to a minimum or you’ll incur the wrath of the map tile server gods.
You don’t want that.
Tried but downloaded folders were empty.
This material is no longer supported by me as I no longer work at Tableau.