Remove countries' political borders from ggplot2 map - ggplot2

I need to remove the political borders of the countries from the following ggplot2 map:
library(ggplot2)
world = map_data('world')
plot=ggplot() +
geom_polygon(data=world, aes(x=long, y=lat, group=group), fill='NA', color='black', size=0.2)
print(plot)
Any suggestion on how I can do this?
Thanks

There are two workarounds to your question:
First workaround: Using maps instead of ggplot2
library(maps)
world <- maps::map("world", fill=FALSE, plot=TRUE, interior = FALSE)
Which results in:
Second workaround: Using maps and ggplot2
library(maps)
library(magrittr)
library(maptools)
library(raster)
library(ggplot2)
#Defining a general CRS
mycrs <- "+proj=longlat +datum=WGS84 +no_defs"
#Using the original maps package, then converting map into SpatialPolygons object
world <- maps::map("world", fill=TRUE) %$%
maptools::map2SpatialPolygons(., IDs=names,proj4string=CRS(mycrs))
#The resulting map has self intersection problems so any further operation reports errors; using buffers of width 0 is a fast fix
while(rgeos::gIsValid(world)==FALSE){
world <- rgeos::gBuffer(world, byid = TRUE, width = 0, quadsegs = 5, capStyle = "ROUND")
}
#Dissolving polygon's limits
world <- raster::aggregate(world)
#Plotting. I add theme_void to your code to erase any axis, etc
ggplot() +
geom_polygon(data = world, aes(x=long, y=lat, group=group), fill='NA', color='black', size=0.2)+
theme_void()
The result:
Hope it helps

The rnaturalearth package offers an easier way to make world maps in ggplot2 now.
library(ggplot2)
library(rnaturalearth)
#Mapping for coastlines
coast <- ne_coastline(scale = "small", returnclass = "sf")
ggplot(data = coast) + geom_sf() + theme_classic()
#Optional - apply a fill to the continents
world <- ne_countries(scale = "small", returnclass = "sf")
ggplot(data = world) +
geom_sf(color = "#E5E5E5", fill = "#E5E5E5") +
geom_sf(data = coast) + theme_classic()

Related

How to outline a histogram with a color and add a bell curve on ggplot2

