Introduction
Although heatmaps are often called hotspot maps, they are different. A heatmap identifies data clusters without considering other attributes and is not statistically significant. They are good for quick visualizations of data clusters. This tutorial will show you how to create a heatmap using R, the ggmap package, and FME. To get started with FME and R, read the Tutorial: Getting Started with the R Caller, as well as the RCaller Transformer documentation.
Requirements
- R Installed
- RStudio or any R console
About ggmap
ggmap is an R package that creates spatial visualizations on top of static maps. If you are already familiar with the ggplot2 package, the functions are the same.
Update: Stamen Maps shutdown
The example below originally used Stamen Maps for the base map, since ggmap is presently limited to Stamen Maps or Google Maps. Stamen Maps is being shut down on October 31, 2023, and its maps are now hosted on Stadia. The example has been updated to use Stadia instead of Stamen Maps.
At the time of this update, ggmap had not been officially updated to connect to Stadia, but Stadia is supplying a fork with this capability. We expect this fork to be merged into the official ggmap in the future.
If you find that the RCaller fails using the instructions below, please follow the instructions below to update your ggmap installation to the Stadia fork:
https://docs.stadiamaps.com/guides/migrating-from-stamen-map-tiles/#ggmap
Step-by-step Instructions
Please ensure you have R installed on your computer before you begin. We will be using RStudio to install the ggmap package, but you can use any R console.
1. Open RStudio (or Another R Console)
Open RStudio and create a new R Script. We will need to install the ggmap package before we can continue in FME.
In the new R script, type and run:
install.packages("ggmap")It is also a good idea to test your script in the R console first before using the RCaller in FME. The console provides better debugging messages and lets you see what is happening with your data in real time. For this tutorial, we will jump right into FME Workbench since the script has already been debugged. If you are using your own data, use an R console first.
2. Get Stadia API Key
Stadia requires an API key to use their base maps in ggmap. You can get the API key by signing up for a free account at stadiamaps.com.
After creating a Stadia account, log in and create a Property on the welcome page. In the Authentication Configuration for the new Property, choose +Add API Key. The new key will be displayed and can be copied for use in the RCaller
3. Read in Crimes CSV Data
As of FME 2025.2, the Coordinate System parameter is now configured within the Parameters dialog of each reader/writer format. For more information, including details about the change and affected transformers, please see Coordinate System Parameter Location Change.
-
In a new workspace, click the Add Reader icon in the Toolbar and add a reader with the following parameters:
Format: CSV (Comma Separated Value)
Dataset: /crimes2012-17.csv
Click the Parameters button to set the coordinate system:
Attribute Definition: Manual
Name Type X x_coordinate Y y_coordinate Create Point Geometry from Attributes: Enabled
Coordinate System: LL84
Click OK to add the reader to the workspace.
-
In a new workspace, click the Add Reader icon in the Toolbar and add a reader with the following parameters:
Format: CSV (Comma Separated Value)
Dataset: /crimes2012-17.csv
Coordinate System: LL84
Click the Parameters button and confirm that the X and Y attributes are set to x_coordinate and y_coordinate, respectively. If they are not, change the Attribute Definition to Manual, then manually set.
Click OK to add the reader to the workspace.
Input CSV Crime data
4. Create User Parameters
We need two user parameters to select the crime type we want to analyze and where to save the final image file.
In the Navigation window, right-click on User Parameter and select Manage User Parameters. Then click the + button to add the following parameter:
| Type | Choice |
| Name | TypeOfCrime |
| Prompt | Choose a crime to analyze: |
| Published | Yes |
| Required | Yes |
| Attribute Assignment | Off |
Expand the Choice Configuration section, then click Import at the bottom of the Edit Choices List. This opens the Import Wizard. Select CSV as the Format and the crimes2012-17.csv file as the Dataset, then click Next. Then select Attribute Values for Import From, ensure CSV is selected, and click Continue. Select TYPE for the Choice List, then click Import. A list of crime types will populate the Edit Choices List. Click Ok to save the parameter.
TypeOfCrime user parameter creation
Create a new text parameter and set the following:
| Type | Text |
| Name | ComUserName |
| Prompt | Enter your computer username: |
| Published | Yes |
| Required | Yes |
| Attribute Assignment | Off |
ComUserName user parameter creation
Create a new Password parameter and set the following:
| Type | Password |
| Name | ApiKey |
| Prompt | Stadia API Key |
| Published | Yes |
| Required | Yes |
| Attribute Assignment | Off |
API key user parameter creation
5. Add an RCaller
Now that we’ve created our two published parameters, we can add our R script. Add an RCaller to the canvas and connect it to the CSV reader.
In the parameters, change the Input Table from CSV to crime; you might have to reconnect the RCaller to the Reader.
Change the table in the RCaller from CSV to crime, then reconnect the Reader.
Now paste the following script into the R Script area:
library(ggmap)
crime <- subset(crime, TYPE == "$(TypeOfCrime)")
bounding_box <- c(bottom = 49.2,
top = 49.4,
left = -123.4,
right = -123.0)
register_stadiamaps("$(ApiKey)")
HeatMap <- get_stadiamap(bounding_box, maptype="stamen_toner", zoom=10)
ggmap(HeatMap) + geom_point(aes(x=X, y=Y), data=crime, alpha=.5, color="red", size=3, shape=".") +
stat_density2d(data=crime,
aes(x = X, y = Y, fill= ..level.., alpha= 0.5), size = 0.01,
bins = 30, geom = "polygon") + scale_fill_gradient(low = "green", high = "red") +
facet_wrap(~YEAR) +
ggtitle("$(TypeOfCrime)")
ggsave("C:/Users/$(ComUserName)/Documents/$(TypeOfCrime)From2012-2017.png")
fmeOutput<-data.frame(1)If you don't want to save to the Documents folder, change the path. Be mindful of the slash direction.
6. Run the Workspace
Now run the workspace with prompt enabled to enter your parameter values. Then open up the folder where you saved the PNG.
Final output: heatmap for Theft of Bicycle
R Script Breakdown
The following is a breakdown of the FME-specific steps for the Heatmap R Script. For a more detailed look at how to use ggmap, see the ggmap package documentation.
This subsets the crime data table by crime type.
crime <- subset(crime, TYPE == "$(TypeOfCrime)")This creates the bounding box of the area of interest in latitude/longitude, where top and bottom are latitude and right and left are longitude. You can easily turn this into a Published Parameter; see the completed workspace.
bounding_box <- c(bottom = 49.2,
top = 49.4,
left = -123.2,
right = -123.0)Sets the base map to Stadia maps; you can change the maptype to stamen_toner, stamen_terrain, or stamen_watercolor.
register_stadiamaps("$(ApiKey)")
HeatMap <- get_stadiamap(bounding_box, maptype="stamen_toner", zoom=$(Zoom))
Anywhere you see x= and y=, these values reflect the attribute names for your Latitude and Longitude columns. The data= will reflect what you named the table in the RCaller. Since we already subsetted the data, we can just call crime.
geom_point(aes(x=X, y=Y), data=crime, alpha=.5, color="red", size=3, shape=".")Delete this line if you don’t want to facet. Alternatively, you can add an additional attribute to facet by two attributes: just change the facet from wrap to grid, i.e., facet_grid(NEIGHBOURHOOD~YEAR):
facet_wrap(~YEAR)ggtitle is the title at the top of your image. You can use the user parameters or constant values to change this:
ggtitle("$(TypeOfCrime)")This line saves the map as an image. You can use a direct file path or the published parameter. You can also save the file as a PDF.
ggsave("C:/Users/$(ComUserName)/Documents/$(TypeOfCrime) From 2012-2017.png")fmeOutput is a mandatory line in the RCaller. You can change the data.frame() value to extract data. For more information on fmeOutput, see the RCaller documentation.
fmeOutput<-data.frame(1)Troubleshooting
If you get the following error message but installed ggmap through an R console, ensure the ggmap package is installed in the same location FME uses for the R Interpreter Executable. This can be found by going to Tools > FME Options > Translation, then under R Interpreter:
If you get a Google Maps 403 error, it means the base map service is currently busy; wait a minute and try re-running the workspace.
If you get any other error messages, check and ensure your code is correct. Double-check that your code works in an R Console by replacing the published parameters with actual values.
Additional Resources
[Webinar] Ins and Outs of Using R with FME
Data Attribution
The data used here originates from open data made available by the City of Vancouver, British Columbia. It contains information licensed under the Open Government License - Vancouver.