A bubble map
uses circles of different size to represent a numeric value on a territory. It displays one bubble per geographic coordinate, or one bubble per region (in this case the bubble is usually displayed in the baricentre of the region).
Here is an example showing the geographic position of about 200k tweets containing the hashtags #surf, #windsurf or #kitesurf. See more about this project here.
# Libraries
library(tidyverse)
library(viridis)
library(hrbrthemes)
library(mapdata)
# Load dataset from github
data <- read.table("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/17_ListGPSCoordinates.csv", sep=",", header=T)
# Get the world polygon
world <- map_data("world")
# Reformat data: I count the occurence of each unique position
p <- data %>%
mutate(homelat=round(homelat,1)) %>%
mutate(homelon=round(homelon,1)) %>%
#head(1000) %>%
group_by(homelat, homelon, homecontinent) %>%
summarise(n=n()) %>%
ggplot() +
geom_polygon(data = world, aes(x=long, y = lat, group = group), fill="grey", alpha=0.1) +
geom_point(aes(x=homelon, y=homelat, color=homecontinent, size=n), alpha=0.5) +
scale_color_viridis(discrete=TRUE, guide=FALSE) +
scale_size_continuous(range=c(0.2,68)) +
coord_equal() +
theme_void() +
theme(
panel.spacing=unit(c(0,0,0,0), "null"),
plot.margin=grid::unit(c(0,0,0,0), "cm"),
legend.position=c(0.15,0.07),
legend.direction="horizontal"
) +
ggplot2::annotate("text", x = -165, y = -30, hjust = 0, size = 11, label = paste("Where surfers live."), color = "Black") +
ggplot2::annotate("text", x = -165, y = -36, hjust = 0, size = 8, label = paste("data-to-viz.com | 200,000 #surf tweets recovered"), color = "black", alpha = 0.5) +
xlim(-180,180) +
ylim(-60,80) +
scale_x_continuous(expand = c(0.006, 0.006)) +
coord_equal()
# Save at PNG
ggsave("IMG/Surfer_bubble.png", width = 36, height = 15.22, units = "in", dpi = 90)
Bubble maps are used with two types of dataset:
a list of geographic coordinates (longitude and latitude) and a numeric variable controling the size of the bubble. In the previous example, the number of tweet at each unique pair of coordinate was used.
a list of regions with attributed values and knwon boundary. In this case, the bubble map will replace the usual choropleth map. Note that it allows to avoid the bias caused by different regional area in choropleth maps. (big regions tend to have more weight during the observation).
Interactivity is appreciated for bubble maps. It allows to zoom on a specific part, or click bubbles for more information. Here is an example showing a feaw earthquacke that happend in the Fiji Region since 1964 (data)
# Library
library(leaflet)
# load example data (Fiji Earthquakes) + keep only 100 first lines
data(quakes)
quakes = head(quakes, 100)
# Create a color palette with handmade bins.
mybins=seq(4, 6.5, by=0.5)
mypalette = colorBin( palette="YlOrBr", domain=quakes$mag, na.color="transparent", bins=mybins)
# Prepare the text for the tooltip:
mytext=paste("Depth: ", quakes$depth, "<br/>", "Stations: ", quakes$stations, "<br/>", "Magnitude: ", quakes$mag, sep="") %>%
lapply(htmltools::HTML)
# Final Map
leaflet(quakes) %>%
addTiles() %>%
setView( lat=-27, lng=170 , zoom=4) %>%
addProviderTiles("Esri.WorldImagery") %>%
addCircles(~long, ~lat,
fillColor = ~mypalette(mag), fillOpacity = 0.7, color="white", radius=~sqrt(depth)*3000, stroke=FALSE, weight = 1,
label = mytext,
labelOptions = labelOptions( style = list("font-weight" = "normal", padding = "3px 8px"), textsize = "13px", direction = "auto")
) %>%
addLegend( pal=mypalette, values=~mag, opacity=0.9, title = "Magnitude", position = "bottomright" )
As for bubble charts, the size of bubbles must be mapped to its area, not to its radius. If not it exagerates differences. See more.
Mind overplotting. In any case, it is a good practice to set up a bit of transparency for each bubble, allowing to see the map behind it.
Don’t forget your legend to make the link between bubble size and numeric value.
The R and Python graph galleries are 2 websites providing hundreds of chart example, always providing the reproducible code. Click the button below to see how to build the chart you need with your favorite programing language.
R graph gallery Python gallery
Any thoughts on this? Found any mistake? Disagree? Please drop me a word on twitter or in the comment section below:
A work by Yan Holtz for data-to-viz.com