I have been trying to add a bell curve to my histogram an outline it with a color so that it is more pleasing. enter image description here
I have added what my histogram looks like to give someone an idea on what I am working with, also here is my code thus far, thank you in advance.
ggplot(data = mammal.data.22.select2)+
geom_histogram(aes(x=Time, fill=Species))+
scale_fill_manual(values=c("paleturquoise4", "turquoise2"))+
facet_wrap(~Species, nrow=1)+
ylab("Observations")+
xlab("Time of Day")+
theme(strip.text.x = element_blank())
Let's build a histogram with a build-in dataset that seems similar-ish to your data structure.
library(ggplot2)
binwidth <- 0.25
p <- ggplot(iris, aes(Petal.Length)) +
geom_histogram(
aes(fill = Species),
binwidth = binwidth,
alpha = 0.5
) +
facet_wrap(~ Species)
You can use stat_bin() + geom_step() to give an outline to the histogram, without colouring the edge of every rectangle in the histogram. The only downside is that the first and last bins don't touch the x-axis.
p + stat_bin(
geom = "step", direction = "mid",
aes(colour = Species), binwidth = binwidth
)
To overlay a density function with a histogram, you could calculate the relevant parameters yourself and use stat_function() with fun = dnorm repeatedly. Alternatively, you can use ggh4x::stat_theodensity() to achieve a similar thing. Note that whether you use stat_function() or stat_theodensity(), you should scale the density back to the counts that your histogram uses (or scale histogram to density). In the example below, we do that by using after_stat(count * binwidth).
p + ggh4x::stat_theodensity(
aes(colour = Species,
y = after_stat(count * binwidth))
)
Created on 2022-04-15 by the reprex package (v2.0.1)
(disclaimer: I'm the author of ggh4x)

Why do some xlims and ylims produce this error in ggplot and sf?

I am learning to use ggplot with spatial data using sf.
When I try to produce the following plot I get an error:
library(sf)
library(ggplot2)
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf")
ggplot(data = world) +
geom_sf() +
coord_sf(xlim = c(-102.15, -74.12), ylim = c(0, 33.97), expand = FALSE)
# Error in st_cast.POINT(x[[1]], to, ...) :
# cannot create MULTILINESTRING from POINT
However, if I just very slightly adjust the ylims in either direction, it works!:
ggplot(data = world) +
geom_sf() +
coord_sf(xlim = c(-102.15, -74.12), ylim = c(0.01, 33.97), expand = FALSE)
or
ggplot(data = world) +
geom_sf() +
coord_sf(xlim = c(-102.15, -74.12), ylim = c(-0.01, 33.97), expand = FALSE)
So that's a fine if rather hacky solution, but I am wondering what the issue is? On the final plot, I notice a little islands creeping into the map (the galapagos?)
Is the tip of this polygon somehow interfering with the first piece of code by looking like a point rather than a polygon? Or is something else going on, and how can I address is a bit more elegantly?
I don't believe that the problem you describe is caused by the Galapagos - as it is present at scale = "small" which omits these islands.
I have tried another source of the world country dataset (the one from natural earth is not spherically valid, so I wanted to rule this issue out). The error remains, and now I suspect it has something to do with the code in {ggplot2} - specifically in how it handles the equator (i.e. zero) as a limit when the default expand = TRUE is overriden by user (it might be worth filing an issue at their github).
In the meantime I suggest two possible approaches:
crop your area of interest outside of your ggplot call (this may be preferable for a variety of reasons - see ggplot2 and sf: geom_sf_text within limits set by coord_sf)
avoid the expand = FALSE in your coord_sf() call
For cropping of your world object at data level (and not at presentation level in your ggplot call) consider this code:
library(sf)
library(ggplot2)
library(rnaturalearth)
library(rnaturalearthdata)
world <- ne_countries(scale = "medium", returnclass = "sf") %>%
st_make_valid()
bounds <- matrix(c(-102.15, 0,
-74.12, 0,
-74.12, 33.97,
-102.15, 33.97,
-102.15, 0),
byrow = TRUE, ncol = 2) %>%
list() %>%
st_polygon() %>%
st_sfc(crs = 4326)
small_world <- st_intersection(world, bounds)
ggplot(data = small_world) +
geom_sf()

Add space argument to facet_wrap

facet_wrap() has been recognized for not having a space = "free" argument (https://github.com/tidyverse/ggplot2/issues/2933). This can causes spacing issues on the y-axis of plots.
Create the above figure using the following code:
library(tidyverse)
p <-
mtcars %>%
rownames_to_column() %>%
ggplot(aes(x = disp, y = rowname)) + geom_point() +
facet_wrap(~ carb, ncol = 1, scales = "free_y")
facet_grid on the other hand has a space = "free" argument. Allowing for nice y-axis spacing.
Create the above figure using the following code:
p <-
mtcars %>%
rownames_to_column() %>%
ggplot(aes(x = disp, y = rowname)) + geom_point() +
facet_grid(carb ~ ., scales = "free_y", space = "free_y")
The issue with this is that the label is on the side, not the top. I sometimes have longer facet labels and few rows in the facet. This means the facet label gets cut off.
There is a solution from the ggforce package (comment by ilarischeinin on https://github.com/tidyverse/ggplot2/issues/2933).
p <-
mtcars %>%
rownames_to_column() %>%
ggplot(aes(x = disp, y = rowname)) + geom_point()
p + ggforce::facet_col(vars(carb), scales = "free_y", space = "free")
But, there are limitations leaving ggplot2. For example, I ultimately want a two column figure, and this functionality does not seem possible with ggforce. Is there any way to produce the same result using facet_wrap() so that I can utilize the ncol() argument?
Here is a potential workaround based on https://stackoverflow.com/a/29022188/12957340 :
library(tidyverse)
library(gtable)
library(grid)
p1 <- mtcars %>%
rownames_to_column() %>%
ggplot(aes(x = disp, y = rowname)) + geom_point() +
facet_grid(carb ~ ., scales = "free_y", space = "free_y") +
theme(panel.spacing = unit(1, 'lines'),
strip.text.y = element_text(angle = 0))
gt <- ggplotGrob(p1)
panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
for(i in rev(panels$t-1)) {
gt = gtable_add_rows(gt, unit(0.5, "lines"), i)
}
panels <-c(subset(gt$layout, grepl("panel", gt$layout$name), se=t:r))
strips <- c(subset(gt$layout, grepl("strip-r", gt$layout$name), se=t:r))
stripText = gtable_filter(gt, "strip-r")
for(i in 1:length(strips$t)) {
gt = gtable_add_grob(gt, stripText$grobs[[i]]$grobs[[1]], t=panels$t[i]-1, l=5)
}
gt = gt[,-6]
for(i in panels$t) {
gt$heights[i-1] = unit(0.8, "lines")
gt$heights[i-2] = unit(0.2, "lines")
}
grid.newpage()
grid.draw(gt)
Created on 2021-12-15 by the reprex package (v2.0.1)
It's not clear to me what you mean by "I ultimately want a two column figure", but if you can come up with an example to illustrate your 'ultimate' expected outcome I can try to adapt this approach and see if it will work or not.

ggplot grobs align with tableGrob

I'm having difficulty to find solution for aligning ggplot grob and table grob. I tried to follow the instruction here but still didn't give the results I wanted.
library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col
plot1 <- ggplot(dat, aes(car, mpg)) +
geom_bar(stat = "identity") +
coord_flip()
g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl)
g1 <- gtable_add_cols(g1, unit(0.2, "npc"))
g1 <- gtable_add_grob(g1, grobs = tb1, t=3, l=ncol(g1), b=6, r=ncol(g1))
grid.newpage()
grid.draw(g1)
I would like that each cell in the table be aligned to related bar in histogram, but still couldn't understand how the t,l,b,r be implemented from the layout.This is the output I got
I had a similar question as above when trying to make something like a forestplot in R using ggplot2 and didn't find any of the other solutions fit my needs. The answer above didn't work for me - the table didn't show up. So I hacked together a codewise not that pretty solution, but I actually kind of like the cleanliness visual output.
The things I like about this solution are:
I aligned a set of custom text not in a table, but just in a figure on the right, where the alignment matched for each text entry and each label in the figure.
I used a centered ggtitle to align a "column heading" above each set of text. These could be strings of any kind (in my actual use, I had point estimates and confidence intervals).
library(gridExtra)
library(ggplot2)
dat <- data.frame(
label = c("A", "B", "C"),
point_est = c(1,2,3),
lb_ci = c(.5, 1.5, 2.5),
ub_ci = c(1.5, 2.5, 3.5),
n = c(50, 100, 150),
total = c(75, 150, 200)
)
plot1 <- ggplot(dat, aes(x=point_est, y=label)) +
geom_point() +
geom_errorbarh(aes(xmin=lb_ci, xmax=ub_ci), height=.5) +
ggtitle("Some measure") +
ylab(NULL) + xlab("some effect estimate")
tab_base <- ggplot(dat, aes(y=label)) +
ylab(NULL) + xlab(" ") +
theme(plot.title = element_text(hjust = 0.5, size=12), ## centering title on text
axis.text.x=element_text(color="white"), ## need text to be printed so it stays aligned with figure but white so it's invisible
axis.line=element_blank(),
axis.text.y=element_blank(),axis.ticks=element_blank(),
axis.title.y=element_blank(),legend.position="none",
panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),plot.background=element_blank())
tab1 <- tab_base +
geom_text(aes(x=1, label=n)) +
ggtitle("n")
tab2 <- tab_base +
geom_text(aes(x=1, label=total)) +
ggtitle("total")
lay <- matrix(c(1,1,1,1,1,1,2,3), nrow=1)
grid.arrange(plot1, tab1, tab2, layout_matrix = lay)
By default the cell heights have absolute sizes to accommodate the text, but you can change them to relative units so that they scale with the plot panel,
library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col
plot1 <- ggplot(dat, aes(car, mpg)) +
geom_bar(stat = "identity") +
coord_flip()
g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl, theme = ttheme_default(10))
tb1$heights = unit(rep(1/(nrow(tb1)), nrow(tb1)), "npc")
tb1$widths = unit.pmax(tb1$widths, unit(2, "lines"))
g1 <- gtable_add_cols(g1, sum(tb1$widths))
g1 <- gtable_add_grob(g1, grobs = tb1, t=6, l=ncol(g1), b=6, r=ncol(g1))
grid.newpage()
grid.draw(g1)

