I'm trying to figure out how to display my complete map in gglot2 including the island Both r_base and tmap were able to display the islands but ggplot2 couldn't differentiate the island from the rest of the waterbody...
.
My question is how to make the Islands appear in ggplot2?
See the code i used below.
library(ggplot2)
library (rgdal)
library (rgeos)
library(maptools)
library(tmap)
Loading the Persian Gulf shape fill referred to as iho
PG <- readShapePoly("iho.shp")
the shape file is available here
http://geo.vliz.be:80/geoserver/wfs?request=getfeature&service=wfs&version=1.0.0&typename=MarineRegions:iho&outputformat=SHAPE-ZIP&filter=%3CPropertyIsEqualTo%3E%3CPropertyName%3Eid%3C%2FPropertyName%3E%3CLiteral%3E41%3C%2FLiteral%3E%3C%2FPropertyIsEqualTo%3E
plot with r_base
Q<-plot(PG)
Corresponds to figure A
Ploting with tmap
qtm(PG)
Corresponds to figure B
convert to dataframe
AG <- fortify(PG)
Plot with ggplot2
ggplot()+ geom_polygon(data=AG, aes(long, lat, group = group),
colour = alpha("darkred", 1/2), size = 0.7, fill = 'skyblue', alpha = .3)
Corresponds to figure C
You need to tell ggplot you want the holes filled in with a different color..for example:
ggplot()+ geom_polygon(data=AG, aes(long, lat, group = group, fill = hole), colour = alpha("darkred", 1/2), size = 0.7) + scale_fill_manual(values = c("skyblue", "white")) + theme(legend.position="none")
Also try readOGR() function from the rgdal package instead of readShapePoly() it keeps all the projection and datum information when you read the shape file.
Further to #AdamMccurdy's answer:, there are some possibilities to get the same colour for islands and adjacent background.
The first sets the fill colour of the islands and the colour of the background to be the same. But the grid lines are under the polygon, and thus disappear.
The second is an attempt to get the grid lines back. It plots the background (which includes the grid lines) on top of the panel (using panel.ontop = TRUE). But it's a bit of a fiddle adjusting alpha values to get the same background and island colour.
The third sets the background and island colours to be the same (as in the first), then plots the grid lines on top of the panel. There's a couple of ways to do this; here, I grab the grid lines grob from the original plot, then draw them on top of the panel. Thus the colours remain the same, and no need for alpha transparencies.
library(ggplot2)
library (rgdal)
library (rgeos)
library(maptools)
PG <- readOGR("iho.shp", layer = "iho")
AG <- fortify(PG)
Method 1
bg = "grey92"
ggplot() +
geom_polygon(data = AG, aes(long, lat, group = group, fill = hole),
colour = alpha("darkred", 1/2), size = 0.7) +
scale_fill_manual(values = c("skyblue", bg)) +
theme(panel.background = element_rect(fill = bg),
legend.position = "none")
Method 2
ggplot() +
geom_polygon(data = AG, aes(long, lat, group = group, fill = hole),
colour = alpha("darkred", 1/2), size = 0.7) +
scale_fill_manual(values = c("skyblue", "grey97")) +
theme(panel.background = element_rect(fill = alpha("grey85", .5)),
panel.ontop = TRUE,
legend.position = "none")
Method 3
Minor edit updating to ggplot version 3.0.0
library(grid)
bg <- "grey92"
p <- ggplot() +
geom_polygon(data = AG, aes(long, lat, group = group, fill = hole),
colour = alpha("darkred", 1/2), size = 0.7) +
scale_fill_manual(values = c("skyblue", bg)) +
theme(panel.background = element_rect(fill = bg),
legend.position = "none")
# Get the ggplot grob
g <- ggplotGrob(p)
# Get the Grid lines
grill <- g[7,5]$grobs[[1]]$children[[1]]
# grill includes the grey background. Remove it.
grill$children[[1]] <- nullGrob()
# Draw the plot, and move to the panel viewport
p
downViewport("panel.7-5-7-5")
# Draw the edited grill on top of the panel
grid.draw(grill)
upViewport(0)
But this version might be a little more robust to changes to ggplot
library(grid)
bg <- "grey92"
p <- ggplot() +
geom_polygon(data = AG, aes(long, lat, group = group, fill = hole),
colour = alpha("darkred", 1/2), size = 0.7) +
scale_fill_manual(values = c("skyblue", bg)) +
theme(panel.background = element_rect(fill = bg),
legend.position = "none")
# Get the ggplot grob
g <- ggplotGrob(p)
# Get the Grid lines
grill <- getGrob(grid.force(g), gPath("grill"), grep = TRUE)
# grill includes the grey background. Remove it.
grill = removeGrob(grill, gPath("background"), grep = TRUE)
# Get the name of the viewport containing the panel grob.
# The names of the viewports are the same as the names of the grobs.
# It is easier to select panel's name from the grobs' names
names = grid.ls(grid.force(g))$name
match = grep("panel.\\d", names, value = TRUE)
# Draw the plot, and move to the panel viewport
grid.newpage(); grid.draw(g)
downViewport(match)
# Draw the edited grill on top of the panel
grid.draw(grill)
upViewport(0)
Related
I have data where each point lays on a spectrum between two centroids. I have generated a color for each point by specifying a color for each centroid, then setting the color of each point as a function of its position between its two centroids. I used this to manually specify colors for each point and plotted the data in the following way:
lb.plot.dat <- data.frame('UMAP1' = lb.umap$layout[,1], 'UMAP2' = lb.umap$layout[,2],
'sample' = as.factor(substr(colnames(lb.vip), 1, 5)),
'fuzzy.class' = color.vect))
p3 <- ggplot(lb.plot.dat, aes(x = UMAP1, y = UMAP2)) + geom_point(aes(color = color.vect)) +
ggtitle('Fuzzy Classification') + scale_color_identity()
p3 + facet_grid(cols = vars(sample)) + theme(legend.) +
ggsave(filename = 'ref-samps_bcell-vip-model_fuzzy-class.png', height = 8, width = 16)
(color.vect is the aforementioned vector of colors for each point in the plot)
I would like to generate a legend of this plot that gives the color used for each centroid. I have a named vector class.cols that contains the colors used for each centroid and is named according to the corresponding class.
Is there a way to transform this vector into a legend for the plot even though it is not explicitly used in the plotting call?
You can turn on legend drawing in scale_color_identity() by setting guide = "legend". You'll have to specify the breaks and labels in the scale function so that the legend correctly states what each color represents, and not just the name of the color.
library(ggplot2)
df <- data.frame(x = 1:3, y = 1:3, color = c("red", "green", "blue"))
# no legend by default
ggplot(df, aes(x, y, color = color)) +
geom_point() +
scale_color_identity()
# legend turned on
ggplot(df, aes(x, y, color = color)) +
geom_point() +
scale_color_identity(guide = "legend")
Created on 2019-12-15 by the reprex package (v0.3.0)
Problem
Greetings, I'm trying to plot a map with a dark background using ggplot2 by setting the theme() parameter plot.background to e.g. element_rect(fill = "#000000") but switching from the cartesian coordinate system to a map projection using coord_map() introduces white margins which can only be removed by adjusting the size of the plot to the same ratio as the map area.
How can I remove this margin and apply the fill colour specified using the plot.background parameter to the whole plot regardless of its ratio?
MWE
nz <- map_data("nz")
ggplot(nz, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", colour = "black") +
coord_map() +
theme_void() +
theme(plot.background = element_rect(fill = "#000000"))
Output
Expected output
Update
After about two hours of trying different approaches and wondering how R plotting and especially ggplot2 can be so incredibly clumsy, I finally found a solution here but it requires another library and additional steps to produce this conceptually elementary adjustment which should really be the default in the first place so there surely must be a native solution… right? 😓
There is a solution with the grid package, which is the package ggplot2 uses to draw the plots. First, I would make the small adjustment to your plotting code by also setting the plot background colour to black:
g <- ggplot(nz, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", colour = "black") +
coord_map() +
theme_void() +
theme(plot.background = element_rect(fill = "#000000", colour = "#000000"))
Next we convert the g to a gtable and draw it with the grid package:
library(grid)
gt <- ggplotGrob(g)
grid.newpage()
# Draw a black rectangle
grid.draw(rectGrob(gp = gpar(fill = "#000000")))
grid.draw(gt)
The problem is that many coord-functions set a fixed aspect ratio for the plot, which will in turn affect other plot elements that are defined in absolute dimensions.
Is it possible to get these two maps side by side, with the same height, in one png image? The two images should be separated by minimal but appropriate space, as shown below. I am receptive to other solutions, especially ggmap.
I tried par(mar=... (and also mai) to reduce margin size but that did not seem to affect size or space between the two maps. I also used cex = 1.8 in the second par() function (for the state) which makes the height of the two maps similar but spaces them even farther apart.
When I save the file as PDF, I get each map on a separate page. When I try png, I get only the Missouri map.
MWE:
library(maps)
op <- par(mfrow=c(1,2))
png(file = "maps.png", width = 1000, height = 400)
par(mar=c(0,0,0,0))
map('state')
map('state', 'missouri', add = TRUE, fill = TRUE)
map('state', c('mississippi', 'alabama', 'north carolina', 'florida'), add = TRUE, fill = TRUE, col = "gray")
par(mar=c(0,0,0,0))
map('county', 'missouri')
map('county', 'missouri,scott', add=TRUE, fill=TRUE)
dev.off()
par(op)
Desired result:
The par options are specific to the active "graphic device" at that moment. To demonstrate:
Try this, starting with "normal" (non-file) graphics.
par(mfrow=1:2)
par('mfrow')
# [1] 1 2
png("maps.png")
par('mfrow')
# [1] 1 1
dev.off()
# windows
# 2
par('mfrow')
# [1] 1 2
I didn't close the previous plain-graphics-window, so once I closed the png device, the previously-active window became active again. And it was still thinking mfrow=1:2.
So I think your answer is this, where the only change is the order of png, par(mfrow=1:2).
png(file = "maps.png", width = 1000, height = 400)
op <- par(mfrow=c(1,2))
par(mar=c(0,0,0,0))
map('state')
map('state', 'missouri', add = TRUE, fill = TRUE)
map('state', c('mississippi', 'alabama', 'north carolina', 'florida'), add = TRUE, fill = TRUE, col = "gray")
par(mar=c(0,0,0,0))
map('county', 'missouri')
map('county', 'missouri,scott', add=TRUE, fill=TRUE)
dev.off()
par(op)
Inspired by #Andres comment, I developed a ggplot2 version that places the two maps side by side using patchwork. I found it easier for me to use geom_polygon instead of converting the maps to sf objects.
library(maptools)
library(ggplot2)
library(ggthemes) # for Tufte theme
library(patchwork)
# remove the unneeded ink not removed by
# theme_tufte()
theme_tufte_empty <- function(){
theme(axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks.length = unit(0, "cm"))
}
usa <- map_data("state")
us_missouri <- map_data('state','missouri') #do similar for other states
us_map <- ggplot() +
geom_polygon(data = usa, aes(x=long, y = lat, group = group), fill = NA, color = "black") +
geom_polygon(data = us_missouri, aes(x = long, y = lat, group = group), fill = "black") +
theme_tufte() + # quickly remove most ink
theme_tufte_empty() +
coord_fixed(1.3)
missouri <- map_data("county", "missouri")
mo_scott <- map_data("county", "missouri,scott")
mo_map <- ggplot() +
geom_polygon(data = missouri, aes(x=long, y = lat, group = group), fill = NA, color = "black") +
geom_polygon(data = mo_scott, aes(x = long, y = lat, group = group), fill = "black") +
theme_tufte() +
theme_tufte_empty() +
coord_fixed(1.3)
us_map + mo_map + plot_layout(ncol = 2, widths = c(1.5,1))
I want to set custom shape, size and color for points added to a map based upon a variable called 'Dataset'. I'm able to set the color of the points if I set the shape to the same type for all the points, but I'm hoping to have a map with a little more information. When I runt this code, all the points are circles colored black. What am I missing?
Thanks everyone for your help & time!!
Here's a reproducible example:
# Read in libraries
library(ggplot2)
library(maps)
library(maptools)
library(ggmap)
# Create mapping objects
world <- map_data("world2")
world$long <- world$long
state_dat <- map_data("state")
canada <- world[world$region==c("Canada"),]
map_dat <- rbind(state_dat, canada)
# Create custom shapes, sizes, colors
pt_colors=c("red", "blue", "grey", "green")
shapes = c(120, 22, 24, 21)
shape_size = c(1.1, 0.8, 1, 1)
# Create lat/long dataframe
xy <- data.frame(Dataset=c("GBIF","Flower","GBIF","Leaf","DNA","GBIF","GBIF","Leaf","GBIF","GBIF","DNA","GBIF","DNA","GBIF","GBIF","Leaf","GBIF","GBIF","GBIF","DNA"),
lat=c(38.89450,34.45300,39.86556,30.38818,28.74590,33.78527,41.23439,30.37935,41.38250,40.60648,30.87580,40.56425,28.75000,41.52666,35.46451,30.73621,38.50221,33.70335,38.98000,29.61100),
long=c(-77.06292,-84.22643,-79.50248,-84.64519,-81.47860,-84.37109,-81.46374,-86.17667,-72.10861,-74.53538,-84.41520,-74.86654,-81.47750,-73.15833,-78.89952,-86.73095,-78.40308,-86.70289,-77.03917,-81.78740)
)
# Create base map
p0 <- ggplot() +
geom_polygon(data=map_dat,aes(x=long,y=lat,group=group, fill=region),fill="white",color="black", show.legend=FALSE)+
coord_map("gilbert",xlim=c(-60,-97),ylim=c(15,47.5)) +#mollweide is pretty good
labs(x=expression("Longitude"*~degree*W), y=expression("Latitude"*~degree*N)) +
theme(panel.border = element_rect(colour = "black", fill=NA, size=1),
plot.margin=unit(c(0.25,0.25,0.25,0.25),'inches'),
legend.position='none') +
theme(rect = element_blank())
# Add points to the map
p1 <- p0 +
geom_point(data=xy,aes(x=long,y=lat,fill=Dataset)) +
scale_color_manual(values=pt_colors) +
scale_shape_manual(values=shapes) +
scale_size_manual(values=shape_size)
You need to have colour, shape, and size within your geom_point aesthetic values. Geom_point doesn't use fill as an aesthetic, but uses colour.
Simply fixing that will generate what you want.
p1 <- p0 +
geom_point(data=xy,aes(x=long,y=lat,colour = Dataset, shape = Dataset, size = Dataset)) +
scale_color_manual(values=pt_colors) +
scale_shape_manual(values=shapes) +
scale_size_manual(values=shape_size)
I am now plotting the map of Canada using ggplot2. Because the default projection method is "aea"(Albers Equal Area), so the longitude and latitude are straight lines on the map. I wonder how I can display the longitude and latitude in the form of "110W, 100W, 90W" and "50N, 60N, 70N" on the map. They should be curves. Thanks a lot.
The arcgis shapfile is downloaded from https://www.arcgis.com/home/item.html?id=dcbcdf86939548af81efbd2d732336db
library(ggplot2)
library(rgdal)
countries<-readOGR("Canada.shp", layer="Canada")
ggplot()+geom_polygon(data=countries,aes(x=long,y=lat,group=group),fill='white',color = "black")
The final result should be like this.
You can do this with the coord_map argument of ggplot documented here
This uses projections to alter the coordinate grid. Curved lines would include equal-distance projections, but you should look here for a list of all projections allowed. Which one you choose is a manner of preference.
Using azequidistant (I think this is the Azimuthal equidistant projection), and adding labels manually:
axis_labels <- rbind(
data.frame(long = rep(-140,5),lat = seq(40,80,10), labels = seq(40,80,10)), # x axis labels
data.frame(long = seq(-140,-60,40),lat = rep(85,3), labels = seq(140,60,-40)) # y axis labels
)
ggplot() +
geom_polygon(data=countries,aes(x=long,y=lat,group=group),fill='white',color = "black") +
coord_map("azequidistant") +
scale_x_continuous(breaks = seq(-140,60, by = 20))+
scale_y_continuous(breaks = seq(40,80, by = 10)) +
geom_text(data = axis_labels, aes(x = long, y = lat, label = labels)) +
theme_bw() +
theme(panel.grid.major = element_line(colour = "grey"),
panel.border = element_blank(),
axis.text = element_blank())
You can use a separate graticule layer of spatial data, which you then project based on your Canada layer.
You can find free graticule layers for download at NaturalEarthData.
countries<-readOGR("Canada.shp", layer="Canada")
grat <- readOGR("graticule.shp", layer="graticule")
grat_prj <- spTransform(grat, CRS(countries))
ggplot() +
geom_polygon(data=countries, aes(x=long,y=lat,group=group),fill='white',color = "black") +
geom_path(data=grat_prj, aes(long, lat, group=group, fill=NULL), linetype="solid", color="grey50")