I am plotting a map of Norway with an area of interest highlighted with a red rectangle using ggplot2. If I omit the geom_rect or coord_map, the map plots very quickly (< 1 seconds). If I use both - which I need to - it is extremely slow to print and render (about five minutes).
I presume this is something to do with the munching - projecting the rectangle onto the new coordinate system. Is there a way to control this?
library(ggplot2)
library(maps)
library(mapdata)
xlim <- c(5, 10)
ylim <- c(60, 62)
norwaymap <- map_data("worldHires", "Norway")
a <- ggplot(norwaymap, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = NA, fill = "grey60") +
geom_rect(xmin = xlim[1], xmax = xlim[2], ymin = ylim[1], ymax = ylim[2],
colour = "red", fill = NA) +
coord_map(xlim = c(3, 33), ylim = c(57, 72))
print(a) # super slow
Using the low resolution map makes the map plotting much faster (about 10 seconds).
No need to resort to mercator approximations:
library(ggplot2)
library(maps)
library(mapdata)
norwaymap <- map_data("worldHires", "Norway")
xlim <- c(5, 10)
ylim <- c(60, 62)
ggplot() +
geom_map(data=norwaymap, map=norwaymap,
aes(long, lat, map_id=region),
color=NA, fill="grey60") +
geom_rect(data=data.frame(),
aes(xmin=xlim[1], xmax=xlim[2], ymin=ylim[1], ymax=ylim[2]),
color="red", fill=NA) +
coord_map(xlim=c(3, 33), ylim=c(57, 72)) +
ggthemes::theme_map()
Another option would be to use an Albers equal-area conic projection (a typical one for that region):
ggplot() +
geom_map(data=norwaymap, map=norwaymap,
aes(long, lat, map_id=region),
color=NA, fill="grey60") +
geom_rect(data=data.frame(),
aes(xmin=xlim[1], xmax=xlim[2], ymin=ylim[1], ymax=ylim[2]),
color="red", fill=NA) +
ggalt::coord_proj("+proj=aea +lat_1=60 +lat_2=70 +lon_0=18.37",
xlim=c(3, 33), ylim=c(57, 72)) +
ggthemes::theme_map()
That has a "disadvantage" of the rectangle being projected (it is with Mercator, too, there's just no distortion).
Either way, the magic for the rectangle is ensuring you're plotting only one, like Luke said.
Use coord_quickmap and especially annotate instead of geom_rect to speed things up:
ggplot(norwaymap, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = NA, fill = "grey60") +
annotate(geom="rect", xmin = xlim[1], xmax = xlim[2], ymin = ylim[1],
ymax = ylim[2], colour = "red", fill = NA) +
coord_quickmap(xlim = c(3, 33), ylim = c(57, 72))
geom_rect overplots several rectangles on the same spot, annotate just plots one rectangle. You can read about the difference between coord_map and coord_quickmap in the help files: ?coord_quickmap.
Related
I'm making a ggplot of a basemap with some points overlaid. I believe the default for plotting a basemap is to have the axes plot in latlong with degrees N/W (even though its projected in web mercator) but the degree symbol isn't showing up and instead is displayed as a little box?
library(sf)
library(basemaps)
library(ggplot2)
library(ggstar)
pt_df = data.frame(X = c(-10069438, -10827213),
Y = c(4014585, 4013104),
Type = c("MS", "OK"))
pt_df = st_as_sf(pt_df, coords = c("X", "Y"), crs = 3857)
bbox = st_box(pt_df)
bbox["xmin"]<- -11500000
bbox["xmax"]<- -9900000
bbox["ymin"] <- 3000000
bbox["ymax"] <- 4500000
basemap_ggplot(bbox, map_service="osm_stamen", map_type="terrain")+
geom_star(data = pt_df, aes(x=X, y=Y, fill="red"), size=5)+
xlab("")+
ylab("")
I wrote out the expression to recode the x- and y- axes yet they're still showing boxes.
basemap_ggplot(bbox, map_service="osm_stamen",
map_type="terrain")+
geom_star(data = pt_df, aes(x=X, y=Y, fill="red"), size=5)+
xlab("")+
ylab("")+
scale_y_continuous(breaks = c(28, 30, 32, 34, 36),
labels = c(expression(28~degree~N),
expression(30~degree~N),
expression(32~degree~N),
expression(34~degree~N),
expression(36~degree~N)))+
scale_x_continuous(breaks = c(-100, -95, -90, -85),
labels = c(expression(-100~degree~W),
expression(-95~degree~W),
expression(-90~degree~W),
expression(-85~degree~W)))
Any ideas?
Here's an example of my code but I almost think it might be some sort of setting issue and therefore isn't reproducible on someone else's computer? Any help/ideas appreciated.
We could insert unicode character:
scale_y_continuous(labels = function(x) paste0(x, '\u00B0', "N"))
ggplot() +
geom_sf(
data = border$osm_lines,
inherit.aes = FALSE,
color = "black",
size = .4,
alpha = .8
)+
scale_y_continuous(labels = ~ paste0(., '\u00B0', "N"))+
scale_x_continuous(labels = ~ paste0(., '\u00B0', "N"))
I have created maps using the ggplot function on R. I then wanted to add bathymetric lines. I so downloaded them from the NOAA portal using the code lines:
library(marmap)
bat <- getNOAA.bathy(-11.99792 ,-5.002083 ,35.00208,43.99792,res=4, keep=TRUE)
plot(bat, land=TRUE, n=100, lwd=0.03)
plot(bat, deep=-200, shallow=-200, step=0, lwd=0.5, drawlabel=TRUE, add=TRUE)
plot(bat, deep=-1000, shallow=-1000, step=0, lwd=0.3, drawlabel=TRUE, add=TRUE)
Until this moment the lines look homogeneous and not discontinued.
I then run these two lines:
bathy_df <- inlmisc::Grid2Polygons(as.SpatialGridDataFrame(bat),
level=TRUE, pretty=TRUE)
bathy_map <- fortify(bathy_df)
But then, when I add bathy_map to my ggplot, the lines of the bathymetry appear as you can see in the attached picture: not homogeneous at all and discontinue.
This is the script of my ggplot:
D <- ggplot() +
geom_raster(data = Fig_D, aes(x = x, y = y, fill = value)) +
facet_wrap(~ variable) +
coord_equal() +
scale_fill_viridis_c(option = "turbo", direction = 1, limits=c(0, 160)) +
geom_polygon(data=bathy_map,
aes(x=long,y=lat,group=group), inherit.aes=F,
colour='black', fill=NA, lwd=0.5)+
geom_polygon(data = coast_map,
aes(x=long,y=lat,group=group), inherit.aes=F,
colour='black', fill='gray', lwd=0.5) +
theme_void(base_size = 12) +
theme(strip.text.x = element_text(size = 10, vjust = 1)) +
theme(legend.position = "right", legend.justification = "left") +
labs(fill='SPL')
(the first geom_polygon is the one referring to the bathymetric lines)
Do you know how I can make these lines look more homogeneous? And also, do you know how I can show the depth of some of the most important bathymetric lines?
Thank you.
Maps created with ggplot showing bathymetric lines
When you want to draw maps with ggplot2, always think library(sf)! ;-)
Here is an example:
# Load useful packages
library(sf)
library(marmap)
library(tidyverse)
library(rnaturalearth)
# Get bathymetric data
bat <- getNOAA.bathy(-12, -5, 35, 44, res = 4, keep = TRUE)
bat_xyz <- as.xyz(bat)
# Import country data
country <- ne_countries(scale = "medium", returnclass = "sf")
# Plot using ggplot and sf
ggplot() +
geom_sf(data = country) +
geom_tile(data = bat_xyz, aes(x = V1, y = V2, fill = V3)) +
geom_contour(data = bat_xyz,
aes(x = V1, y = V2, z = V3),
binwidth = 100, color = "grey85", size = 0.1) +
geom_contour(data = bat_xyz,
aes(x = V1, y = V2, z = V3),
breaks = -200, color = "grey85", size = 0.5) +
geom_sf(data = country) +
coord_sf(xlim = c(-12, -5),
ylim = c(35, 44)) +
labs(x = "Longitude", y = "Latitude", fill = "Depth (m)") +
theme_minimal()
And here is the result.
You don't need to use inlmisc::Grid2Polygons() nor ggplot2::fortify(). Simply use marmap::as.xyz() to transform your bathymetric data into a long data.frame, and use either (or both), of geom_tile() and geom_contour().
Of course, you can add several layers of geom_contour(). Here, I've added one with one isobath every 100 meters, and a darker one at -200m.
As for labelling some (or all) of the isobaths, have a look at metR::geom_label_contour()
I need to plot some data over a map of Antarctica and I managed to do so following this thread
Polar/Stereographic map in R
library(rgdal)
library(raster)
library(ggplot2)
Long <- c(-75, -76, -77, -78, -79)
Lat <- c(123, 124, 125, 126, 127)
Sodio<- c(110, 209, 65.7, 47.6, 135)
data<-data.frame(Long, Lat, Sodio)
# Defines the x axes required
x_lines <- seq(-120,180, by = 60)
wm <- map_data("world")
ggplot() +
geom_polygon(data = wm, aes(x = long, y = lat, group = group), fill = "grey", colour = "black", alpha = 0.8) +
# Convert to polar coordinates
coord_map("ortho", orientation = c(-90, 0, 0)) +
scale_y_continuous(limits=c(-90,-60),breaks = seq(-45, -90, by = -5), labels = NULL) +
# Removes Axes and labels
scale_x_continuous(breaks = NULL) +
xlab("") +
ylab("") +
# Adds labels
geom_text(aes(x = -160, y = seq(-55, -85, by = -10), hjust = -0.2, label = paste0(seq(55, 85, by = 10), "°S"))) +
geom_text(aes(x = x_lines, y = -63, label = c("120°W", "60°W", "0°", "60°E", "120°E", "180°W"))) +
# Adds axes
geom_hline(aes(yintercept = -60), size = 1) +
geom_segment(aes(y = -60, yend = -90, x = x_lines, xend = x_lines), linetype = "dashed") +
# Change theme to remove axes and ticks
theme(panel.background = element_blank(),
panel.grid.major = element_line(size = 0.25, linetype = 'dashed',
colour = "black"),
axis.ticks=element_blank()) +
geom_point(data=data, aes(x=Long, y=Lat, color=Sodio))+
scale_color_gradient(low="blue", high="red")
And the code works. Like a charm and kudos to the original user to posting it because it helped me a ton.
The problem is that since all the data are in a small sector (mostly between 85° and 65 °N and between 180° W and 130° W, the one I posted are just a super short dummy set) I was tryig to plot just that "wedge" of the Antarctic continent in order to help me visualize the data more clearly. I could just expland the plot and cut it with photoshop but I need to plot a number of these.
I tried changing the projection to a conic one but it starts doing... extremely weird stuff like trying to peoject the entirety of the world even when I try to put limits in the scale_y_continuous.
Any idea on how to solve this? Also, any idea on how I can add "elevation" lines on the map? I'm working in ggplot because I need to plot some data on top of it afterwards and I'm more familiar with that package of R, but I'm ok with other packages as long as they allow me to plot data on top of it and they can save the plot at 300 dpi...
I have a simple question which I've asked myself many times already. When I am plotting one or more polygons in R using ggplot2, how can I actually change the filling colour? I do not only want to change the outline of the polygon, but the whole thing.
In my first simple plots (ea_map and hb_map) it works fine to assign the colours "yellow" and "purple", however in my final plot "ea_hb_map" (which I've pictured below), the colours are set back to default.
ea <- readOGR("C:/Users/BASELINE/Eastern Arctic/Summer/2010_EA_S/cis_SGRDREA_20100628_pl_a.shp")
hb <- readOGR("C:/Users/BASELINE/Hudson Bay/Summer/2010_HB_S/cis_SGRDRHB_20100628_pl_a.shp")
ea_map <- ggplot() +
geom_polygon(data=ea, aes(x = long, y = lat, group = group), fill = "red")
plot(ea_map)
hb_map <- ggplot() +
geom_polygon(data=hb, aes(x = long, y = lat, group = group), fill = "purple")
plot(hb_map)
ea_df <- tidy(ea)
hb_df <- tidy(hb)
eastern_arctic_map <- ea_map +
geom_sf(data=world, fill = "antiquewhite1") +
coord_sf(xlim = c(-115, -50), ylim = c(50,83), expand = FALSE)+
scale_y_continuous(breaks = c(50, 60, 70, 80)) +
scale_x_continuous(breaks = c(-50, -70, -90, -110)) +
geom_polygon(data = ea_df, aes(x=long, y=lat, group=group, fill="Eastern Arctic"), alpha=0.4) +
labs(fill = "",
x = "lon",
y = "lat") +
theme_grey(base_size = 9) +
theme(legend.key.size = unit(0.8,"line"))
print(eastern_arctic_map)
ea_hb_map <- eastern_arctic_map +
geom_polygon(data=hb_df, aes(x = long, y = lat, group = group, fill = "Hudson Bay"), alpha=0.4)
print(ea_hb_map)
I'm just trying to make a simple study area map that also contains an inset of the state that I am working in (North Carolina). I would like to convert the inset map to a grob object to plot it within the main study area map, then use ggsave to save the map as an image, pdf, etc. I am using shapefiles for my actual map, but I'll show you what I am trying for using map_data:
library(ggplot2)
library(ggmap)
library(maps)
library(mapdata)
library(gridExtra)
library(grid)
# get the NC data:
states <- map_data("state")
nc_df <- subset(states, region == "north carolina")
# study area map:
nc_base <- ggplot() +
geom_polygon(data = nc_df, aes(x = long, y = lat, group = group), fill="grey", color="black") +
coord_fixed(xlim=c(-80, -77.5), ylim=c(33.5, 34.9), ratio = 1.3) +
theme_bw()
nc_base
# inset map:
insetmap<-ggplot() +
geom_polygon(data = nc_df, aes(x = long, y = lat, group = group), fill="grey", color="black") + # get the state border back on top
coord_fixed(ratio = 1.3) +
annotate(geom = "rect", ymax = 34.9, ymin = 33.5, xmax = -77.5, xmin = -80, colour = "red", fill = NA) +
ylab("") +
xlab("") +
theme_nothing()
insetmap
insetmap.grob <- ggplotGrob(insetmap)
final_map <- nc_base + annotation_custom(insetmap.grob, xmin=-79.5, xmax=-79, ymin=33.75, ymax=34)
final_map
When I run the script to produce the final map, only the study area map is produced. I'm wondering if I'm using ggplotGrob incorrectly, or it is something else? I might have read elsewhere that the annotation_custom function does not work unless you are using the coord_cartesian function in ggplot2 (and here I am using coord_fixed). If that is the case, can I zoom in similarly with that function, or is there another coord_ function to zoom in on my study area map?
Thanks,
Jay
I do this kind of thing fairly often and have found that the grid::viewport approach works well...although note that you cannot use ggsave when you are working with multiple viewports as ggsave will only save the last viewport.
Try:
nc_base <- ggplot() +
geom_polygon(data = nc_df, aes(x = long, y = lat, group = group), fill="grey", color="black") +
coord_fixed(xlim=c(-80, -77.5), ylim=c(33.5, 34.9), ratio = 1.3) +
theme_bw()
print(nc_base)
# inset map:
insetmap <- ggplot() +
geom_polygon(data = nc_df, aes(x = long, y = lat, group = group), fill="grey", color="black") + # get the state border back on top
coord_fixed(ratio = 1.3) +
annotate(geom = "rect", ymax = 34.9, ymin = 33.5, xmax = -77.5, xmin = -80, colour = "red", fill = NA) +
ylab("") +
xlab("") +
# used theme_inset instead of theme_nothing
theme_inset()
print(insetmap)
# save where you want to with filename arg in png(). Currently saves 'map.png' to your working directory
# set resolution, width, height
png(filename = "map.png", width = 1150, height = 800, res = 300)
# create a viewport for inset
# vp_inset width/height arguments set the size of the inset; x and y arguments set the position (from 0 to 1) of the left, top corner of the inset along each axis (i.e. not map coordinates as you have in your annotation custom). You can adjust these as you see fit.
vp_inset <- grid::viewport(width = 0.35, height = 0.35, x = 0.2, y = 0.5, just = c("left", "top"))
print(nc_base)
print(insetmap, vp = vp_inset)
dev.off()