Related
I am trying to highlight single 1x1 degree grid squares on a map.
It works highlighting individual grid squares for the first 1 squares but after highlight the 4th square it begins to highlight multiple groups of squares and I am not sure why?
library(ggOceanMaps)
#devtools::install_github("MikkoVihtakari/ggOceanMapsData")
library(ggOceanMapsData)
dt <- data.frame(lon = c(35, 35, 60, 60), lat = c(-25, -25, -40, -40))
grid_2019_1 <- data.frame(lat=c(-28, -29), long=c(51, 52))
grid_2019_2 <- data.frame(lat=c(-28, -29), long=c(52, 53))
grid_2019_3 <- data.frame(lat=c(-28, -29), long=c(53, 54))
grid_2019_4 <- data.frame(lat=c(-30, -31), long=c(41, 42))
grid_2019_5 <- data.frame(lat=c(-30, -31), long=c(42, 43))
P4 = basemap(data = dt,bathymetry = T,
lon.interval = 1,
lat.interval = 1,
bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1)
P4.1 = P4 + stat_density2d(data = grid_2019_1, aes(x = long, y = lat, fill = ..density..),
geom = 'tile', contour = F)
P4.2 = P4.1 + stat_density2d(data = grid_2019_2, aes(x = long, y = lat, fill = ..density..),
geom = 'tile', contour = F)
P4.3 = P4.2 + stat_density2d(data = grid_2019_3, aes(x = long, y = lat, fill = ..density..),
geom = 'tile', contour = F)
P4.4 = P4.3 + stat_density2d(data = grid_2019_4, aes(x = long, y = lat, fill = ..density..),
geom = 'tile', contour = F)
P4.5 = P4.4 + stat_density2d(data = grid_2019_5, aes(x = long, y = lat, fill = ..density..),
geom = 'tile', contour = F)
Fixed using geom_tile
P4 = basemap(data = dt,bathymetry = T,
lon.interval = 1,
lat.interval = 1,
bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1)
grid_2019_1 <- data.frame(lat=c(-28.5), long=c(51.5))
grid_2019_8 <- data.frame(lat=c(-31.5), long=c(42.5))
P4.1 = P4 + geom_tile(data = grid_2019_8, aes(x= long, y = lat, fill= 'red' ))
P4.1
P4.8 = P4 + geom_tile(data = grid_2019_8, aes(x= long, y = lat, fill= 'red' ))
P4.8
This question already has answers here:
Create discrete color bar with varying interval widths and no spacing between legend levels
(5 answers)
Closed last year.
I'd like to break the legend into categories rather than having a continuous range of colours. Could someone kindly help me for the specific example I am using here? Below is my current trial with colour breaks at 40, 60 and 80. Thank you very much!
library(raster)
library(ggplot2)
library(maptools)
data("wrld_simpl")
#sample raster
r <- raster(ncol=10, nrow=20)
r[] <- 1:ncell(r)
extent(r) <- extent(c(-180, 180, -70, 70))
#plotting
var_df <- as.data.frame(rasterToPoints(r))
p <- ggplot() +
geom_polygon(data = wrld_simpl[wrld_simpl#data$UN!="10",],
aes(x = long, y = lat, group = group),
colour = "black", fill = "grey")
p <- p + geom_raster(data = var_df, aes(x = x, y = y, fill = layer))
p <- p + coord_equal() + theme_bw() +labs(x="", y="")
p <- p + theme(legend.key=element_blank(),
axis.text.y =element_text(size=16),
axis.text.x =element_text(size=16),
legend.text =element_text(size=12),
legend.title=element_text(size=12))
# p <- p + scale_fill_gradientn(colours = rev(terrain.colors(10)))
p <- p + scale_colour_manual(values = c("red", "blue", "green","yellow"),
breaks = c("40", "60", "80", max(var_df$layer)),
labels = c("1-40", "40-60", "60-80", "80+"))
p <- p + geom_polygon(data = wrld_simpl[wrld_simpl#data$UN!="10",],
aes(x = long, y = lat, group = group),
colour = "black", fill = NA)
p
Current continuous legend:
Example of legend with breaks:
Here you go. I took the plot_discrete_cbar() function written by #AF7 from here
library(raster)
library(ggplot2)
library(maptools)
# Plot discrete colorbar function
plot_discrete_cbar = function (
# Vector of breaks. If +-Inf are used, triangles will be added to the sides of the color bar
breaks,
palette = "Greys", # RColorBrewer palette to use
# Alternatively, manually set colors
colors = RColorBrewer::brewer.pal(length(breaks) - 1, palette),
direction = 1, # Flip colors? Can be 1 or -1
spacing = "natural", # Spacing between labels. Can be "natural" or "constant"
border_color = NA, # NA = no border color
legend_title = NULL,
legend_direction = "horizontal", # Can be "horizontal" or "vertical"
font_size = NULL,
expand_size = 1, # Controls spacing around legend plot
spacing_scaling = 1, # Multiplicative factor for label and legend title spacing
width = 0.1, # Thickness of color bar
triangle_size = 0.1 # Relative width of +-Inf triangles
) {
require(ggplot2)
if (!(spacing %in% c("natural", "constant"))) stop("Spacing must be either 'natural' or 'constant'")
if (!(direction %in% c(1, -1))) stop("Direction must be either 1 or -1")
if (!(legend_direction %in% c("horizontal", "vertical"))) {
stop("Legend_direction must be either 'horizontal' or 'vertical'")
}
breaks = as.numeric(breaks)
new_breaks = sort(unique(breaks))
if (any(new_breaks != breaks)) warning("Wrong order or duplicated breaks")
breaks = new_breaks
if (class(colors) == "function") colors = colors(length(breaks) - 1)
if (length(colors) != length(breaks) - 1) {
stop("Number of colors (", length(colors), ") must be equal to number of breaks (",
length(breaks), ") minus 1")
}
if (!missing(colors)) {
warning("Ignoring RColorBrewer palette '", palette, "', since colors were passed manually")
}
if (direction == -1) colors = rev(colors)
inf_breaks = which(is.infinite(breaks))
if (length(inf_breaks) != 0) breaks = breaks[-inf_breaks]
plotcolors = colors
n_breaks = length(breaks)
labels = breaks
if (spacing == "constant") {
breaks = 1:n_breaks
}
r_breaks = range(breaks)
if(is.null(font_size)) {
print("Legend key font_size not set. Use default value = 5")
font_size <- 5
} else {
print(paste0("font_size = ", font_size))
font_size <- font_size
}
cbar_df = data.frame(stringsAsFactors = FALSE,
y = breaks,
yend = c(breaks[-1], NA),
color = as.character(1:n_breaks)
)[-n_breaks,]
xmin = 1 - width/2
xmax = 1 + width/2
cbar_plot = ggplot(cbar_df, aes(xmin = xmin, xmax = xmax,
ymin = y, ymax = yend, fill = color)) +
geom_rect(show.legend = FALSE,
color = border_color)
if (any(inf_breaks == 1)) { # Add < arrow for -Inf
firstv = breaks[1]
polystart = data.frame(
x = c(xmin, xmax, 1),
y = c(rep(firstv, 2), firstv - diff(r_breaks) * triangle_size)
)
plotcolors = plotcolors[-1]
cbar_plot = cbar_plot +
geom_polygon(data = polystart, aes(x = x, y = y),
show.legend = FALSE,
inherit.aes = FALSE,
fill = colors[1],
color = border_color)
}
if (any(inf_breaks > 1)) { # Add > arrow for +Inf
lastv = breaks[n_breaks]
polyend = data.frame(
x = c(xmin, xmax, 1),
y = c(rep(lastv, 2), lastv + diff(r_breaks) * triangle_size)
)
plotcolors = plotcolors[-length(plotcolors)]
cbar_plot = cbar_plot +
geom_polygon(data = polyend, aes(x = x, y = y),
show.legend = FALSE,
inherit.aes = FALSE,
fill = colors[length(colors)],
color = border_color)
}
if (legend_direction == "horizontal") { # horizontal legend
mul = 1
x = xmin
xend = xmax
cbar_plot = cbar_plot + coord_flip()
angle = 0
legend_position = xmax + 0.1 * spacing_scaling
} else { # vertical legend
mul = -1
x = xmax
xend = xmin
angle = -90
legend_position = xmax + 0.2 * spacing_scaling
}
cbar_plot = cbar_plot +
geom_segment(data = data.frame(y = breaks, yend = breaks),
aes(y = y, yend = yend),
x = x - 0.05 * mul * spacing_scaling, xend = xend,
inherit.aes = FALSE) +
annotate(geom = 'text', x = x - 0.1 * mul * spacing_scaling, y = breaks,
label = labels,
size = font_size) +
scale_x_continuous(expand = c(expand_size, expand_size)) +
scale_fill_manual(values = plotcolors) +
theme_void()
if (!is.null(legend_title)) { # Add legend title
cbar_plot = cbar_plot +
annotate(geom = 'text', x = legend_position, y = mean(r_breaks),
label = legend_title,
angle = angle,
size = font_size)
}
return(cbar_plot)
}
Cut data into bins for the discrete colorbar
myvalues <- c(seq(0, 200, 40), Inf)
var_df$cuts <- cut(var_df$layer, myvalues, include.lowest = TRUE)
levels(var_df$cuts)
#> [1] "[0,40]" "(40,80]" "(80,120]" "(120,160]" "(160,200]" "(200,Inf]"
Plot the raster
p <- ggplot() +
geom_polygon(data = wrld_simpl[wrld_simpl#data$UN != "10", ],
aes(x = long, y = lat, group = group),
colour = "black", fill = "grey")
p <- p + geom_raster(data = var_df, aes(x = x, y = y, fill = cuts)) # matching cuts & fill
p <- p + coord_equal() + theme_minimal() + labs(x="", y="")
p <- p + theme(legend.key =element_blank(),
axis.text.y =element_text(size=16),
axis.text.x =element_text(size=16),
legend.text =element_text(size=12),
legend.title=element_text(size=12))
p <- p + scale_fill_brewer("Layer", palette = "YlGnBu", drop = FALSE)
p <- p + geom_polygon(data = wrld_simpl[wrld_simpl#data$UN != "10", ],
aes(x = long, y = lat, group = group),
colour = "black", fill = NA)
p <- p + theme(legend.position = "none")
Plot the discrete colorbar
dbar <- plot_discrete_cbar(myvalues,
palette = "YlGnBu",
legend_title = NULL,
spacing = "natural")
# reduce top and bottom margins
p1 <- p + theme(plot.margin = unit(c(10, 10, -35, 10), "pt"))
dbar <- dbar + theme(plot.margin = unit(c(-35, 10, -30, 10), "pt"))
Combine two plots together
# devtools::install_github('baptiste/egg')
library(egg)
ggarrange(p1, dbar, nrow = 2, ncol = 1, heights = c(1, 0.4))
Created on 2018-10-18 by the reprex package (v0.2.1.9000)
I am trying to create a map that to show some study sites in three states. I would like to get rid of the black border lines that go through the map. Like below:
lon <- c(-89.105917,-89.377778,-86.700278,-86.677361,-87.338083,-87.340444)
lat <- c(37.358694, 37.215278,38.460528,38.448389,37.594583,37.5945)
#crop
lon1 <- c(-86.6214142,-87.3423767,-87.6656265,-87.1565475,-87.8155823,-87.3194199,-87.3565598)
lat1 <- c(38.484581,37.7038918,37.7400513,38.0794983,37.6372185,37.4466667,37.3590546)
#CRP
lon2 <-c(-88.4263,-87.4707718,-86.435585,-87.9516907,-89.2439117,-88.3630524,-89.0109711)
lat2 <- c(37.3582993,37.5196114,37.5220261,37.4958801,37.3413811,37.2275009,37.3633308)
#Forest
lon3 <-c(-86.608551,-87.3794403,-88.9937515,-86.7436066,-86.7483826)
lat3 <- c(38.2506294,36.9505539,37.4111404,38.1277695,37.1684914)
#Pasture
lon4 <-c(-86.6036377,-86.2461395,-86.9746704,-87.4977493,-88.9970474,-86.2609634,-86.6067734,-86.9820709)
lat4 <- c(37.0606689,37.8114433,37.5391922,37.8073006,37.4703789,37.3089409,38.1600189,37.6018295)
df <- as.data.frame(cbind(lon,lat))
df1 <- as.data.frame(cbind(lon1,lat1))
df2 <- as.data.frame(cbind(lon2,lat2))
df3 <- as.data.frame(cbind(lon3,lat3))
df4 <- as.data.frame(cbind(lon4,lat4))
pdf("/Users/tribaker/Desktop/Thesis/RaCA/RaCASites.pdf")
al1 = get_map(location = c("posey county,indiana"),
zoom = 8, maptype = 'satellite')
mdat <- map_data('state',Fill=TRUE)
ggmap(al1) +
geom_path(data=mdat,aes(x=long,y=lat, regions=c('"Kentucky","Illinois","Indiana"')),colour="black",alpha=1)+
borders("county", colour="grey60", alpha=.5)+
borders("state", colour="black", alpha=.8)+
geom_point(data = df, aes(x = lon, y = lat,colour = "Study Site", alpha = 0.8), size = 8, shape = 15) +
geom_point(data = df1, aes(x = lon1, y = lat1,colour = "Crop",fill=TRUE, alpha = 0.8), size = 8, shape = 16) +
geom_point(data = df2, aes(x = lon2, y = lat2,colour = "CRP", fill = TRUE ,alpha = 0.8), size = 8, shape = 16) +
geom_point(data = df3, aes(x = lon3, y = lat3, colour = "Forest",fill = TRUE,alpha = 0.8), size = 8, shape =16) +
geom_point(data = df4, aes(x = lon4, y = lat4,colour = "Pasture",fill = TRUE,alpha = 0.8), size = 8, shape = 16) +
guides(fill=FALSE, alpha=FALSE, size=FALSE)
geom_text(aes(label = state), data = mdat, size = 2, angle = 45)
thanks in advance
I couldn't get the borders function to work correctly, but you can just do it manually...
Create an mdat2 dataframe with the county data and draw the borders yourself...
lon <- c(-89.105917,-89.377778,-86.700278,-86.677361,-87.338083,-87.340444)
lat <- c(37.358694, 37.215278,38.460528,38.448389,37.594583,37.5945)
#crop
lon1 <- c(-86.6214142,-87.3423767,-87.6656265,-87.1565475,-87.8155823,-87.3194199,-87.3565598)
lat1 <- c(38.484581,37.7038918,37.7400513,38.0794983,37.6372185,37.4466667,37.3590546)
#CRP
lon2 <-c(-88.4263,-87.4707718,-86.435585,-87.9516907,-89.2439117,-88.3630524,-89.0109711)
lat2 <- c(37.3582993,37.5196114,37.5220261,37.4958801,37.3413811,37.2275009,37.3633308)
#Forest
lon3 <-c(-86.608551,-87.3794403,-88.9937515,-86.7436066,-86.7483826)
lat3 <- c(38.2506294,36.9505539,37.4111404,38.1277695,37.1684914)
#Pasture
lon4 <-c(-86.6036377,-86.2461395,-86.9746704,-87.4977493,-88.9970474,-86.2609634,-86.6067734,-86.9820709)
lat4 <- c(37.0606689,37.8114433,37.5391922,37.8073006,37.4703789,37.3089409,38.1600189,37.6018295)
df <- as.data.frame(cbind(lon,lat))
df1 <- as.data.frame(cbind(lon1,lat1))
df2 <- as.data.frame(cbind(lon2,lat2))
df3 <- as.data.frame(cbind(lon3,lat3))
df4 <- as.data.frame(cbind(lon4,lat4))
al1 = get_map(location = c("posey county,indiana"),
zoom = 8, maptype = 'satellite')
mdat <- map_data('state', regions=c("Kentucky","Illinois","Indiana"))
mdat2 <- map_data('county', regions=c("Kentucky","Illinois","Indiana"))
ggmap(al1) +
geom_path(data=mdat2,aes(x=long,y=lat,group=group), colour="grey60", alpha=.5)+
geom_path(data=mdat,aes(x=long,y=lat,group=group), colour="black", alpha=.8)+
geom_point(data = df, aes(x = lon, y = lat,colour = "Study Site", alpha = 0.8), size = 8, shape = 15) +
geom_point(data = df1, aes(x = lon1, y = lat1,colour = "Crop",fill=TRUE, alpha = 0.8), size = 8, shape = 16) +
geom_point(data = df2, aes(x = lon2, y = lat2,colour = "CRP", fill = TRUE ,alpha = 0.8), size = 8, shape = 16) +
geom_point(data = df3, aes(x = lon3, y = lat3, colour = "Forest",fill = TRUE,alpha = 0.8), size = 8, shape =16) +
geom_point(data = df4, aes(x = lon4, y = lat4,colour = "Pasture",fill = TRUE,alpha = 0.8), size = 8, shape = 16) +
guides(fill=FALSE, alpha=FALSE, size=FALSE)
geom_text(aes(label = state), data = mdat, size = 2, angle = 45)
The question relates to this: Line graph customization (add circles, colors), but since I got a new task, I created a new question.
So again my data frame is the same as in the question I've posted in a link. With code below and (little of my own modification) that was given to me by #beetroot
value <- c(9, 4, 10, 7, 10,
10, 10, 4, 10,
4, 10, 2, 5, 5, 4)
names <- c("a","b",
"c","d","e",
"f", "g","h",
"i","j","k","l",
"m","n","p")
df <- data.frame(value, names)
df$names <- as.character(df$names)
df$part <- rep(c("part3", "part2", "part1"), each = 5)
library(dplyr)
library(tidyr)
df2 <- df %>%
group_by(part, names) %>%
expand(value = min(df$value):max(df$value))
p <- ggplot() +
geom_point(data = df2, aes(x = value, y = names),
shape = 1) +
geom_point(data = df, aes(y = names, x = value, group = 1),
colour = I("red"), shape = 21, lwd = 3, fill = "red") +
geom_line(data = df, aes(y = names, x = value, group = 1),
group = I(1),color = I("red")) +
theme_bw() +
facet_wrap(~part, ncol = 1, scales = "free_y")
p + theme(strip.background = element_rect(fill="dodgerblue3"),
strip.text.x = element_text(colour = "white"))+xlab("") +ylab("")
df <- data.frame(value, names)
df$names <- as.character(df$names)
I get this output:
But now I would like to connect lines through (PART1, PART2 and PART3) so that my output would look like:
I used black color of a line just it will be more visible that I would like to connect this parts with lines.
Although I am not completely satisfied I've found solution. I computed the bounding box.
Firstly I removed facet_wrap(~part, ncol = 1, scales = "free_y") so my code looks like this:
p <- ggplot() +
geom_point(data = df2, aes(x = value, y = names),
shape = 1) +
geom_point(data = df, aes(y = names, x = value, group = 1),
colour = I("red"), shape = 21, lwd = 3, fill = "red") +
geom_line(data = df, aes(y = names, x = value, group = 1),
group = I(1),color = I("red")) +
theme_bw()
Then the trick was to create data frame and add the width and height of text directly:
# PART 1
TextFrame <- data.frame(X = 6, Y = 15.5, LAB = "PART 1")
TextFrame <- transform(TextFrame,
w = strwidth(LAB, 'inches') + 8,
h = strheight(LAB, 'inches') + 0.3
)
# PART 2
TextFrame.1 <- data.frame(X = 6, Y = 10.5, LAB = "PART 2")
TextFrame.1 <- transform(TextFrame.1,
w = strwidth(LAB, 'inches') + 8,
h = strheight(LAB, 'inches') + 0.3
)
# PART 3
TextFrame.2 <- data.frame(X = 6, Y = 4.5, LAB = "PART 3")
TextFrame.2 <- transform(TextFrame.2,
w = strwidth(LAB, 'inches') + 8,
h = strheight(LAB, 'inches') + 0.3
)
Then I've used geom_rectand geom_text to create the illusion I am after.
p + geom_rect(data = TextFrame, aes(xmin = X - w/2, xmax = X + w/2,
ymin = Y - h/2, ymax = Y + h/2), fill = "dodgerblue3") +
geom_text(data = TextFrame,aes(x = X, y = Y, label = LAB), size = 5) +
geom_rect(data = TextFrame.1, aes(xmin = X - w/2, xmax = X + w/2,
ymin = Y - h/2, ymax = Y + h/2), fill = "dodgerblue3") +
geom_text(data = TextFrame.1,aes(x = X, y = Y, label = LAB), size = 5) +
geom_rect(data = TextFrame.2, aes(xmin = X - w/2, xmax = X + w/2,
ymin = Y - h/2, ymax = Y + h/2), fill = "dodgerblue3") +
geom_text(data = TextFrame.2,aes(x = X, y = Y, label = LAB), size = 5)
And the output is:
Any solution for drawing a scale bar and north arrow on map with ggplot2
library(mapdata); library(ggplot2);
nl.map=data.frame(map('worldHires', 'Netherlands')[c('x', 'y')])
ggplot(nl.map, aes(x, y))+geom_path()
Thanks for your time.
A few years back I produced some code that could draw a scalebar (see also this post on r-sig-geo), this is the code I wrote back then. You could give it a go:
First some support functions:
makeNiceNumber = function(num, num.pretty = 1) {
# Rounding provided by code from Maarten Plieger
return((round(num/10^(round(log10(num))-1))*(10^(round(log10(num))-1))))
}
createBoxPolygon = function(llcorner, width, height) {
relativeCoords = data.frame(c(0, 0, width, width, 0), c(0, height, height, 0, 0))
names(relativeCoords) = names(llcorner)
return(t(apply(relativeCoords, 1, function(x) llcorner + x)))
}
And the real function:
addScaleBar = function(ggplot_obj, spatial_obj, attribute, addParams =
list()) {
addParamsDefaults = list(noBins = 5, xname = "x", yname = "y", unit = "m",
placement = "bottomright", sbLengthPct = 0.3, sbHeightvsWidth = 1/14)
addParams = modifyList(addParamsDefaults, addParams)
range_x = max(spatial_obj[[addParams[["xname"]]]]) - min(spatial_obj[[addParams[["xname"]]]])
range_y = max(spatial_obj[[addParams[["yname"]]]]) - min(spatial_obj[[addParams[["yname"]]]])
lengthScalebar = addParams[["sbLengthPct"]] * range_x
## OPTION: use pretty() instead
widthBin = makeNiceNumber(lengthScalebar / addParams[["noBins"]])
heightBin = lengthScalebar * addParams[["sbHeightvsWidth"]]
lowerLeftCornerScaleBar = c(x = max(spatial_obj[[addParams[["xname"]]]]) - (widthBin * addParams[["noBins"]]), y = min(spatial_obj[[addParams[["yname"]]]]))
scaleBarPolygon = do.call("rbind", lapply(0:(addParams[["noBins"]] - 1), function(n) {
dum = data.frame(createBoxPolygon(lowerLeftCornerScaleBar + c((n * widthBin), 0), widthBin, heightBin))
if(!(n + 1) %% 2 == 0) dum$cat = "odd" else dum$cat = "even"
return(dum)
}))
scaleBarPolygon[[attribute]] = min(spatial_obj[[attribute]])
textScaleBar = data.frame(x = lowerLeftCornerScaleBar[[addParams[["xname"]]]] + (c(0:(addParams[["noBins"]])) * widthBin), y = lowerLeftCornerScaleBar[[addParams[["yname"]]]],
label = as.character(0:(addParams[["noBins"]]) * widthBin))
textScaleBar[[attribute]] = min(spatial_obj[[attribute]])
return(ggplot_obj +
geom_polygon(data = subset(scaleBarPolygon, cat == "odd"), fill = "black", color = "black", legend = FALSE) +
geom_polygon(data = subset(scaleBarPolygon, cat == "even"), fill = "white", color = "black", legend = FALSE) +
geom_text(aes(label = label), color = "black", size = 6, data = textScaleBar, hjust = 0.5, vjust = 1.2, legend = FALSE))
}
And some example code:
library(ggplot2)
library(sp)
data(meuse)
data(meuse.grid)
ggobj = ggplot(aes(x = x, y = y, color = zinc), data = meuse) + geom_point()
# Make sure to increase the graphic device a bit
addScaleBar(ggobj, meuse, "zinc", addParams = list(noBins = 5))
There is a library called ggsn, which allows you to customize the scale bar and north arrow.
ggplot() +
geom_path(aes(long, lat, group=group), data=worldUk, color="black", fill=NA) +
coord_equal() +
ggsn::scalebar(worldUk, dist = 100, st.size=3, height=0.01, dd2km = TRUE, model = 'WGS84')