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"))
Related
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 am using the windrose function posted here: Wind rose with ggplot (R)?
I need to have the percents on the figure showing on the individual lines (rather than on the left side), but so far I have not been able to figure out how. (see figure below for depiction of goal)
Here is the code that makes the figure:
p.windrose <- ggplot(data = data,
aes(x = dir.binned,y = (..count..)/sum(..count..),
fill = spd.binned)) +
geom_bar()+
scale_y_continuous(breaks = ybreaks.prct,labels=percent)+
ylab("")+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica")
I marked up the figure I have so far with what I am trying to do! It'd be neat if the labels either auto-picked the location with the least wind in that direction, or if it had a tag for the placement so that it could be changed.
I tried using geom_text, but I get an error saying that "aesthetics must be valid data columns".
Thanks for your help!
One of the things you could do is to make an extra data.frame that you use for the labels. Since the data isn't available from your question, I'll illustrate with mock data below:
library(ggplot2)
# Mock data
df <- data.frame(
x = 1:360,
y = runif(360, 0, 0.20)
)
labels <- data.frame(
x = 90,
y = scales::extended_breaks()(range(df$y))
)
ggplot(data = df,
aes(x = as.factor(x), y = y)) +
geom_point() +
geom_text(data = labels,
aes(label = scales::percent(y, 1))) +
scale_x_discrete(breaks = seq(0, 1, length.out = 9) * 360) +
coord_polar() +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
#teunbrand answer got me very close! I wanted to add the code I used to get everything just right in case anyone in the future has a similar problem.
# Create the labels:
x_location <- pi # x location of the labels
# Get the percentage
T_data <- data %>%
dplyr::group_by(dir.binned) %>%
dplyr::summarise(count= n()) %>%
dplyr::mutate(y = count/sum(count))
labels <- data.frame(x = x_location,
y = scales::extended_breaks()(range(T_data$y)))
# Create figure
p.windrose <- ggplot() +
geom_bar(data = data,
aes(x = dir.binned, y = (..count..)/sum(..count..),
fill = spd.binned))+
geom_text(data = labels,
aes(x=x, y=y, label = scales::percent(y, 1))) +
scale_y_continuous(breaks = waiver(),labels=NULL)+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
ylab("")+xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica") +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
I'm trying to make a map with points plotted for the Canadian prairie provinces, but I'm having no luck adding in a legend to my map. I'm very new to mapping in r, so I'm not understanding how I should include aes to get a legend. My data for siteDataTrees is from an excel csv file and the top looks like this:
siteDataTrees
and the data for siteDataBoth is also from a csv file and the top looks like this:
siteDataBoth.
Here's what I have so far for my code:
library(maps)
library(ggplot2)
library(sf)
prairies1 <- map("worldHires","Canada", xlim = c(-120,-87), ylim = c(49,61),
plot = FALSE, fill = TRUE)
prairies <- st_as_sf(prairies1)
ggplot(data = prairies) +
geom_sf() +
geom_point(data = siteDataTrees, aes(x = long, y = lat), size = 2.5, pch = 21,
fill = "purple", show.legend = TRUE) +
geom_point(data = siteDataBoth, aes(x = long, y = lat), size = 2.5, pch = 21,
fill = "light green", show.legend = TRUE) +
geom_text(data = locations, aes(x = long, y = lat, label = name),
size = 2, col = "black", check_overlap = FALSE) +
annotation_scale(location = "tr", width_hint = 0.2) +
ggtitle("Climate Stations and Tree Chronology Locations for South AB") +
labs(x = "latitude", y = "longitude") +
theme(legend.position = "right") +
coord_sf(xlim = c(-115, -110), ylim = c(48.9, 50.49), expand = FALSE)
I've also included a map to show what it looks like without the legend.
How should I take the data frame prairies and use it with aes to include a legend? Is there another way to add in a legend in ggplot2 without using the aes function? Thank you in advance for your help and please let me know if something is missing as this is my first posting
Let me give you a couple of examples on how to work out a legend using a slightly modified example from r-spatial.
First we prepare the data:
library(maps)
library(ggplot2)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
(sites <- data.frame(longitude = c(-80.144005, -80.109),
latitude = c(26.479005,26.83),
type = c("tree", "station")))
Now we plot. Case 1: color is not an issue
ggplot(data = world) +
geom_sf() +
geom_point(data = sites,
aes(x = longitude, y = latitude, fill = type),
size = 4,
shape = 23) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")
Case 2: fill color is an issue.
Here we can use a named vectors to pass the colors and the labels we want by type of point. For example:
mapfill <- c('tree' = "forestgreen", 'station' = "purple")
maplab <- c('tree' = "trees in prairies", 'station' = "Stations in prairies")
Then we plot combining both mapfill and maplab:
ggplot(data = world) +
geom_sf() +
geom_point(data = sites, aes(x = longitude, y = latitude, fill = type), size = 4,
shape = 23) +
scale_fill_manual(values = mapfill, labels = maplab) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")
Remark 1 If you do not want type in the legend title you can either delete it using legend. title = element_blank() within theme
Remark 2 If, instead of fill, you are using color, use function scale_color_manual. If you are combining both fill and color do the same with scale_***_manual
In spirit of full disclosure, if you do not mind the colors and you want a quick fix (and I cannot stress this enough) you can also code fill = "TextYouWantInLegend" within aes. See following example:
ggplot(data = world) +
geom_sf() +
geom_point(data = sites[1,], aes(x = longitude, y = latitude, fill = "toto"), size = 4,
shape = 23) +
geom_point(data = sites[2,], aes(x = longitude, y = latitude, fill = "koko"), size = 4,
shape = 23) +
coord_sf(xlim = c(-88, -78), ylim = c(24.5, 33), expand = FALSE) +
theme(legend.position = "bottom")
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.