A New Method for Creating Hex Maps

We love hex maps. We’ve written several blog posts about them and we use them all the time in both our personal and professional projects. Over the years, there have been several different methods for creating them in Tableau. Several years ago, Kevin wrote What the Hex? (A Brief History of the Hex) in which he walks through the various methods developed by the Tableau community—from Brittany Fong’s and Matt Chamber’s coordinates-based tile maps to the polygon file approach developed by Rody Zakovich to the spatial files created by Joshua Milligan and Luke Stanke. Another option not mentioned in the blog—since the blog is now 7 years old—was a method developed by Shaun Davis that built upon the coordinates-based solution and used calculated fields instead of an additional data file (Kevin mentions it in tip # 10 on Ten Tips including "Create a Hex Map Without Adding a Data Source).

 

Until recently, my favorite approach has been the spatial file created by Luke Stanke, but Kevin and I recently stumbled on a new approach that has since become our preferred method. In this blog, I’m going to quickly review the various methods, detail some of the drawbacks of each, then share the new technique.

 

Coordinates

This method entails joining or relating your data set to a spreadsheet or text file that contains the geography (we’ll be using US states) and the X and Y coordinates (Columns and Rows, respectively).

 

 

We then plot the X and Y coordinates using a scatterplot and a custom Hexagon shape.

 

 

Note # 1: The coordinates file that is typically used requires that you reverse the Y axis. As it will simplify things later, I’ve reversed the coordinates in the file itself so that this is not necessary. If you’d like that file, you can find it here: US Hex Map Coordinates.xlsx

 

Note # 2: When using standard mark types such as circles and squares, Tableau can automatically change the color of the label (e.g. white on a dark background and black on a light background) in order to increase the contrast between the mark color and the label color (making it more readable). However, it cannot do this with custom shapes. To address this, I’ve used a second axis using a circle mark type. And, in upcoming examples, I’ll use a second map layer. For more details on this technique, see tip # 2 on Ten Tips including "Show the Axis on the Top but Not the Bottom"

 

Unfortunately, there are several issues with this approach:

 

1.     Separate Source – It requires a separate file be added to your data source.

2.     Padding – You must fiddle with the width and height of the chart to get the right padding/spacing between marks.

3.     Dashboard Issues – When you add the sheet to the dashboard, things can get messy, requiring that you adjust the size of the sheet and the size of the marks.

4.     Filters – If you apply filters, the marks completely disappear.

 

We can address the first issue by leveraging a method developed by Shaun Davis. Instead of bringing in a separate file with the coordinates, we create large CASE statements to get the Row and Column values. The Row calc looks something like this:

 

CASE [State/Province]

WHEN 'Alaska' THEN 0.0

WHEN 'Alabama' THEN -6.0

WHEN 'Arkansas' THEN -5.0

WHEN 'Arizona' THEN -5.0

WHEN 'California' THEN -5.0

WHEN 'Colorado' THEN -4.0

WHEN 'Connecticut' THEN -3.0

WHEN 'District of Columbia' THEN -5.0

WHEN 'Delaware' THEN -4.0

WHEN 'Florida' THEN -8.0

WHEN 'Georgia' THEN -7.0

WHEN 'Hawaii' THEN -8.0

WHEN 'Iowa' THEN -3.0

WHEN 'Idaho' THEN -3.0

...

 

The end result looks exactly the same, but we’ve at least eliminated one of the issues detailed above. But what about the other issues?

 

Spatial Files

Fortunately, Joshua Milligan and Luke Stanke have come to our rescue!! They took the US hex map and turned it into a spatial file—specifically, a shapefile. We relate this shapefile to our data, as shown below.

 

 

Then we use the Geometry field to automatically draw the map.

 



So, does this address the rest of our issues? Actually, it does (though we’ll need a couple of tricks). The spatial file automatically creates nice padding between each mark without the need for us to fiddle with the width and height. And, when we add it to a dashboard, it automatically resizes everything, keeping equal padding between the hexagons. One potential concern might be that the padding is built into the shapefile, so you can’t increase or decrease it. But this can be addressed by changing the mark type to shape and using a hexagon shape. That also allows us to use different styles of hexagons (I’ll share a few examples later).

 

Applying filters will still make the marks completely disappear, but we can use a separate data source and map layers to create a sort of static background map. To learn how to do that, see A Solution to the Hex Map Filtering Issue.

 

This method is pretty close to perfect, but it still has a few drawbacks.

 

1. Refreshing on Cloud/Server

Last year, I discovered an issue with refreshing extracted data sources on Cloud (and presumably Server). When the data source includes tables from a database related to a spatial file, that data source doesn’t properly refresh. All indications are that the refresh completed—the job completes successfully and the data source extract dates get updated, but if you dig into the data source, you’ll find that it didn’t actually refresh. I haven’t tested this issue recently, so I’m not sure if it still exists, but my previous experience (and how hard it is to see that it’s actually happening) has made me very wary about creating data sources that relate tables from a database to a spatial file. Ultimately, it would be nice to avoid the spatial file altogether.

 

2. Other Hex/Tile Maps

I’ve seen and used lots of different tile maps—Canada, Europe, Africa, the entire world, etc.—but, to my knowledge, the only one that’s been converted to a spatial file is the United States. Creating spatial files for all other hex/tile maps would certainly be doable, but it would require using additional tools (a GIS platform) and specialized skills. I’m okay with GIS, but I’d rather find a more Tableau-centric solution.

 

Spatial Coordinates

So how can we address these two problems? The answer…spatial calculations!! Let’s go back to the Shaun Davis method—the one that creates calculated fields for Row and Column. This data source only has our primary data—no secondary file of coordinates or spatial files. We’re going to take those Row and Column values and convert them into geospatial coordinates. It doesn’t really matter that they aren’t actually Latitude and Longitude values—we’re just going to trick them into acting as Latitude and Longitude. Let’s create a calculated field that converts these into a spatial point:

 

Point Coordinate

// Convert the X & Y coordinates into geospatial coordinates.

MAKEPOINT([Row], [Column])

 

We then simply drag that to our view, in the same way as we did with the spatial file Geometry field.

 

 

Boom!! We have a hex map—one that did not require any additional data files to be added to our data source and one that can be created for any country, continent, etc. as long as we have the X and Y coordinates.

 

But, there’s a slight problem. Notice that there is more vertical spacing than horizontal spacing? This might not be a big deal to most people, but it drives me crazy!! I must fix this!

 

Let’s Get a Little Wonky…

Warning: We’re going to get into some low level technical stuff here, so feel free to skip to the end of the section where I show you the updated calcs. If you want to get nerdy with me then, hell yeah! Keep reading…

 

So, what’s going on here? Two things actually. The first problem is that we’ve converted cartesian coordinates (X and Y) to geospatial coordinates (Latitude and Longitude). These are very different coordinate systems. The “distance” of a unit on a cartesian plane is static. The distance between 0 to 1 is exactly the same as the distance between 1000 and 1001. And it doesn’t matter whether the coordinate is on the X axis or the Y axis—0 to 1 on the X axis is the exact same distance as 0 to 1 on the Y axis. This is because cartesian planes are two dimensional (i.e. flat) surfaces.

 

The globe, on the other hand, is a three dimensional mostly-spherical object. The result is that the “distance” of a unit in geospatial coordinates is not always equal. Latitude lines are parallel lines running east and west. Because they are parallel, the distance between units of Latitude is more or less static—around 69 miles (it varies a bit due to the fact that the earth is not a perfect sphere—ranging from 68.703 miles at the equator to 69.407 at the poles). Longitude lines are different—they run north and south, converging at both the north and south poles. So, it follows that the distance between Longitude lines are largest at the equator (69.172 miles) and get smaller the closer you get to the poles.

 

Wikipedia
 

That was a long explanation, but important to know. That said, it ultimately doesn’t impact us that much—at least not enough that we’d actually notice it visually. Our coordinates are all relatively small (close-ish to zero) meaning that they are very close to the equator. At the equator, the distance between units of Latitude and units of Longitude are pretty close to the same value—close enough that we probably wouldn’t be able to see the difference.

 

However, it is possible that someone might make build a hex map with coordinates closer to the poles. For example, if we adjusted our Rows to go from -100 to -108, the difference would be much more noticeable.

 

 

This will plot our hex map significantly closer to the south pole. Thus, the distances between lines of Longitude are much smaller than the distances between lines of Latitude. In other words, the 1 horizontal unit is much smaller than 1 vertical unit, which leads to the smooshing we see above.

 

While we could figure out the exact math to deal with these differences and adjust them—as Andy Cotgreave and I detailed in his blog, How to make art out of your Strava activity data with Tableau—it’s overkill here. Instead, we can just divide our Row and Column values by some arbitrarily large number, making them very very close to zero. Let’s create calculated fields for both of these new adjusted Latitudes and Longitudes:

 

Hex Latitude

[Column]/1000000

 

Hex Longitude

[Row]/1000000

 

With these values very close to zero, there is pretty much no way we’ll ever notice the problem (at least until someone creates a hex maps with huge numbers for coordinates!!!)

 

But this is only part of the problem causing the spacing issues. The second problem is much simpler. The hexagon shape is taller than it is wide. The shape I’m using is 504 pixels tall by 437 pixels wide—a ratio of about 1.1533. This is, of course, true of both the coordinates method and the spatial file. With the coordinates approach, we just resize the chart/sheet so that it’s wider than it is tall. Don’t believe me? Here’s a hex map using the coordinates method where the axes have been set to be more or less equal. Just like our spatial coordinates, the vertical padding is much larger than the horizontal padding.

 



I’ll admit that I don’t 100% know how the spatial file addresses this problem, but Joshua and Luke clearly made adjustments so that the solution is baked into the files themselves.

 

Fortunately, the solution is simple—we either divide the rows by the 1.1533 ratio or we multiple the columns by the ratio. I’ll divide the rows, resulting in the following Longitude calc:

 

Hex Longitude

[Row]/1.1533/1000000

 

That ought to do it, so let’s combine these together in our MAKEPOINT calc and try it out.

 

Point Coordinate

MAKEPOINT([Hex Longitude], [Hex Latitude])

 


Yay, it works!

 

That was a long explanation, but ultimately, the solution is pretty simple. Let’s recap:

 

1.     Create the Column and Row calculated fields.

2.     Create the Latitude and Longitude calculated fields, being sure to adjust based on the shape size ratio and by a large number to keep the value close to zero.

3.     Create the geometry using MAKEPOINT.

 

Advantages

The advantage of this method are:

 

1.     No Separate File – No need for a separate file in your data source.

2.     Padding Control – Complete control over padding. Easily make it as large or small as you like.

3.     Dashboard – Limited issues when adding to a dashboard. Note: Unlike spatial files, you’ll need to manually resize the sheet and shapes once added to a dashboard.

4.     Equal Padding – No need to fiddle with height and width of the chart to get the right padding in between marks.

5.     Filters – Using the technique mentioned earlier, you can ensure a mark is always visible, even if it’s filtered out.

6.     Cloud/Server Refresh – Since no secondary files are in the data source, there is no risk of issues when refreshing the extract.

7.     Works for Anything – No need to use a GIS tool to create a spatial file. If you have X and Y coordinates, you can use this method to create your hex map.

8.     Styling – You can apply any type of styling you want. And since it’s a map, you can have unlimited map layers.

9.     Any Shape – This method allows you to use any shape you like.

 

Let’s talk a bit about the last two advantages. These are not exclusive to this new method because, as I shared earlier, you can change the mark type when using a spatial file, allowing you to use whatever shapes and layers you like. For example, here are a couple of alternative hexagon shapes:

 



However, those shapes need to have the same height to width ratio as the hexagon we’ve been using. Otherwise, the built-in adjustments will not be accurate and will lead to padding differences. For example, if we choose a square mark using the spatial file, we’d see something like this:

 

 

The horizontal padding is much larger than the vertical padding. It’s not bad at all, but I’m a perfectionist and I really want it to be equal. With the new spatial coordinates technique, we can simply adjust the ratio used in the Longitude calculation. In this case, since the ratio between the height and width of a square is 1, we can eliminate it altogether.

 

Hex Longitude

[Row]/1000000

 

And then we get a perfectly padded square tile map.

 

 

Note: The alternative hexagons shown above did not have the exact same ratio as the original hexagons, so the ratio used in the calculations had to be adjusted to 1.1 in order to get equal padding.

 

Wrap Up

OK, that was a little bit wonky and I’m sure everyone probably thinks I’m the most anal-retentive person alive (I need that padding to be exact!! 😉)

 



But I do think this new method for creating hex/tile maps is the superior method. I hope you find it useful in your work. If you’re interested, you can find the workbook used here on Tableau Public.

 

Thanks, as always, for reading and if you have any comments, please leave them in the comments section below.


Ken Flerlage, January 19, 2026

Twitter | LinkedIn | GitHub | Tableau Public


No comments:

Powered by Blogger.