Building My First Interactive Map
This map was conceived from a viz I made that sprung from an idea I had for a “Hackathon” day we have each month at LiftedViz. Bellingham has an extraordinary brewery scene and I thought it would be fun to explore that. Well, the idea took root and just grew from there. First and last gardening metaphor, I promise. For some context, I have been working in the data visualization world for a total of 9 months. By the time I finished my ‘Brewery Viz’, I had been using Tableau for about 5 of those months.
The map you see was the most difficult visual I have made so far in my career. The grand vision I had going into this was way beyond the scope of my understanding at the time. I really had my work cut out for me on this one. It wasn’t easy and the execution isn’t perfect, but I came out on the other side with a functioning map that I’m proud of. In this article I’ll be going through the steps I took to create this map and what my thought process was. Although it will follow similar form, I am hesitant to call this a tutorial as the route I took and decisions I made were that of a beginner.
This article is intended both to illustrate the thought process of a beginner undertaking a complicated viz, and to explain how to replicate this viz for your own purposes.
The function: Connect data, then connect it again
The Vision: Before I can begin building, I need comprehensive data on the brewery scene in Bellingham. This means getting data on each brewery and every individual beer on tap.
The Challenge: Since this data is specific to the breweries and beer in Bellingham(and I don’t have the technical skills to scrape data), there was no existing dataset to utilize. I had to manually research and collect data on every brewery in Bellingham, and each beer they had on tap at the time.
The How-To: In order to get a genuine map of Bellingham, I had to track down a geospatial file containing city and neighborhood boundaries from a local government website. THEN, in order to accurately plot the breweries on the map, I typed in the address of each brewery into Google Maps and find the longitude and latitude of each.
The image on the right shows the relationship I had to form between 3 data sources: The first is the “Brewery Data” that contains each brewery and data on the breweries themselves, the second is “plans_neighborhood” which is the geospatial data for Bellingham, and the third is “Beer Specific Data” which is in-depth data on every beer at each brewery.
This relationship is set up so the data on individual beers relates to the breweries in “Brewery Data”, and the name of the neighborhoods in the geospatial file relates to which neighborhood each brewery is located.
I quickly encountered issues due to the relationship between the brewery data and the geospatial data. Neighborhoods in Bellingham that did not contain a brewery would disappear from the map completely. When I interacted with sets I made, additional neighborhoods would disappear based on which breweries were contained within the set.
The solution was to add another data source that was just a copy of my geospatial file and leave it disconnected from my other data. This way, the entire map of Bellingham could be displayed without being affected by changes I made to the main data set.
The Function: Setting Up map layers
The Vision: Creating a map in Tableau is fairly simple and intuitive. I won’t cover the process here since there are already plenty of good resources available. For this viz, I wanted the map to be dynamic and update colors based on changes made through parameters and sets (which I will cover next).
The Challenge: My objectives for this map added complexity that resulted in two problems I needed to solve.
The first was a “hover effect” that, while not fatal to the overall functionality, made for a bad user experience. As you can see below, hovering over some parts of the map caused the entire map and all of the borders to highlight. The neighborhoods without breweries associated with them acted as a singular unit.
The second problem was much more detrimental. Without the second data source added, whole swathes of the map would disappear due to parameters I created. The parameters in question were made to highlight specific breweries on the map based on certain criteria such as: “Who has outdoor seating”, “Who has a full restaurant”, etc. I would update the category in the parameter control, and only neighborhoods that had a brewery would display on the map. Not ideal.
This step solves the first problem, and in the end I was using 3 map layers to achieve the intended hover effect.
The How-To: I utilized multiple map layers, one of which was disconnected from my main data source in order to achieve this.
The bottom layer contains the Geometry field from the geospatial file needed to display the map of Bellingham, but uses the Neighborhood field from my Brewery data source, not the Neighborhood field from the geospatial file. These fields come from the data source that DOES have the relationship.
This setup meant that selecting between different categories in my parameter would affect the map and cause neighborhoods without a brewery to disappear. While this was originally the problem I sought to solve, it was necessary for the final map. The next step describes how I was able to work around this.
The middle layer uses the spatial file that I added and left disconnected from the original data source. It contains the Geometry and Neighborhood fields from the spatial file. I set the color opacity to 0% so the bottom layer would show through, but couldn’t be interacted with. Before I did this, I was having an unintended effect where hovering over the map would highlight the entire map and every neighborhood border instead of the individual neighborhood.
Now, when someone hovers around the map, each neighborhood will highlight and neighborhood boundaries are still visible even when the parameter is interacted with. Giving this layer 0% opacity meant the bottom layer would update with changes in the parameter, which will come into play in a later step.
The top layer contains fields from my brewery data source that does have the relationship to the other data. I used the Latitude and Longitude fields for the location of each brewery and the Brewery name Field. With this set up, I can have the map of Bellingham itself as well as the data points for each brewery able to change based on parameters and sets.
The Function: create parameters and sets for interactivity
The vision: for this map was to incorporate interactivity and have different breweries highlighted based on certain criteria. Want to know which breweries have full restaurants? Or who has prime outdoor seating? Select that category and how the corresponding data points are highlighted! To achieve this I needed 3 things: A parameter, a couple of sets, and a calculation to trigger the parameter. Here’s a great introduction to Tableau Sets.
The How-To: The parameter allows me to select between the different categories I plan on highlighting, which are “All Breweries”, “Breweries with a Restaurant”, and “Breweries with Outdoor Seating.” I’ll be using custom buttons to interact with the map later, but for now I ‘showed’ the parameter so I can use the default Parameter Controls and test for functionality.
Next I needed to create the sets that correspond to the parameter I just made. In my Brewery Data table I have fields with boolean (yes/no) values that coincide with the categories I want to highlight. For example, I have a column in my data labeled “Has a Restaurant” and for each brewery I have, I entered a value of “Yes” or “No”. This made the sets very simple to make. Create a set, include the ‘Yes’ values and exclude the ‘No' values.
Now I just need a calculated field to actually connect the sets to the parameter. I created a CASE statement calculation and put it onto both color and size in the marks card of the top map layer. My original thought was to use this field as a filter but I decided it looked better to instead keep the data points visible and just differentiate them through color and size.
The Function: A Heatmap based on parameter selection
The Vision: Yet another example of a simple solution after hours of trial and error and research! Another part of the grand vision was to have the neighborhoods on the map act as a heatmap based on which breweries were selected by the parameter. I wanted the breweries that were highlighted by the parameter selection to count towards the density of each neighborhood. If a neighborhood contained 4 breweries that all have great outdoor seating, and another neighborhood only contains one, you would easily see based on the heatmap which neighborhoods had what you were looking for.
The Challenge: Figuring out how to translate the selected breweries into a numerical value that I can use to update the heatmap.
The How To: The solution was a calculated field relating the parameter to the neighborhood value.
The trick was to turn this calculated field into a measure so it could be aggregated and affect the heatmap. I converted the field from a dimension into a measure, changed the default aggregation to COUNT, and dragged it onto color in the marks card.
That’s why I changed the opacity of the middle map layer to 0%. The bottom layer is now a heatmap based off parameter selection, but the middle layer prevents that unpleasant hover effect I was experiencing.
The function: Tooltips with brewery logos
The Vision: I wanted to have a really cool tooltip pop-up when you hover over each brewery.
The Challenge: How do I display each logo along with information from the data source such as the address and website? The solution was a viz-in-tooltip from a sheet that has each brewery associated with its logo (shape on the marks card). So when you hover over a brewery on the map, the viz-in-tooltip is filtered to just that brewery and only a single image will show.
The How-To: For the viz-in-tooltip, I opened a new sheet, placed ‘Brewery’ onto Rows as well as shapes on the marks card, updated the shapes to the custom ones I had, then just made sure each logo was associated to the correct brewery.
Then all I had to do was go to the sheet with my map, insert the sheet I just made as a viz-in-tooltip, and add the remaining fields I want to display.
The Function: custom buttons and interactivity
The Vision: For the final design, I didn’t want to use Tableau’s default parameter control. I have seen buttons being used in other vizzes so I decided to try and implement that. I thought buttons would look a lot cleaner and keep the design more consistent. Detailed steps for creating parameter actions and color-changing buttons.
The Challenge: Making clickable buttons that correspond to the selection of the parameter as well as updating the color of the button.
There are 3 things I need to make this happen:
I need a sheet with the shapes/buttons that will eventually be above the map on the dashboard.
I need a way to change the color and image of the buttons when one is selected, which will require some calculations.
And I need to have the buttons actually trigger changes on the map, which can be done through parameter actions.
The How-To: First thing is to create a new sheet for the buttons.
I double-clicked in the Columns card and created a calculation that just has “0” then I copied the pill two times.
Now there are 3 layers on the marks card, one for each button. I can change the mark type to my custom shape, and resize them.
Since I’m using custom shapes instead of Tableau shapes, I need to have a set of icons in black and yellow. I won’t actually be changing the color of the icon, but swapping it out for the other icon in the set.
Next, I need the shapes to swap when they are selected.
I need two calculations to make this happen. For each button I made an IF/THEN calc that returns a true or false value based on whether or not that category in the parameter is selected. I know in the calculation I used colors for the text, but that was just simpler than typing “yellow custom shape” and “black custom shape”.
I put this calculation on shape and chose which shape I wanted for true and for false. Which in this case was a yellow icon if that button was selected, and black if it wasn’t.
The second calculation isn’t much of a calculation, but it’s needed so the parameter can actually tell which button is associated with each value in the parameter.
I double-clicked on the mark card shelf and typed in the name of each of the categories I was using in my parameter; ‘Breweries’, ‘Outdoor Seating’, and ‘Restaurant’.
The last step is to add this sheet to the dashboard and make some parameter actions to be able to interact with the map.
Thankfully, this step is pretty straight-forward. I have 3 buttons so I need to make 3 parameter actions. The source sheet will always just be the worksheet with the buttons. The target parameter is the one we used both on the map and on the button worksheet.
I chose to run action on select, and to keep the current value. The only differentiator is which source field to use. I just needed to make sure I chose the text calculation I made for each of the buttons.
The outcome: A functioning, dynamic map of breweries in bellingham!
Before I started this viz, I hardly knew what a parameter or set even was. Now I’ve utilized multiple map layers, dynamic buttons, parameters, sets, actions, and calculations for nearly everything. After who-knows-how-many hours of reading articles, watching videos, experiencing road blocks at every step, I was able to execute my vision for this map. I may have bitten off more than I could chew, but the end result was worth it!
More than 100 hours were devoted to developing this entire viz, but it was an amazing learning experience and when all was said and done, it has earned almost 6,000 views to-date on Tableau Public and garnered enough attention to get picked up by TWO of the largest publications in Bellingham. Goes to show what a good idea and a little bit of exposure can do! I’m incredibly proud of how this turned out and it just solidifies how much I enjoy growing my Tableau abilities and my excitement for what I’ll be able to accomplish in the future.