0

Here is what I'm trying to do:

  1. I have two data frames for IL (for example), each data frame has a column to indicate if the counties should be mask or not.
  2. I will mapping those two data frames, side by side using facet_wrap(), and using my own created color bar,which is from blue to red with mean set to white.
  3. For counties with mask=1, I need to mask those counties.

And my questions are:

  1. Right now I am using the grey color to mask the areas, but it is very ugly. I saw some published paper using the white background square with lines (like a shadow area) for masking. I don't know how to call that so I don't even know how to google search for that. If the legend can be used, how should I create the masking layer and put a separate legend for that other than a single color bar? The legend is like: enter image description here
  2. I created a separate data frame called df_mask, basically picking out the rows with mask=1. Then used geom_polygon to plot that data frame. Is that a way avoid doing that? Since I already have a column of mask in my data frame. For example, like a discrete fill, with 0 being transparent, and 1 being the shadow area.
  3. Right now my masking layer also mask the border between counties, that why I set alpha=0.9 so that I can kind of see the broader, however, that's too ugly... I want to mask the counties without masking the broaders.

Here is my sample code to generate my current plot:

library(RColorBrewer)
library(dplyr)
library(gridExtra)
library(ggplot2)
library(maptools)
library(ggmap)
library(RColorBrewer)
library(colorRamps)
map_il = map_data('county','illinois')
head(map_il)
#create a fake data to plot
counties = unique(map_il$subregion)
n=length(counties)
#fake data 1
df1 = data.frame(subregion=counties, value=runif(n),id=1,mask=sample(0:1,n,TRUE))
df2 = data.frame(subregion=counties, value=runif(n),id=2,mask=sample(0:1,n,TRUE))
merged_df_1 = merge(map_il,df1,sort=FALSE,by='subregion')
merged_df_1 = merged_df_1[order(merged_df_1$order),]
merged_df_2 = merge(map_il,df2,sort=FALSE,by='subregion')
merged_df_2 = merged_df_2[order(merged_df_2$order),]
#set the two df to plot, using facet_wrap and id to seperate
df = rbind(merged_df_1,merged_df_2)
dim(df)
head(df)
#Choose my own color scale, I want the color from blue to red, with white
#stands for the mean of the two plots
get_color = function(c_v){
  return(rgb(c_v[1], c_v[2], c_v[3]))
}
get_color_vector = function(z_min,z_max,z_mean,green_lim=NA){
  #nin <- 256
  nin <- 1000
  nzero <- floor(1 + nin*(z_mean - z_min)/(z_max-z_min))
  maxblue <- .7
  maxred  <- .7

  colors <- matrix(NA, nin, 3)
  colors[1:nzero,3] <- 1
  colors[1:nzero,2] <- seq(1 - maxblue, 1, length.out = nzero)
  colors[1:nzero,1] <- colors[1:nzero,2]
  ix <- (nzero+1):nin
  colors[ix, 1] <- 1
  colors[ix, 2] <- seq(1, 1 - maxred, length.out = nin - nzero)
  colors[ix, 3] <- colors[ix, 2]
  if(!is.na(green_lim)){
    colors[,2] <- seq(green_lim[1],green_lim[2], length.out = nin)
  }
  col_vector <- apply(colors, 1, get_color)
  return(col_vector)                 
}
avg = mean(c(df1$value, df2$value))
r_min = min(c(df1$value, df2$value)) 
r_max = max(c(df1$value, df2$value))
color_vector = get_color_vector(r_min, r_max, avg)
#creat another data frame to make
df_mask = df[df$mask==1,]
#make the plot
qplot(long, lat, data = df, group = group, fill = value,
                  geom = "polygon")+
    scale_fill_gradientn("",colours=color_vector,limits=c(r_min,r_max),
                         breaks=c(r_min,avg,r_max),
                         labels=c(round(r_min),"Avg",round(r_max)))+
    labs(fill='',x="",y="")+
    ggtitle('Sample plot')+
    theme_bw()+facet_wrap(~id,ncol=2)+
    geom_path( data = df , colour = "black")+
    geom_polygon(data=df_mask,fill='grey',alpha=0.9)+
    theme(plot.title = element_text(size=12),
          strip.text.x = element_text(size = 8, colour = "black", angle = 0),
          legend.text = element_text(size=6))

Sample plot: enter image description here

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jiang Du
  • 189
  • 2
  • 14

1 Answers1

1

Question 1

As far as I know, ggplot2 does not support hatching, although there may be some hacks/tricks online if you search for that.

Question 2

I would use your mask column to set value to NA where necessary. For those counties you can set a separate color, not needing the second data.frame. You can control that color with na.value inside scale_fill_gradientn, the default is dark grey.

Question 3

You should switch the order of the layers. Plot the polygons first, then plot the borders.

General tips

In general, for more complicated plots like this, I would always use ggplot instead of qplot.

You probably want to use coord_map to make sure that the aspect ratio is making sense.

Code

df$value[df$mask == 1] <- NA

ggplot(df, aes(long, lat, group = group, fill = value)) +
  geom_polygon() +
  geom_path(data = df , colour = "black") +
  scale_fill_gradientn("",
                       colours = color_vector,
                       limits = c(r_min, r_max),
                       breaks = c(r_min, avg,r_max),
                       labels = c(round(r_min), "Avg", round(r_max)),
                       na.value = 'grey80')+
  labs(x = "", y = "") +
  facet_wrap(~id, ncol = 2) +
  ggtitle('Sample plot') +
  theme_bw() +
  theme(plot.title = element_text(size = 12),
        strip.text.x = element_text(size = 8, colour = "black", angle = 0),
        legend.text = element_text(size = 6)) +
  coord_map()

Result

enter image description here

Axeman
  • 32,068
  • 8
  • 81
  • 94
  • Thank you @Axeman, it look much better and more concise now. At least I know it's called hatching, so that I can do my search. Also, do you know how to provide a legend of the 'NA' values under the color bar which having the grey color? – Jiang Du Feb 22 '16 at 18:50
  • Such a smart way doing that. Thanks!! – Jiang Du Feb 22 '16 at 19:38