Plotting bar charts on map using ggplot2?
Asked Answered
R

1

21

I would like to produce a barplot for each location on a map using ggplot2, as was done by xingmowang with base graphics and a number of packages:

http://nzprimarysectortrade.wordpress.com/2011/10/02/let-r-fly-visualizing-export-data-using-r/

enter image description here

This is related to Embedding a miniature plot within a plot.

For the moment, the best I can do is match value to point size in a jittered point plot:

require(ggplot2)
require(maps)

#Get world map info
world_map <- map_data("world")

#Creat a base plot
p <- ggplot() + coord_fixed()

#Add map to base plot
base_world <- p + geom_polygon(data=world_map,
                               aes(x=long,
                                   y=lat,
                                   group=group))


#Create example data
geo_data <- data.frame(long=c(20,20,100,100,20,20,100,100),
                       lat=c(0,0,0,0,0,0,0,0),
                       value=c(10,30,40,50,20,20,100,100),
                       Facet=rep(c("Facet_1", "Facet_2"), 4),
                       colour=rep(c("colour_1", "colour_2"), each=4))

#Creat an example plot
map_with_jitter <- base_world+geom_point(data=geo_data,
                                            aes(x=long,
                                                y=lat,
                                                colour=colour,
                                                size=value),
                                         position="jitter",
                                         alpha=I(0.5))

#Add faceting
map_with_jitter <- map_with_jitter + facet_wrap(~Facet)

map_with_jitter <- map_with_jitter + theme(legend.position="none")

print(map_with_jitter)

Example map plot with ggplot2

With an inelegant workaround:

subset_data <- geo_data[geo_data$Facet=="Facet_1" &
                          geo_data$long=="20",]
subplot <- qplot(data=subset_data,
                 x=colour,
                 y=value,
                 fill=colour,
                 geom="bar",
                 stat="identity")+theme(legend.position="none")

print(base_world)
print(subplot, vp=viewport((200+mean(subset_data$long))/400,(100+mean(subset_data$lat))/200 , .2, .2))

enter image description here

Resentful answered 16/4, 2013 at 4:12 Comment(5)
Related question: #10368680Surovy
What is the question here? What have you tried?Scone
see ?annotation_custom for an example of inset graphicInconsolable
ggsubplots?Inconsolable
You can indeed use ggsubplots to achieve this.See my answer belowGuidon
G
25

Update 2016-12-23: The ggsubplot-package is no longer actively maintained and is archived on CRAN:

Package ‘ggsubplot’ was removed from the CRAN repository.>
Formerly available versions can be obtained from the archive.>
Archived on 2016-01-11 as requested by the maintainer [email protected].

ggsubplot will not work with R versions >= 3.1.0. Install R 3.0.3 to run the code below:


You can indeed achieve this by means of the ggsubplot package like Baptiste suggests.

library(ggsubplot)
library(ggplot2)
library(maps)
library(plyr)

#Get world map info
world_map <- map_data("world")

#Create a base plot
p <- ggplot()  + geom_polygon(data=world_map,aes(x=long, y=lat,group=group))

# Calculate the mean longitude and latitude per region, these will be the coördinates where the plots will be placed, so you can tweak them where needed.
# Create simulation data of the age distribution per region and merge the two.

centres <- ddply(world_map,.(region),summarize,long=mean(long),lat=mean(lat))
mycat <- cut(runif(1000), c(0, 0.1, 0.3, 0.6, 1), labels=FALSE) 
mycat <- as.factor(mycat)
age <- factor(mycat,labels=c("<15","15-30","20-60",">60"))
simdat <- merge(centres ,age)
colnames(simdat) <- c( "region","long","lat","Age" )

# Select the countries where you want a subplot for and plot
simdat2 <- subset(simdat, region %in% c("USA","China","USSR","Brazil", "Australia"))
(testplot <- p+geom_subplot2d(aes(long, lat, subplot = geom_bar(aes(Age, ..count.., fill = Age))), bins = c(15,12), ref = NULL, width = rel(0.8), data = simdat2))

Result:enter image description here

Guidon answered 17/4, 2013 at 7:26 Comment(8)
Any way to add a y axis or at least a reference bar showing the hight of a given number of units on the y axis (ref : ref_box, ref_hline, ref_vline only allow you to specify relative to plot area not y axis units)? I guess one could add a known data point to each bin with a known value on the y axis which would then be presented in the legend. Any other solutions?Reprehension
Could someone possibly clarify how geom_bar's ..count.. argument works?Unsphere
Alternatively: simdat3 = plyr::count(simdat2, vars = c('region','long','lat','Age')) and plot with p + geom_subplot(data=simdat3, aes(long, lat, group=region, subplot = geom_bar(aes(Age, freq, fill = Age), stat="identity")),width = 10, height=20)Unsphere
The other day, I could not replicate one of the examples with ggsubplot. Today, I tried this example, but I could not replicate it. I had an error message saying Error in layout_base(data, vars, drop = drop) : At least one layer must contain all variables used for facetting. I wonder if you have the same error message. Could you test your script?Umbrian
@jazurro Still working for me. Which version of ggplot2 are you using?Guidon
I got the same error message as jazzurro. I'm running ggplot2 version 3.1.3.Garwin
I also get this error using ggplot2 version 1.01 (R version 3.1.2).Lemley
This seems to be a known issue related to the R version ( >= R 3.1.0). github.com/garrettgman/ggsubplot/issues/10Guidon

© 2022 - 2024 — McMap. All rights reserved.