This may be a wish list thing, not sure (i.e. maybe there would need to be the creation of geom_pie for this to occur). I saw a map today (LINK) with pie graphs on it as seen here.
I don't want to debate the merits of a pie graph, this was more of an exercise of can I do this in ggplot?
I have provided a data set below (loaded from my drop box) that has the mapping data to make a New York State map and some purely fabricated data on racial percentages by county. I have given this racial make up as a merge with the main data set and as a separate data set called key. I also think Bryan Goodrich's response to me in another post (HERE) on centering county names will be helpful to this concept.
How can we make the map above with ggplot2?
A data set and the map without the pie graphs:
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
head(ny); head(key) #view the data set from my drop box
library(ggplot2)
ggplot(ny, aes(long, lat, group=group)) + geom_polygon(colour='black', fill=NA)
# Now how can we plot a pie chart of race on each county
# (sizing of the pie would also be controllable via a size
# parameter like other `geom_` functions).
Thanks in advance for your ideas.
EDIT: I just saw another case at junkcharts that screams for this type of capability:
Three years later this is solved. I've put together a number of processes together and thanks to #Guangchuang Yu's excellent ggtree package this can be done fairly easily. Note that as of (9/3/2015) you need to have version 1.0.18 of ggtree installed but these will eventually trickle down to their respective repositories.
I've used the following resources to make this (the links will give greater detail):
ggtree blog
move ggplot legend
correct ggtree version
centering things in polygons
Here's the code:
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
head(ny); head(key) #view the data set from my drop box
if (!require("pacman")) install.packages("pacman")
p_load(ggplot2, ggtree, dplyr, tidyr, sp, maps, pipeR, grid, XML, gtable)
getLabelPoint <- function(county) {Polygon(county[c('long', 'lat')])#labpt}
df <- map_data('county', 'new york') # NY region county data
centroids <- by(df, df$subregion, getLabelPoint) # Returns list
centroids <- do.call("rbind.data.frame", centroids) # Convert to Data Frame
names(centroids) <- c('long', 'lat') # Appropriate Header
pops <- "http://data.newsday.com/long-island/data/census/county-population-estimates-2012/" %>%
readHTMLTable(which=1) %>%
tbl_df() %>%
select(1:2) %>%
setNames(c("region", "population")) %>%
mutate(
population = {as.numeric(gsub("\\D", "", population))},
region = tolower(gsub("\\s+[Cc]ounty|\\.", "", region)),
#weight = ((1 - (1/(1 + exp(population/sum(population)))))/11)
weight = exp(population/sum(population)),
weight = sqrt(weight/sum(weight))/3
)
race_data_long <- add_rownames(centroids, "region") %>>%
left_join({distinct(select(ny, region:other))}) %>>%
left_join(pops) %>>%
(~ race_data) %>>%
gather(race, prop, white:other) %>%
split(., .$region)
pies <- setNames(lapply(1:length(race_data_long), function(i){
ggplot(race_data_long[[i]], aes(x=1, prop, fill=race)) +
geom_bar(stat="identity", width=1) +
coord_polar(theta="y") +
theme_tree() +
xlab(NULL) +
ylab(NULL) +
theme_transparent() +
theme(plot.margin=unit(c(0,0,0,0),"mm"))
}), names(race_data_long))
e1 <- ggplot(race_data_long[[1]], aes(x=1, prop, fill=race)) +
geom_bar(stat="identity", width=1) +
coord_polar(theta="y")
leg1 <- gtable_filter(ggplot_gtable(ggplot_build(e1)), "guide-box")
p <- ggplot(ny, aes(long, lat, group=group)) +
geom_polygon(colour='black', fill=NA) +
theme_bw() +
annotation_custom(grob = leg1, xmin = -77.5, xmax = -78.5, ymin = 44, ymax = 45)
n <- length(pies)
for (i in 1:n) {
nms <- names(pies)[i]
dat <- race_data[which(race_data$region == nms)[1], ]
p <- subview(p, pies[[i]], x=unlist(dat[["long"]])[1], y=unlist(dat[["lat"]])[1], dat[["weight"]], dat[["weight"]])
}
print(p)
This functionality should be in ggplot, I think it is coming to ggplot soonish, but it is currently available in base plots. I thought I would post this just for comparison's sake.
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
library(plotrix)
e=10^-5
myglyff=function(gi) {
floating.pie(mean(gi$long),
mean(gi$lat),
x=c(gi[1,"white"]+e,
gi[1,"black"]+e,
gi[1,"hispanic"]+e,
gi[1,"asian"]+e,
gi[1,"other"]+e),
radius=.1) #insert size variable here
}
g1=ny[which(ny$group==1),]
plot(g1$long,
g1$lat,
type='l',
xlim=c(-80,-71.5),
ylim=c(40.5,45.1))
myglyff(g1)
for(i in 2:62)
{gi=ny[which(ny$group==i),]
lines(gi$long,gi$lat)
myglyff(gi)
}
Also, there may be (probably are) more elegant ways of doing this in the base graphics.
As, you can see, there are quite a few problems with this that need to be solved. A fill color for the counties. The pie charts tend to be too small or overlap. The lat and long do not take a projection so sizes of counties are distorted.
In any event, I am interested in what others can come up with.
I've written some code to do this using grid graphics. There is an example here: https://qdrsite.wordpress.com/2016/06/26/pies-on-a-map/
The goal here was to associate the pie charts with specific points on the map, and not necessarily regions. For this particular solution, it is necessary to convert the map coordinates (latitude and longitude) to a (0,1) scale so they can be plotted in the proper locations on the map. The grid package is used to print to the viewport that contains the plot panel.
Code:
# Pies On A Map
# Demonstration script
# By QDR
# Uses NLCD land cover data for different sites in the National Ecological Observatory Network.
# Each site consists of a number of different plots, and each plot has its own land cover classification.
# On a US map, plot a pie chart at the location of each site with the proportion of plots at that site within each land cover class.
# For this demo script, I've hard coded in the color scale, and included the data as a CSV linked from dropbox.
# Custom color scale (taken from the official NLCD legend)
nlcdcolors <- structure(c("#7F7F7F", "#FFB3CC", "#00B200", "#00FFFF", "#006600", "#E5CC99", "#00B2B2", "#FFFF00", "#B2B200", "#80FFCC"), .Names = c("unknown", "cultivatedCrops", "deciduousForest", "emergentHerbaceousWetlands", "evergreenForest", "grasslandHerbaceous", "mixedForest", "pastureHay", "shrubScrub", "woodyWetlands"))
# NLCD data for the NEON plots
nlcdtable_long <- read.csv(file='https://www.dropbox.com/s/x95p4dvoegfspax/demo_nlcdneon.csv?raw=1', row.names=NULL, stringsAsFactors=FALSE)
library(ggplot2)
library(plyr)
library(grid)
# Create a blank state map. The geom_tile() is included because it allows a legend for all the pie charts to be printed, although it does not
statemap <- ggplot(nlcdtable_long, aes(decimalLongitude,decimalLatitude,fill=nlcdClass)) +
geom_tile() +
borders('state', fill='beige') + coord_map() +
scale_x_continuous(limits=c(-125,-65), expand=c(0,0), name = 'Longitude') +
scale_y_continuous(limits=c(25, 50), expand=c(0,0), name = 'Latitude') +
scale_fill_manual(values = nlcdcolors, name = 'NLCD Classification')
# Create a list of ggplot objects. Each one is the pie chart for each site with all labels removed.
pies <- dlply(nlcdtable_long, .(siteID), function(z)
ggplot(z, aes(x=factor(1), y=prop_plots, fill=nlcdClass)) +
geom_bar(stat='identity', width=1) +
coord_polar(theta='y') +
scale_fill_manual(values = nlcdcolors) +
theme(axis.line=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.position="none",
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
plot.background=element_blank()))
# Use the latitude and longitude maxima and minima from the map to calculate the coordinates of each site location on a scale of 0 to 1, within the map panel.
piecoords <- ddply(nlcdtable_long, .(siteID), function(x) with(x, data.frame(
siteID = siteID[1],
x = (decimalLongitude[1]+125)/60,
y = (decimalLatitude[1]-25)/25
)))
# Print the state map.
statemap
# Use a function from the grid package to move into the viewport that contains the plot panel, so that we can plot the individual pies in their correct locations on the map.
downViewport('panel.3-4-3-4')
# Here is the fun part: loop through the pies list. At each iteration, print the ggplot object at the correct location on the viewport. The y coordinate is shifted by half the height of the pie (set at 10% of the height of the map) so that the pie will be centered at the correct coordinate.
for (i in 1:length(pies))
print(pies[[i]], vp=dataViewport(xData=c(-125,-65), yData=c(25,50), clip='off',xscale = c(-125,-65), yscale=c(25,50), x=piecoords$x[i], y=piecoords$y[i]-.06, height=.12, width=.12))
The result looks like this:
I stumbled upon what looks like a function to do this: "add.pie" in the "mapplots" package.
The example from the package is below.
plot(NA,NA, xlim=c(-1,1), ylim=c(-1,1) )
add.pie(z=rpois(6,10), x=-0.5, y=0.5, radius=0.5)
add.pie(z=rpois(4,10), x=0.5, y=-0.5, radius=0.3)
A slight variation on the OP's original requirements, but this seems like an appropriate answer/update.
If you want an interactive Google Map, as of googleway v2.6.0 you can add charts inside info_windows of map layers.
see ?googleway::google_charts for documentation and examples
library(googleway)
set_key("GOOGLE_MAP_KEY")
## create some dummy chart data
markerCharts <- data.frame(stop_id = rep(tram_stops$stop_id, each = 3))
markerCharts$variable <- c("yes", "no", "maybe")
markerCharts$value <- sample(1:10, size = nrow(markerCharts), replace = T)
chartList <- list(
data = markerCharts
, type = 'pie'
, options = list(
title = "my pie"
, is3D = TRUE
, height = 240
, width = 240
, colors = c('#440154', '#21908C', '#FDE725')
)
)
google_map() %>%
add_markers(
data = tram_stops
, id = "stop_id"
, info_window = chartList
)
Related
This may be a wish list thing, not sure (i.e. maybe there would need to be the creation of geom_pie for this to occur). I saw a map today (LINK) with pie graphs on it as seen here.
I don't want to debate the merits of a pie graph, this was more of an exercise of can I do this in ggplot?
I have provided a data set below (loaded from my drop box) that has the mapping data to make a New York State map and some purely fabricated data on racial percentages by county. I have given this racial make up as a merge with the main data set and as a separate data set called key. I also think Bryan Goodrich's response to me in another post (HERE) on centering county names will be helpful to this concept.
How can we make the map above with ggplot2?
A data set and the map without the pie graphs:
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
head(ny); head(key) #view the data set from my drop box
library(ggplot2)
ggplot(ny, aes(long, lat, group=group)) + geom_polygon(colour='black', fill=NA)
# Now how can we plot a pie chart of race on each county
# (sizing of the pie would also be controllable via a size
# parameter like other `geom_` functions).
Thanks in advance for your ideas.
EDIT: I just saw another case at junkcharts that screams for this type of capability:
Three years later this is solved. I've put together a number of processes together and thanks to #Guangchuang Yu's excellent ggtree package this can be done fairly easily. Note that as of (9/3/2015) you need to have version 1.0.18 of ggtree installed but these will eventually trickle down to their respective repositories.
I've used the following resources to make this (the links will give greater detail):
ggtree blog
move ggplot legend
correct ggtree version
centering things in polygons
Here's the code:
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
head(ny); head(key) #view the data set from my drop box
if (!require("pacman")) install.packages("pacman")
p_load(ggplot2, ggtree, dplyr, tidyr, sp, maps, pipeR, grid, XML, gtable)
getLabelPoint <- function(county) {Polygon(county[c('long', 'lat')])#labpt}
df <- map_data('county', 'new york') # NY region county data
centroids <- by(df, df$subregion, getLabelPoint) # Returns list
centroids <- do.call("rbind.data.frame", centroids) # Convert to Data Frame
names(centroids) <- c('long', 'lat') # Appropriate Header
pops <- "http://data.newsday.com/long-island/data/census/county-population-estimates-2012/" %>%
readHTMLTable(which=1) %>%
tbl_df() %>%
select(1:2) %>%
setNames(c("region", "population")) %>%
mutate(
population = {as.numeric(gsub("\\D", "", population))},
region = tolower(gsub("\\s+[Cc]ounty|\\.", "", region)),
#weight = ((1 - (1/(1 + exp(population/sum(population)))))/11)
weight = exp(population/sum(population)),
weight = sqrt(weight/sum(weight))/3
)
race_data_long <- add_rownames(centroids, "region") %>>%
left_join({distinct(select(ny, region:other))}) %>>%
left_join(pops) %>>%
(~ race_data) %>>%
gather(race, prop, white:other) %>%
split(., .$region)
pies <- setNames(lapply(1:length(race_data_long), function(i){
ggplot(race_data_long[[i]], aes(x=1, prop, fill=race)) +
geom_bar(stat="identity", width=1) +
coord_polar(theta="y") +
theme_tree() +
xlab(NULL) +
ylab(NULL) +
theme_transparent() +
theme(plot.margin=unit(c(0,0,0,0),"mm"))
}), names(race_data_long))
e1 <- ggplot(race_data_long[[1]], aes(x=1, prop, fill=race)) +
geom_bar(stat="identity", width=1) +
coord_polar(theta="y")
leg1 <- gtable_filter(ggplot_gtable(ggplot_build(e1)), "guide-box")
p <- ggplot(ny, aes(long, lat, group=group)) +
geom_polygon(colour='black', fill=NA) +
theme_bw() +
annotation_custom(grob = leg1, xmin = -77.5, xmax = -78.5, ymin = 44, ymax = 45)
n <- length(pies)
for (i in 1:n) {
nms <- names(pies)[i]
dat <- race_data[which(race_data$region == nms)[1], ]
p <- subview(p, pies[[i]], x=unlist(dat[["long"]])[1], y=unlist(dat[["lat"]])[1], dat[["weight"]], dat[["weight"]])
}
print(p)
This functionality should be in ggplot, I think it is coming to ggplot soonish, but it is currently available in base plots. I thought I would post this just for comparison's sake.
load(url("http://dl.dropbox.com/u/61803503/nycounty.RData"))
library(plotrix)
e=10^-5
myglyff=function(gi) {
floating.pie(mean(gi$long),
mean(gi$lat),
x=c(gi[1,"white"]+e,
gi[1,"black"]+e,
gi[1,"hispanic"]+e,
gi[1,"asian"]+e,
gi[1,"other"]+e),
radius=.1) #insert size variable here
}
g1=ny[which(ny$group==1),]
plot(g1$long,
g1$lat,
type='l',
xlim=c(-80,-71.5),
ylim=c(40.5,45.1))
myglyff(g1)
for(i in 2:62)
{gi=ny[which(ny$group==i),]
lines(gi$long,gi$lat)
myglyff(gi)
}
Also, there may be (probably are) more elegant ways of doing this in the base graphics.
As, you can see, there are quite a few problems with this that need to be solved. A fill color for the counties. The pie charts tend to be too small or overlap. The lat and long do not take a projection so sizes of counties are distorted.
In any event, I am interested in what others can come up with.
I've written some code to do this using grid graphics. There is an example here: https://qdrsite.wordpress.com/2016/06/26/pies-on-a-map/
The goal here was to associate the pie charts with specific points on the map, and not necessarily regions. For this particular solution, it is necessary to convert the map coordinates (latitude and longitude) to a (0,1) scale so they can be plotted in the proper locations on the map. The grid package is used to print to the viewport that contains the plot panel.
Code:
# Pies On A Map
# Demonstration script
# By QDR
# Uses NLCD land cover data for different sites in the National Ecological Observatory Network.
# Each site consists of a number of different plots, and each plot has its own land cover classification.
# On a US map, plot a pie chart at the location of each site with the proportion of plots at that site within each land cover class.
# For this demo script, I've hard coded in the color scale, and included the data as a CSV linked from dropbox.
# Custom color scale (taken from the official NLCD legend)
nlcdcolors <- structure(c("#7F7F7F", "#FFB3CC", "#00B200", "#00FFFF", "#006600", "#E5CC99", "#00B2B2", "#FFFF00", "#B2B200", "#80FFCC"), .Names = c("unknown", "cultivatedCrops", "deciduousForest", "emergentHerbaceousWetlands", "evergreenForest", "grasslandHerbaceous", "mixedForest", "pastureHay", "shrubScrub", "woodyWetlands"))
# NLCD data for the NEON plots
nlcdtable_long <- read.csv(file='https://www.dropbox.com/s/x95p4dvoegfspax/demo_nlcdneon.csv?raw=1', row.names=NULL, stringsAsFactors=FALSE)
library(ggplot2)
library(plyr)
library(grid)
# Create a blank state map. The geom_tile() is included because it allows a legend for all the pie charts to be printed, although it does not
statemap <- ggplot(nlcdtable_long, aes(decimalLongitude,decimalLatitude,fill=nlcdClass)) +
geom_tile() +
borders('state', fill='beige') + coord_map() +
scale_x_continuous(limits=c(-125,-65), expand=c(0,0), name = 'Longitude') +
scale_y_continuous(limits=c(25, 50), expand=c(0,0), name = 'Latitude') +
scale_fill_manual(values = nlcdcolors, name = 'NLCD Classification')
# Create a list of ggplot objects. Each one is the pie chart for each site with all labels removed.
pies <- dlply(nlcdtable_long, .(siteID), function(z)
ggplot(z, aes(x=factor(1), y=prop_plots, fill=nlcdClass)) +
geom_bar(stat='identity', width=1) +
coord_polar(theta='y') +
scale_fill_manual(values = nlcdcolors) +
theme(axis.line=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.position="none",
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
plot.background=element_blank()))
# Use the latitude and longitude maxima and minima from the map to calculate the coordinates of each site location on a scale of 0 to 1, within the map panel.
piecoords <- ddply(nlcdtable_long, .(siteID), function(x) with(x, data.frame(
siteID = siteID[1],
x = (decimalLongitude[1]+125)/60,
y = (decimalLatitude[1]-25)/25
)))
# Print the state map.
statemap
# Use a function from the grid package to move into the viewport that contains the plot panel, so that we can plot the individual pies in their correct locations on the map.
downViewport('panel.3-4-3-4')
# Here is the fun part: loop through the pies list. At each iteration, print the ggplot object at the correct location on the viewport. The y coordinate is shifted by half the height of the pie (set at 10% of the height of the map) so that the pie will be centered at the correct coordinate.
for (i in 1:length(pies))
print(pies[[i]], vp=dataViewport(xData=c(-125,-65), yData=c(25,50), clip='off',xscale = c(-125,-65), yscale=c(25,50), x=piecoords$x[i], y=piecoords$y[i]-.06, height=.12, width=.12))
The result looks like this:
I stumbled upon what looks like a function to do this: "add.pie" in the "mapplots" package.
The example from the package is below.
plot(NA,NA, xlim=c(-1,1), ylim=c(-1,1) )
add.pie(z=rpois(6,10), x=-0.5, y=0.5, radius=0.5)
add.pie(z=rpois(4,10), x=0.5, y=-0.5, radius=0.3)
A slight variation on the OP's original requirements, but this seems like an appropriate answer/update.
If you want an interactive Google Map, as of googleway v2.6.0 you can add charts inside info_windows of map layers.
see ?googleway::google_charts for documentation and examples
library(googleway)
set_key("GOOGLE_MAP_KEY")
## create some dummy chart data
markerCharts <- data.frame(stop_id = rep(tram_stops$stop_id, each = 3))
markerCharts$variable <- c("yes", "no", "maybe")
markerCharts$value <- sample(1:10, size = nrow(markerCharts), replace = T)
chartList <- list(
data = markerCharts
, type = 'pie'
, options = list(
title = "my pie"
, is3D = TRUE
, height = 240
, width = 240
, colors = c('#440154', '#21908C', '#FDE725')
)
)
google_map() %>%
add_markers(
data = tram_stops
, id = "stop_id"
, info_window = chartList
)
I want to plot the (spatial) correlation pattern between two variables and overlapped by countries borders. I use borders() function with ggplot but the xlim and ylim didn't give the exact limit I expect, instead, they give all the country. I want to have the exact limits to overlap the data.
library(ncdf4)
library(ggplot2)
library(reshape)
library(maps)
library(stringr)
library(reshape2)
library(mapdata)
library(maptools)
ncfile <- nc_open("/Volumes/KIT/CHIRPS/index/correlation/correlation.amm.allindex.nc")
lon <- ncvar_get(ncfile, "lon")
lat <- ncvar_get(ncfile, "lat")
pr <- ncvar_get(ncfile, "prptotcorrel")
ret <- list ("lat"=lat, "lon"=lon,"pr"= pr)
##
str(ret)
######## melt function for pr
melt_pr <- function(L) {
dimnames(L$pr) <- list(lon = L$lon, lat = L$lat)
rett <- melt(L$pr, value.name ="pr")
}
######
mpr <- melt_pr(ret)
head(mpr)
#
xlims=range(mpr$lon); xlims
ylims=range(mpr$lat); ylims
gcorrelation=ggplot(data = mpr, aes(x = lon, y = lat, fill = pr)) +
geom_tile() +
borders('world', xlim=xlims, ylim=ylims, colour='black', size=.2) +
coord_fixed(xlim=xlims, ylim=ylims) +
labs(x = "Longitude", y = "Latitude") +
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-1,1), na.value = NA, name="correlation") +
theme_bw() +
coord_fixed(1.3)
gcorrelation
I expect to have country borders that fit exactly the data.
Here is what I'd like the plot to look like. Here is the image with the countries; I want just to overlap with the exact limit of shaded data.
Welcome to stack overflow. Without having a sample of your data (as code), it will be hard to help. I believe that coord_cartesian() will do what you want instead of coord_fixed()
Instead of coord_fixed() or coord_cartesian(), use the xlim and ylim parameters of coord_map().
coord_map() projects a portion of the earth, which is approximately spherical, onto a flat 2D plane using any projection defined by the mapproj package.
(As #yake84 suggested, it would be best to present a simplified version of your problem that contains code and data so people can run and test their solutions.)
Taking a step back, if you are developing fresh code, I'd avoid outdated packages like reshape, reshape2, and some of the spatial functions. Instead build on their replacements (often developed by the same people) such as tidyr, sf, and the associated functions in ggplot2, such as ggsf().
Hi #yake84 and #wibeasley, sorry I'm pretty new on Stack overflow, thanks for your suggestions, coord_map() gave the right expected map. Thanks also for the packages suggestion.
I'd like to create a plot similar to this, where each point represents a unique data point of a specific type (eg. red group or blue group), and the points of each group form a circular shape.
I have so far gotten this far, using the packcircles function in R:
How do I "group" the different colours together? Since I am using the packcircle function, the circle is drawn from the center and then spirals outward, so ordering the points does group them, but I'd rather something more similar to the example I provided above.
Here is the code I used to generate the plot
library(packcircles)
library(ggplot2)
library(plyr)
library(dplyr)
Sample data
data <- data.frame(group=paste("Group", letters[1:4]), value=rep(1,100))
data <- data[order(data$group), ]
Generate layout using packcircles function in R
packing <- circleProgressiveLayout(data$value, sizetype = "area")
id <- data$group
packing <- cbind(id,packing)
dat.gg <- circleLayoutVertices(packing, idcol=1, xysizecols=2:4, npoints=1)
Make the plot using ggplot2
ggplot() +
geom_point(data = dat.gg, aes(x,y, colour=factor(id))) +
theme_minimal() +
theme(legend.position="none",
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
axis.text=element_blank())
Thanks in advance.
I think the way to do it is actually to order your packing along the axis you want before binding it with your data. Doing the same as you but ordering packing along x:
packing <- circleProgressiveLayout(data$value, sizetype = "area")
packing <- packing[order(packing$x),]
id <- data$group
packing <- cbind(id,packing)
dat.gg <- circleLayoutVertices(packing, idcol=1, xysizecols=2:4, npoints=1)
I obtain this
The initial ordering of packing is with increasing x^2 + y^2, that is distance from the center of your circle. When you bind it you distribute your groups along this ordering of coordinates, that are concentric circles. By changing the ordering you change your distribution on the circle.
You can of course pack along y, or even you could think of packing along the angle, by calculating it with atan2 function and ordering along the angle before binding:
packing <- circleProgressiveLayout(data$value, sizetype = "area")
packing$theta <- atan2(packing$y,packing$x)
packing <- packing[order(packing$theta),]
id <- data$group
packing <- cbind(id,packing)
dat.gg <- circleLayoutVertices(packing, idcol=1, xysizecols=2:4, npoints=1)
ggplot() +
geom_point(data = dat.gg, aes(x,y, colour=factor(id))) +
theme_minimal() +
theme(legend.position="none",
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
axis.text=element_blank())
I'm working to produce a facet/lattice plot of choropleth maps that each show a how different model runs affect one variable being mapped across a number of polygons. The problem is that the output graphic produces strange lines that run between the polygons in each plot (see the graphic below).
While I've manipulated and converted the shapefile into a data frame with appropriate attributes for ggplot2, I'm not familiar with the details of how to use the package and the online documentation is limited for such a complex package. I'm not sure what parameter is causing this issue, but I suspect it may be the aes parameter.
The script:
library(rgdal, tidyr, maptools, ggplot2, dplyr, reshape2)
setwd('D:/path/to/wd')
waterloo <- read.table("waterloo-data.txt", header=TRUE, sep=',', stringsAsFactors=FALSE)
waterloo <- data.frame(waterloo$DAUID, waterloo$LA0km, waterloo$LA4_exp, waterloo$LA20km, waterloo$LA30km, waterloo$LA40km, waterloo$LA50km)
colnames(waterloo) <- c("DAUID", "LA0km", "LA10km","LA20km", "LA30km", "LA40km", "LA50km")
## Produces expenditure measurements by ID variable DAUID, using reshape2/melt
wtidy <- melt(waterloo, id.vars=c("DAUID"), measure.vars = c("LA0km", "LA10km", "LA20km", "LA30km", "LA40km", "LA50km"))
colnames(wtidy) <- c("DAUID", "BufferSize", "Expenditure")
wtidy$DAUID <- as.factor(wtidy$DAUID) # for subsequent join with wtrl_f
### READ SPATIAL DATA ###
#wtrl <- readOGR(".", "Waterloo_DA_2011_new")
wtrl <- readShapeSpatial("Waterloo_DA_2011_new")
wtrl$id <- row.names(wtrl)
wtrl_f <- fortify(wtrl)
wtrl_f <- left_join(wtrl_f, wtrl#data, by="id")
# Join wtrl fortified (wtrl_f) to either twaterloo or wtidy
wtrl_f <- left_join(wtrl_f, wtidy, by="DAUID")
### PLOT SPATIAL DATA ###
ggplot(data = wtrl_f, # the input data
aes(x = long.x, y = lat.x, fill = Variable/1000, group = BufferSize)) + # define variables
geom_polygon() + # plot the DAs
geom_path(colour="black", lwd=0.05) + # polygon borders
coord_equal() + # fixed x and y scales
facet_wrap(~ BufferSize, ncol = 2) + # one plot per buffer size
scale_fill_gradient2(low = "green", mid = "grey", high = "red", # colors
midpoint = 10000, name = "Variable\n(thousands)") + # legend options
theme(axis.text = element_blank(), # change the theme options
axis.title = element_blank(), # remove axis titles
axis.ticks = element_blank()) # remove axis ticks
The output graphic appears as follows:
Strange! I've made good progress but I don't know where ggplot is getting these lines. Any help on this would be appreciated!
PS; as an additional unrelated question, the polygon lines are rather jagged. How would I smooth these lines?
This answer helped me to solve my problem, but not before I made up this minimal example ready to post. I'm sharing it here in case it helps someone solve the same problem faster.
Problem:
I'm trying to make a basic map in R with ggplot2. The polygons are filling wrong, making extra lines.
library("ggplot2")
library("maps")
map <- ggplot(map_data("world", region = "UK"), aes(x = long, y = lat)) + geom_polygon()
map
wrong map image
Solution:
I have to set the aesthetic "group" parameter to put the polygon points in the right order, otherwise ggplot will try to plot a patch of Scotland coastline in the middle of the south coast (for example).
map <- ggplot(map_data("world", region = "UK"), aes(x = long, y = lat, group = group)) + geom_polygon()
map
OK, I managed to resolve this issue by changing the aesthetic group parameter found on page 11 of the ggplot2 manual:
http://cran.r-project.org/web/packages/ggplot2/ggplot2.pdf
The correct parameter is "group" and not the factor that is used to group the plots. The correct ggplot code:
ggplot(data = wtrl_f, # the input data
aes(x = long.x, y = lat.x, fill = Expenditure/1000, group = group)) + # define variables
geom_polygon() + # plot the DAs
geom_path(colour="black", lwd=0.025) + # DA borders
coord_equal() + # fixed x and y scales
facet_wrap(~ BufferSize, ncol = 2) + # one plot per buffer size
scale_fill_gradient2(low = "green", mid = "grey", high = "red", # colors
midpoint = 10000, name = "Expenditures\n(thousands)") + # legend options
theme(axis.text = element_blank(), # change the theme options
axis.title = element_blank(), # remove axis titles
axis.ticks = element_blank()) # remove axis ticks
i want to create a map of the US in R with the states color coded in a heat map type of way based on a metric. I know how to do this using the googleVis api but i can't use the code and without the rollovers it's not that great. what is the quickest way to get this done? i'm familiar with the maps package but i can't get the colors to cooperate. i believe this is called a choropleth map.
There is a complete example in the ggplot2 package, see ?map_data.
library(ggplot2)
example(map_data)
(hopefully answer may still be helpful for somebody)
RevolutionAnalytics has excellent example of map visualization using spplot() function. Here's image from there:
There is a population-driven cloropleth example in the UScensus2000tract package.
Code
# Transform dataset to correct format
crimes <- data.frame(state = tolower(row.names(USArrests)), USArrests)
crimes
# Map data
# install.packages("maps") remember to install these two packages if you
# install.packages("mapproj") do not have them yet
library(mapproj)
library(maps)
states_map <- map_data("state")
states_map
# Merge datasets together
crime_map <- merge(states_map, crimes, by.x = "region", by.y = "state")
# After merging, the order has changed, which leads to polygons drawn
# in the incorrect order. Let's sort it
crime_map
library(dplyr) # for arrange() function
# Sort by group, then order
crime_map <- arrange(crime_map, group, order)
crime_map
# Now data can be plotted
library(ggplot2)
plot1 <- ggplot(crime_map, aes(x = long, y = lat, group = group, fill = Assault)) +
geom_polygon(colour = "black") +
coord_map("polyconic")
plot1
# Add title
plot1 <- plot1 +
ggtitle(" Proportion of crimes in the USA")
plot1
# Improve on colours
plot1 <- plot1 +
scale_fill_gradient2(low = "#559999", mid = "grey", high = "#BB650B",
midpoint = median(crimes$Assault))
plot1
# If you want white transparent backgroud only
plot1 <- plot1 +
theme_void()
plot1
# Note: if RStudio gives you this error when ploducing plot, then use this and try
# again
devAskNewPage(ask = FALSE)
# Special thanks to Winston Chang and other ggplot developers at RStudio who made made
# many of these codes