I want to build a world map from the map_data ggplot2 function, and then crop it to a specific extension.
I am trying to build a world map with this extension:
ext <- data.frame(xmin = -10.57514, xmax = 37.21653, ymin = 29.68319, ymax = 73.22486)
The code that I have used is this:
library(ggplot2)
ggplot(map_data("world"), aes(long, lat)) +
geom_polygon(aes(group = group), color = "white", fill = "lightgray", size = 0.2) +
theme_void() +
coord_fixed() +
scale_x_continuous(limits = c(ext$xmin, ext$xmax)) +
scale_y_continuous(limits = c(ext$ymin, ext$ymax))
This results in:
As you can see, the bottom of the plot (i.e, most of North Africa) is not accurate.
How would you fix that? Many thanks 😊
One option is to put the x and y limits into coord_fixed:
library(ggplot2)
ggplot(map_data("world"), aes(long, lat)) +
geom_polygon(aes(group = group),
color = "white",
fill = "lightgray",
size = 0.2) +
theme_void() +
coord_fixed(xlim = c(ext$xmin, ext$xmax),
ylim = c(ext$ymin, ext$ymax))
Output
Related
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 want to plot the raster plot/dataframe on top of the shapefile but I keep getting various errors depending on how I write the code.
I've tried using a + with the finished objects, landmap+critmapped, I've tried adding the codes together and plotting both as data but that didn't work:
I've tried the following, as well as other things...
Thank you for any help/direction.
critmapped<-ggplot(df, aes(x, y, fill = layer)) +
geom_raster() +
scale_fill_viridis_c(na.value = "white") +
labs(fill = "Count") +
theme_minimal() + ggplot() + geom_path(data = land_df, aes(x = long, y = lat, group = group), color = 'black', fill = 'green')
#Error: Don't know how to add ggplot() to a plot
critmapped+landmap2
#Error: Don't know how to add landmap2 to a plot
#The shapefile code
require(rgdal)
land <- readOGR(dsn = "C:/Users/tjef631/Desktop/R Stats/Data/NE_10m_full",
layer = "ne_10m_land")
land_df<-fortify(land)
names(land_df)
landmap<-ggplot() + geom_path(data = land_df, aes(x = long, y = lat, group
= group),
color = 'black', fill = 'green')
landmap
#the raster/dataframe code
critmapped<-ggplot(df, aes(x, y, fill = layer)) +
geom_raster() +
scale_fill_viridis_c(na.value = "white") +
labs(fill = "Count") +
theme_minimal()
critmapped
I came up with a way to plot rivers using geom_path. I do not know if there is a better way. I had to split the dataframe into hundreds of "rivers". So it is very slow. Any ideas?
world_map <- map_data('world')
system("wget https://sites.google.com/site/joabelb/Home/PrincRiosBrazil.zip")
system("unzip -o PrincRiosBrazil.zip")
library(rgdal)
shapeHid <- readOGR(dsn = ".", layer = "PrincipaisRiosDoBrasil")
shapeHid#data$id = rownames(shapeHid#data)
library(ggplot2)
shapeHid.points = fortify(shapeHid, region="id")#
shapeHid.df = merge(shapeHid.points, shapeHid#data, by="id", all=F)
listofrivers<-split(shapeHid.df, shapeHid.df$id)
myMap3 <- ggplot() +
lapply(listofrivers, function(x) geom_path(data=x, aes(x=long, y=lat), color="gray70", linetype=1)) +
geom_map(data = world_map, map = world_map, aes(map_id = region),
color = 'black', fill = NA, linetype=2) +
theme(panel.border = element_rect(fill = NA, colour = "black"))+
theme(axis.title=element_blank())+
scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3
If you routinely work with shapefiles, geom_path and geom_polygon gives everything you need. In recent versions, ggplot deals directly with spatial objects, so there's no need to use fortify and merge (probably the step taking more time in your code). Here's an example using the shapefile of federative units of Brazil from IBGE as base map:
shapeUFs <- readOGR('.', 'BRUFE250GC_SIR')
shapeHid <- readOGR('.', 'PrincipaisRiosDoBrasil')
ggplot(shapeUFs, aes(long, lat, group = group)) +
geom_polygon(fill = 'gray90', color = 'black') +
geom_path(data = shapeHid, color = 'steelblue2') +
coord_map() + theme_void()
Performance will be affected by the size of your shapes (determined by number of features and level of details) more than the geometry you're using in ggplot. You can use rgeos::gSimplify to reduce the number of vertices in a spatial polygon/lines object. You can also plot points directly over the map:
# Simplifying the geometry of the federative units
shapeUFs.s <- rgeos::gSimplify(shapeUFs, .05, TRUE)
# Storing map in an object
riversMap <- ggplot(shapeUFs.s, aes(long, lat)) +
geom_polygon(aes(group = group), fill = 'gray90', color = 'black') +
geom_path(data = shapeHid, aes(group = group), color = 'steelblue2') +
coord_map() + theme_void()
# Sampling 20 cities in Brazil
brMunics <- read.csv('https://raw.githubusercontent.com/kelvins/Municipios-Brasileiros/master/Municipios_Brasileiros.csv')
Munics <- brMunics[sample(nrow(brMunics), 20), ]
# Plotting points over the map
riversMap + geom_point(data = Munics, aes(Longitude, Latitude), color = 'red')
# If your data already have the coordinates named 'lat' and 'long',
# you can skip aes(Longitude, Latitude):
names(Munics)[6:7] <- c('lat','long')
riversMap + geom_point(data = Munics, color = 'red')
I would do the following:
library(sf)
library(ggplot2)
world_map <- map_data('world')
sdf <- read_sf("PrincipaisRiosDoBrasil.shp")
myMap3 <- ggplot() +
geom_map(data = world_map, map = world_map, aes(map_id = region), color = 'black', fill = NA, linetype=2) +
geom_sf(data = sdf)+
theme(panel.border = element_rect(fill = NA, colour = "black"))+
theme(axis.title=element_blank())+
scale_y_continuous(limits=c(-15,6),expand=c(0,0))+
scale_x_continuous(limits=c(-76,-55),expand=c(0,0))
myMap3
You'll need to update ggplot2 to 3.0.0 for geom_sf.
I'm trying to plot the different ways to name a pencil in France on a map with ggplot2. For each of the 96 departments of France, I have one item and a score associated to this item. I have no problem plotting the items according to their departments on a map, but I can't figure out a way to make the colors of each polygons vary according to their associated score. My data is here. The code to produce the map is below:
library(ggplot2)
library(scales)
library(Cairo)
#open data
plotDatafr = read.table("plotDatafr.txt", header=T, sep="\t", quote="", dec=".")
g <- ggplot() +
geom_polygon(data = plotDatafr, aes(x=long, y = lat, group = group, fill=item), alpha=0.8, colour = "black") +
scale_fill_manual(values = c("#009E73", "#F0E442", "#0072B2", "#D55E00"), na.value=NA) +
theme_nothing(legend = TRUE) +
coord_map() #avoid distorsion
ggsave(g, filename = "crayon_euro.png", scale=1) #save for futher use
I tried to use the "scale_fill_distiller" command, but with such command I can only plot the properties of a single item, and I loose their given colors, for example:
g <- ggplot() +
geom_polygon(data = plotDatafr, aes(x = long, y = lat, group = group, fill = score), colour = "black", alpha = 0.8) +
scale_fill_distiller(palette = "Purples", breaks = pretty_breaks(n = 9), labels = percent, direction = 1, "", guide=FALSE) +
guides(fill = guide_legend(reverse = TRUE, override.aes = list(alpha = 1))) +
theme_nothing(legend = TRUE) +
coord_map() #avoid distorsion
ggsave(g, filename = "crayon_euro.png", scale=1) #save for futher use
Does anyone have any idea how I can make the different my polygons shades varying according to their numerical value? I can't figure a way to combine scale_fill_distiller and scale_fill_manual in the same time.
you could use scale_fill_gradient instead to adjust aes(fill) by plotDatafr$score:
#open plotting data
plotDatafr = read.table("plotDatafr.txt", header=T, sep="\t", quote="", dec=".")
# make mapping data object
fr <- map_data("france")
# plot
ggplot(fr, aes(x=long, y = lat, group = group)) +
geom_polygon(data = plotDatafr, aes(fill=score), alpha=0.8, colour = "black") +
scale_fill_gradient(low = "yellow", high = "blue", na.value=NA) +
coord_map()
scale_fill_distiller is designed for discrete data, so you would have to bin plotDatafr$score in some way, before using it.
The answer given by #Haboryme above works perfectly! The trick is to set the alpha with "score" directly in the aes() of geom_polygon, that is to say:
ggplot() + geom_polygon(data = plotDatafr, aes(x = long, y = lat, group = group, fill = item, alpha = score), colour = NA) + scale_fill_manual(values = c("#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"), name = "", na.value=NA) + coord_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()