ggplot plotly API mess width stack bar graph

I am using plotly library to get me HTML interactive graph, which i already generating from ggplot2, but with stacked graph, plotly doesnt work properly.
Here is my ggplot code :
if(file.exists(filename)) {
data = read.table(filename,sep=",",header=T)
} else {
g <- paste0("=== [E] Error : Couldn't Found File : ",filename)
print (g)
}
ReadChData <- data[data$Channel %in% c("R"),]
#head(ReadChData,10)
# calculate midpoints of bars (simplified using comment by #DWin)
Data <- ddply(ReadChData, .(qos_level),
transform, pos = cumsum(AvgBandwidth) - (0.5 *AvgBandwidth)
)
# library(dplyr) ## If using dplyr...
# Data <- group_by(Data,Year) %>%
# mutate(pos = cumsum(Frequency) - (0.5 * Frequency))
# plot bars and add text
g <- ggplot(Data, aes(x = qos_level, y = AvgBandwidth)) +
scale_x_continuous(breaks = x_axis_break) +
geom_bar(aes(fill = MasterID), stat="identity", width=0.2) +
scale_colour_gradientn(colours = rainbow(7)) +
geom_text(aes(label = AvgBandwidth, y = pos), size = 3) +
theme_set(theme_bw()) +
ylab("Bandwidth (GB/s)") +
xlab("QoS Level") +
ggtitle("Qos Compting Stream")
png(paste0(opt$out,"/",GraphName,".png"),width=6*ppi, height=6*ppi, res=ppi)
print (g)
library(plotly)
p <- ggplotly(g)
#libdir arugumet will be use to point to commin lib
htmlwidgets::saveWidget(as.widget(p), selfcontained=FALSE, paste0(opt$out,"/qos_competing_stream.html"))
and here is HTML output form plotly lib
http://pasteboard.co/2fHQfJwFu.jpg
Please help.
This is perhaps quite a bit late to answer. But for someone who might have the issue in future...
The geom_bar's width parameter is not recognized by ggplotly function.
Work Around :
A work around (not very good one) by using parameters colour="white", size = 1. This basically adds a white line around the bars, making an effect like white space.
You could try the following:
stat_summary(aes(fill = MasterID), geom="bar", colour="white", size = 1, fun.y = "sum", position = "stack")
Better solution :
Use bargap parameter from layout function. The code should be:
ggplotly(type='bar', ...) %>% layout(bargap = 3, autosize=T)
P.S. the code in question code is not executable, throws an error due to missing filename.