I'm trying to add a couple details to my map in ggplot2 but I'm new to the package and I'm not sure how to proceed. Code and map are below (ignore the weird spacing on the map, I took a screen shot in Rstudio). Thanks for taking a look!
I'm trying to do the following:
Add latitude and longitude tick marks on the x and y axis. I coded it in the script below but nothing is happening, not sure why - no errors pop up.
If possible, I'd like to add a box in the inset map showing the extent/coverage of the larger map, since the points in the smaller map (the red ones) are barely visible. I'm not sure how to add and place a polygon in the inset map.
Here is what the map currently looks like for reference:
library(raster)
library(ggplot2)
library(ggthemes)
library(ggsn)
library(ggmap)
library(maps)
library(mapdata)
mapdata <- getData("GADM", country = "panama", level = 1)
mymap <- fortify(mapdata)
mypoint <- data.frame(long=c(-79.743, -79.696, -79.645, -79.595),
lat=c(9.160, 9.117, 9.058, 9.015),
group=c("L", "GW", "OGR", "LC"))
mypoint2 <- data.frame(long=c(-79.846, -79.707, -79.665, -79.610),
lat=c(9.181, 9.112, 9.057, 9.014),
group=c("BCI", "G", "EH", "MF"))
g1 <- ggplot() +
geom_blank(data = mymap, aes(x=long, y=lat)) +
geom_map(data = mymap, map = mymap,
aes(group = group, map_id = id),
fill = "#b2b2b2", color = "black", size = 0.3) +
coord_sf(xlim=c(-80,-79.5), ylim=c(8.9, 9.25), expand = FALSE) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "black", size = 3) +
geom_label(data = mypoint, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(0.015, 0.02, 0.022, 0.018)) +
geom_point(data = mypoint2, aes(x = long, y = lat),
color = "blue", size = 3) +
geom_label(data = mypoint2, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(-0.02, -0.018, -0.02, -0.02)) +
scale_x_continuous(limits = c(-80,-79.5), expand = c(0, 0)) +
scale_y_continuous(limits = c(8.9, 9.25), expand = c(0, 0)) +
theme_map() +
ggsn::scalebar(location = "bottomleft", dist = 5,
transform = TRUE, dist_unit = "km", model = 'WGS84',
x.min = -79.97, x.max = -79.8,
y.min = 8.93, y.max = 9.25) +
north(x.min = -79.6, x.max = -79.5,
y.min = 9.2, y.max = 9.24,
location = "toprgiht", scale = 0.1)
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(panel.background = element_rect(fill = NULL))
)
g3 <- g1 +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Latitude and longitude tick marks are disappearing because of theme_map() - it sets axis_ticks and axis_text (among other things) to element_blank(). One way to get them back is to override theme_map() with
g1_with_lbls <- g1 +
theme(
axis.text = element_text(),
axis.ticks = element_line(),
axis.title = element_text()
) +
xlab("Longitude") +
ylab("Lattitude")
You would place the polygon on the smaller map as a part of the ggplotGrob object you are creating
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(
panel.background = element_rect(fill = NULL)
) +
geom_rect(
aes(xmin = -80, xmax = -79, ymin = 8.5, ymax = 9.5), fill = NA,
col = "red", size = 1
)
)
Then
g3 <- g1_with_lbls +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Has both the ticks and the rectangle.
Related
I am trying to plot a polygon hull using ggplot and plotly.
While without label polygons are shown in the plot, when I add extra labels in aesthetics the polygons disappear.
library(data.table)
library(ggplot2)
library(dplyr)
library(plotly)
df <- data.table(continent = c(rep("America",3), rep("Europe",4)),
state = c("USA", "Brasil", "Chile", "Italy", "Swiss", "Spain", "Greece"),
X = rnorm(7, 5, 1),
Y = rnorm(7, -13, 1)
)
df$X_sd = sd(df$X)
df$Y_sd = sd(df$Y)
hull2 <- df %>%
group_by(continent) %>%
slice(chull(X,Y))
p <- df %>%
ggplot( aes(x=X,
y=Y,
fill = continent,
color = continent,
label=state))+
geom_polygon(data = hull2,
lwd = 1,
alpha = 0.1,
linetype = "dashed")+
geom_errorbarh(aes(xmin = X - X_sd,
xmax = X + X_sd),
size = 0.5,
alpha = 0.3) +
geom_errorbar(aes(ymin = Y - Y_sd,
ymax = Y + Y_sd),
size = 0.5,
alpha = 0.3) +
geom_point(shape=21,
color="black",
size=3)+
theme_bw()+
theme(legend.position = "none")
ggplotly(p)
How odd! If you most label = state to the aes for the last geom_ you'll get the standard warning, but it works and the state shows up in the tooltip.
The designation of color = continent shows up, as well. I am going to guess that you're not interested in having that in your tooltip, so I've added how you could change that at the end. There is a tooltip with the continent listed two times, but with the information about how to remove the color, you'll see how you might make further adjustments depending on the trace.
p <- df %>%
ggplot(aes(x = X, y = Y,
fill = continent,
color = continent #,
# label = state)
)) +
geom_polygon(data = hull2, lwd = 1,
alpha = 0.1, linetype = "dashed") +
geom_errorbarh(aes(xmin = X - X_sd,
xmax = X + X_sd),
size = 0.5, alpha = 0.3) +
geom_errorbar(aes(ymin = Y - Y_sd,
ymax = Y + Y_sd),
size = 0.5, alpha = 0.3) +
geom_point(shape = 21,
color = "black",
size = 3, aes(label = state)) +
theme_bw() + theme(legend.position = "none")
p
ggplotly(p)
To remove the color from the tooltip, assign ggplotly to an object. Then you can remove the string from the 7th and 8th trace.
p1 = ggplotly(p)
lapply(7:8,
function(i){
p1$x$data[[i]]$text <<- stringr::str_replace(p1$x$data[[i]]$text,
"continent: black<br />",
"")
})
p1
FYI, there are 8 traces that make up your plot. The first trace has the double continent text.
I created the following plot using ggplot:
y1 <- runif(20,-2,7)
y2 <- c(-0.30306664,0.14744265 , 0.43857131 ,-0.04536794 ,-1.41432016,0.51887010 , 6.34925495 , 2.82511601 , 2.84251791, 4.05300569,-2.34208042, -0.29278747 , 0.49661933 , 0.75099908 ,1.12097713,2.72244949 , 2.23933230 , 1.86667714 , 2.17540024 , 7.56568823)
x <- 2001:2020
ggplot() +
geom_rect(aes(xmin=2006.90, xmax=2009.15,ymin=-Inf,ymax=10, fill='blue'), alpha= 0.4)+geom_rect(aes(xmin=2019.80, xmax=Inf,ymin=-Inf,ymax=10, fill='orange'), alpha= 0.3)+geom_rect(aes(xmin=2009.90, xmax=2013.15,ymin=-Inf,ymax=10, fill="lightgreen"), alpha= 0.4)+
geom_line(aes(x=x,y = y1),colour="black")+geom_line(aes(x=x,y = y2),colour="red")+
geom_point(aes(x=x,y = y1),col="black")+
geom_point(aes(x=x,y = y2),col="red")+
theme_classic()+
scale_fill_manual(name="",values = c("lightblue","lightgreen","orange"),labels=c(" R","k","C"))+theme(legend.position = "bottom")+ theme(axis.text.x = element_text(angle = 90))+geom_hline(yintercept = 0, color="black", size=1)
I have one legend to explain the content of the rectangles of the graph, but I need to add another legend to explain the two lines which are black and red. I wondered how to add another legend with a different position than the one that already exists to explain the names of the lines?
Can anyone help?
Move color inside aes, add scale_color_identity to get the right colors and to set the labels for the legend:
library(ggplot2)
ggplot() +
geom_rect(aes(xmin = 2006.90, xmax = 2009.15, ymin = -Inf, ymax = 10, fill = "blue"), alpha = 0.4) +
geom_rect(aes(xmin = 2019.80, xmax = Inf, ymin = -Inf, ymax = 10, fill = "orange"), alpha = 0.3) +
geom_rect(aes(xmin = 2009.90, xmax = 2013.15, ymin = -Inf, ymax = 10, fill = "lightgreen"), alpha = 0.4) +
geom_line(aes(x = x, y = y1, colour = "black")) +
geom_line(aes(x = x, y = y2, colour = "red")) +
geom_point(aes(x = x, y = y1, col = "black")) +
geom_point(aes(x = x, y = y2, col = "red")) +
scale_color_identity(name = NULL, labels = c(black = "Label 1", red = "Label 2"), guide = "legend") +
theme_classic() +
scale_fill_manual(name = "", values = c("lightblue", "lightgreen", "orange"), labels = c(" Rezession", "krise", "Corona 2020-")) +
theme(legend.position = "bottom") +
theme(axis.text.x = element_text(angle = 90)) +
geom_hline(yintercept = 0, color = "black", size = 1)
I'm looking for a way to move every second x-axis tick downwards and have the tick line go down with it.
I can change the general margin and tick length for all ticks with:
#MWE
library(ggplot2)
ggplot(cars, aes(dist, speed))+
geom_point()+
theme(
axis.ticks.length.x = unit(15, "pt")
)
But, I would like the x-axis ticks 0, 50, and 100 (i.e., every second tick) to be without the added top margin.
A generalized answer is preferred as my x-axis is categorical and not numerical (and contains 430 ticks, so nothing I can set by hand).
Any ideas?
Edit:
Output should be:
Edit2:
A more intricate example would be:
#MWE
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge')+
theme(
axis.ticks.length.x = unit(15, "pt")
)
Edit -- added categorical approach at bottom.
Here's a hack. Hope there's a better way!
ticks <- data.frame(
x = 25*0:5,
y = rep(c(-0.2, -2), 3)
)
ggplot(cars, aes(dist, speed))+
geom_point()+
geom_rect(fill = "white", xmin = -Inf, xmax = Inf,
ymin = 0, ymax = -5) +
geom_segment(data = ticks,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks,
aes(x = x, y = y, label = x), vjust = 1.5) +
theme(axis.ticks.x = element_blank()) +
scale_x_continuous(breaks = 25*0:5, labels = NULL, name = "") +
coord_cartesian(clip = "off")
Here's a similar approach used with a categorical x.
cats <- sort(as.character(unique(diamonds$cut)))
ticks <- data.frame(x = cats)
ticks$y = ifelse(seq_along(cats) %% 2, -500, -2000)
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge') +
annotate("rect", fill = "white",
xmin = 0.4, xmax = length(cats) + 0.6,
ymin = 0, ymax = -3000) +
geom_segment(data = ticks, inherit.aes = F,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks, inherit.aes = F,
aes(x = x, y = y, label = x), vjust = 1.5) +
scale_x_discrete(labels = NULL, name = "cut") +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.05))) +
theme(axis.ticks.x = element_blank()) +
coord_cartesian(clip = "off")
I map the southern part of the South hemisphere. My issue is Australia which has poorly drawn borders.
My data :
library("maptools")
library("ggplot2")
library("tidyverse")
ylim_map <- c(-90, -30)
xlim_map <- c(-180, 180)
world <- maps::map("world", fill=TRUE, plot=FALSE, ylim = ylim_map)
Convert data in correct format for ggplot :
IDs <- sapply(strsplit(world$names, ":"), function(x) x[1])
world <- map2SpatialPolygons(world, IDs = IDs,
proj4string = CRS("+proj=longlat +datum=WGS84"))
world_map <- fortify(world)
world_map <- world_map[which(between(world_map$lat, ylim_map[1], ylim_map[2]) &
between(world_map$lon, xlim_map[1], xlim_map[2])),]
And my plot :
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)
TLDR:
You need to close your polygons.
Explanation:
Let's trim away extraneous code & zoom in onto Australia. (Though actually the problem exists for Africa & South America as well; it's just not as obvious there...)
We can see that the top line is misbehaving. It's intersecting with the coastline further down south, rather than sticking to its correct latitude level:
ggplot() +
coord_map("orthographic", orientation = c(-40, 130, 0)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id=id),
fill = "darkgrey") +
theme_bw()
Now a geom_map layer is essentially plotting polygons, and ?geom_polygon states:
Polygons are very similar to paths (as drawn by geom_path()) except
that the start and end points are connected and the inside is coloured
by fill. The group aesthetic determines which cases are connected
together into a polygon.
If we replace the geom_map layer with its geom_polygon / geom_path equivalents, the situation becomes much more obvious: the polygon corresponding to Australia has no top line. Instead, the path starts at the one corner and ends at the opposite corner. geom_polygon connects them with a straight line, which may intersect other lines when the coordinate system isn't linear (and coord_map isn't):
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map,
aes(x = long, y = lat, group = group)) +
theme_bw()
Solution:
We can manually close each polygon by repeating its first point at the end. (For polygons that are already closed, this has no additional effect.)
library(dplyr)
world_map2 <- world_map %>%
group_by(group) %>% # each group corresponds to a unique polygon
arrange(order) %>% # sort points in the appropriate sequence
slice(c(1:n(), 1)) %>% # repeat first row after last row
mutate(order = seq(1, n())) %>% # define new order for n+1 rows
ungroup()
Check that the polygons are now closed, & the top line for Australia now traces its latitude level nicely:
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map2,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map2,
aes(x = long, y = lat, group = group)) +
theme_bw()
Applying this to the original use case:
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map2, map = world_map2,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)
I am trying to plot a map with Peru and Ecuador, that presents two simple lat and long points (San Jose and Lima in Peru).
I'm having some issue with the fill when incorporating both Peru and Ecuador into my map.
library(ggplot2)
library(ggmap)
library(maps)
library(mapdata)
peru_ecuador <- map_data("world",c("peru", "ecuador"))
# Add study site points (San Jose and Lima)
points <- data.frame(
long = c(-79.81, -77.04),
lat = c(-6.77, -12.04),
names = c("San Jose", "Lima"),
stringsAsFactors = FALSE
)
# Plot the map
ggplot() +
geom_polygon(data = peru_ecuador, aes(x=long, y = lat), fill = "grey40", color
= "grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)
I would also really love some advise on how best to resize the plot area window of the map. As in change the x and y axis width and length. When I plot just a map of Peru, some of my map information is cut off by the size of the plot area. Please see below:
peru <- map_data("world","peru")
ggplot() +
geom_polygon(data = peru, aes(x=long, y = lat), fill = "grey40", color =
"grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)