ggplot2 barplot with dual Y-axis and error bars - r

I am trying to generate a barplot with dual Y-axis and error bars. I have successfully generated a plot with error bars for one variable but I don't know how to add error bars for another one. My code looks like this. Thanks.
library(ggplot2)
#Data generation
Year <- c(2014, 2015, 2016)
Response <- c(1000, 1100, 1200)
Rate <- c(0.75, 0.42, 0.80)
sd1<- c(75, 100, 180)
sd2<- c(75, 100, 180)
df <- data.frame(Year, Response, Rate,sd1,sd2)
df
# The errorbars overlapped, so use position_dodge to move them horizontally
pd <- position_dodge(0.7) # move them .05 to the left and right
png("test.png", units="in", family="Times", width=2, height=2.5, res=300) #pointsize is font size| increase image size to see the key
ggplot(df) +
geom_bar(aes(x=Year, y=Response),stat="identity", fill="tan1", colour="black")+
geom_errorbar(aes(x=Year, y=Response, ymin=Response-sd1, ymax=Response+sd1),
width=.2, # Width of the error bars
position=pd)+
geom_line(aes(x=Year, y=Rate*max(df$Response)),stat="identity",color = 'red', size = 2)+
geom_point(aes(x=Year, y=Rate*max(df$Response)),stat="identity",color = 'black',size = 3)+
scale_y_continuous(name = "Left Y axis", expand=c(0,0),limits = c(0, 1500),breaks = seq(0, 1500, by=500),sec.axis = sec_axis(~./max(df$Response),name = "Right Y axis"))+
theme(
axis.title.y = element_text(color = "black"),
axis.title.y.right = element_text(color = "blue"))+
theme(
axis.text=element_text(size=6, color = "black",family="Times"),
axis.title=element_text(size=7,face="bold", color = "black"),
plot.title = element_text(color="black", size=5, face="bold.italic",hjust = 0.5,margin=margin(b = 5, unit = "pt")))+
theme(axis.text.x = element_text(angle = 360, hjust = 0.5, vjust = 1.2,color = "black" ))+
theme(axis.line = element_line(size = 0.2, color = "black"),axis.ticks = element_line(colour = "black", size = 0.2))+
theme(axis.ticks.length = unit(0.04, "cm"))+
theme(plot.margin=unit(c(1,0.1,0.1,0.4),"mm"))+
theme(axis.title.y = element_text(margin = margin(t = 0, r = 4, b = 0, l = 0)))+
theme(axis.title.x = element_text(margin = margin(t = 0, r = 4, b = 2, l = 0)))+
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank())+
ggtitle("SRG3")+
theme(legend.position="top")+
theme( legend.text=element_text(size=4),
#legend.justification=c(2.5,1),
legend.key = element_rect(size = 1.5),
legend.key.size = unit(0.3, 'lines'),
legend.position=c(0.79, .8), #width and height
legend.direction = "horizontal",
legend.title=element_blank())
dev.off()
and my plot is as follows:

A suggestion for future questions: your example is far from being a minimal reproducible example. All the visuals an the annotations are not related to your problem but render the code overly complex which makes it harder for others to work with it.
The following would be sufficient:
ggplot(df) +
geom_bar(aes(x = Year, y = Response),
stat = "identity", fill = "tan1",
colour = "black") +
geom_errorbar(aes(x = Year, ymin = Response - sd1, ymax = Response + sd1),
width = .2,
position = pd) +
geom_line(aes(x = Year, y = Rate * max(df$Response)),
color = 'red', size = 2) +
geom_point(aes(x = Year, y = Rate * max(df$Response)),
color = 'black', size = 3)
(Notice that I've removed stat = "identity" in all geom_s because this is set by default. Furthermore, y is not a valid aestetic for geom_errorbar() so I omitted that, too.)
Assuming that the additional variable you would like to plot error bars for is Rate * max(df$Response)) and that the relevant standard deviation is sd2, you may simply append
+ geom_errorbar(aes(x = Year, ymin = Rate * max(df$Response) - sd2,
ymax = Rate * max(df$Response) + sd2),
colour = "green",
width = .2)
to the code chunk above. This yields the output below.

Related

ggplot: Modify histogram plot

I made this plot using the following code:
ggplot(all, aes(x = year, color = layer)) +
geom_histogram(binwidth = 0.5, fill = "white", alpha = 0.5, position = "dodge") +
scale_x_continuous(breaks = pretty(all$year)) +
scale_color_discrete(name = "title", labels = c("A","B")) +
theme_light() +
theme(panel.grid.minor = element_blank(), panel.grid.major = element_blank(),
text = element_text(size = 20),
axis.title.x = element_text(margin = margin(t = 25, r = 0, b = 0, l = 0)),
axis.title.y = element_text(margin = margin(t = 0, r = 25, b = 0, l = 0)),
axis.text.x = element_text(angle = 50, hjust = 1, size = 18, color = "black"),
axis.text.y = element_text(size = 18, color = "black"))
I would now like to change the colors first, using colors from the viridis palette. Furthermore, there are blue and red strokes between the histograms, which I would like to remove.
Could someone help me to change the code?
Thanks in advance!
Test Data:
year <- runif(10, 2014, 2021)
year <- round(year, 0)
layer <- sample(c("A","B"), size=10, replace=T)
all <- as.data.frame(year,layer)
Seems like you want a bar plot not a histogram.
all <- data.frame(year,layer) ## fix the sample data creation
ggplot(all, aes(x = year, fill = layer)) + ## I think fill looks better...
geom_bar(position = position_dodge(preserve = "single")) + ## bar, not histogram
#scale_x_continuous(breaks = pretty(all$year)) + ## this line just confirmed defaults
scale_fill_viridis_d() +
theme_light() ## omitted the rest of the theme as irrelevant for the issue at hand
If you do want outline color, not fill, switching to geom_bar "fixes" the strokes between the bars:
ggplot(all, aes(x = year, color = layer)) +
geom_bar(position = position_dodge(preserve = "single"), fill = NA) +
scale_color_viridis_d() +
theme_light()
Thank you, this is helpful information!

How to add polygon in ggplot2 along with raster? Polygon is missing from final plot after ggplot

I have a stack of raster's and suppose to find the mean of it. I have done it. Now, I want to add polygon on the mean of raster image that I got. Then, I wants to save and make it colorful by using ggplot2 code. But I don't understand how to and where add polygon in ggplot2.
fs <- list.files(path="directory.tiff", pattern =
"tif$", full.names = TRUE)
s<- raster::stack(fs)
pg <- readOGR("parks.shp")
se1 <- calc(s, fun = mean)
plot(se1)
plot(pg, add= T )
They give me this attached below picture, Parks overlay on the mean of raster's. Its fine till now.
But when I used ggplot to change its color scheme. They gave me desired pattern what I want, but the problem is parks polygons doesn't overlay on the final picture (attached below after code what I get). So can anyone tell me where I need to change the code in ggplot to get park shp overlay on the picture 2.
conti_col_pal <- pnw_palette("Bay",10,type="continuous")
binary.cols <- c("1" = conti_col_pal[10], "0" = "white")
cv.df <- as.data.frame(rasterToPoints(se1))
##above I give the comand of se1 when I add pg here instead it give me error.
p_cv <- ggplot() +
coord_fixed() +
geom_raster(data = xy_FONDO, aes(lon, lat, fill = r)) +
scale_fill_gradient(low = "gray56", high = "gray56", na.value = NA, guide = FALSE) +
new_scale("fill") +
geom_raster(data = cv.df, aes(x, y, fill = layer))+
scale_fill_gradientn(colours = conti_col_pal,
breaks = seq(-1, 7, 2), limits = c(0, 10))+
annotate(geom = "text", x = lonmin+2, y = latmax-2, vjust = 1, hjust = 0,
label = "",
color = "black", angle = 0, size=4)+
scale_x_continuous(limits = c(lonmin, lonmax), expand = c(0, 0)) +
scale_y_continuous(limits = c(latmin, latmax), expand = c(0, 0))+
theme_bw(base_family="")+
theme(
plot.margin = margin(0, 0, 0, 0, "cm"),
#panel.background = element_rect(fill = col_pal_binary[1], colour = col_pal_binary[1], size
= 0.5, linetype = "solid"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.x=element_blank(),
axis.ticks.y=element_blank(),
legend.background = element_rect(fill=NA, size=0.3, linetype="solid", color=NA),
legend.position = c(0.8, 0.35),
legend.title= element_blank(),
legend.text = element_text(colour = "black", size = 12, angle = 0),
legend.direction = "vertical", ##vertical; horizontal
legend.title.align=0.5)+
guides(fill = guide_colorbar(## label.position = "bottom",
## title.position = "left",
label.vjust=0,
# draw border around the legend
frame.colour = "black",
barwidth = 1.5,
barheight = 8))
tiff(filename = "bay.tiff", res = 600,
width = 4080, height = 3200, compression = "lzw")
grid.arrange(p_cv,
ncol = 1)
dev.off()
After defining the raster "d.f" do same for pg but use function fortify to do and similarly after "geom_raster" do "geom_polygon" to introduce the polygon in ggplot.

Increase Vertical Spacing between Legend Key in ggplot2

How can I increase vertical spacing between legend keys:
p1 <- ggplot(data = HSS, mapping = aes(x = EVENT, y = HSS, fill = TIME)) +
geom_bar(stat = "identity",width=0.7, colour = "black", position = position_dodge(0.7)) +
scale_fill_manual("HSS", values = c("deepskyblue3", "indianred2"),
labels = c("1200 UTC (0.049)", "0000 UTC (0.031)")) + theme_bw()
p1 <- p1 + scale_y_continuous(expand = expansion(mult = c(0.0085, -0.085)),
limits = c(-0.03,0.5), breaks = c(-0.03,-0.01, 0.01, 0.03, 0.05, 0.07,0.09,0.11,0.13,0.15,0.17,
0.19, 0.21,0.23,0.25,0.27,0.29,0.31,0.33,0.45),
labels = c("-0.03","-0.01","0.01","0.03","0.05","0.07","0.09","0.11","0.13","0.15","0.17",
"0.19","0.21","0.23","0.25","0.27","0.29","0.31","0.33","0.45")) +
theme(axis.text.x=element_text(color = "black", size=12, face = "bold", angle=90, vjust=.5,
hjust=0.8)) +
theme(axis.text.y = element_text(color = "black", size=12, face = "bold"))
p1 <- p1 + theme( axis.line = element_line(colour = "black", size = 0.5, linetype = "solid")) +
labs( y = "HSS")
p1 <- p1 + theme(axis.title=element_text(colour = "blue2" ,size=14,face="bold", vjust = 0.1))
p1 <- p1 + theme(legend.position=c(0.98,0.98)) + theme(legend.title=element_blank(),
legend.text = element_text(face = "bold", size = "12"),
legend.box.background = element_rect(size=0.7, linetype="solid"),
legend.justification = c("right", "top"),
legend.box.margin = margin(1, 1, 1, 1)
)
p1
I tried using legend.key.height legend.spacing.y guide but it only stretched legend keys without adding space between them. Also how can I remove alternate lables (encircled) of Y-axis keeping tickmark with plot.
After browsing ggplot2's source code for a bit, I come to the conclusion that the legend.spacing.y is only applied when the byrow = TRUE as argument to the legend.
Simplied example below.
library(ggplot2)
ggplot(iris, aes(Sepal.Width)) +
geom_density(aes(fill = Species)) +
guides(fill = guide_legend(byrow = TRUE)) +
theme(legend.spacing.y = unit(1, "cm"))
With regards to the labels, just remove the values from the breaks argument in scale_y_continuous() that you don't want to show, you're already specifying them manually.

How do I get exact font, line, point and figure sizes in ggplot2?

For a final article submission I have been asked to update my figures so that they meet the following specifications:
axis lines are 0.25 mm
axis lines all around with ticks facing in
data lines are 0.5 mm
font is 10pt
figures should be 80 or 169 mm wide
must be 300 dpi
What I've tried:
library(ggplot2)
library(cowplot)
theme_set(theme_bw())
x <- rnorm(100)
mydata <- data.frame(x = x,
y = x^2 + runif(100),
z = rep(letters[1:4], 25))
p <- ggplot(data = mydata, aes(x, y)) +
geom_point(aes(color = z)) +
geom_smooth(color = 'black', se = FALSE, size = 0.5) +
theme(text = element_text(family = 'Times', size = 10, color = 'black'),
axis.ticks.length = unit(-0.1, 'cm'),
axis.text.x = element_text(margin = margin(t = 4, unit = 'mm')),
axis.text.y = element_text(margin = margin(r = 4, unit = 'mm')),
panel.grid = element_blank(),
axis.line = element_line(size = 0.25),
legend.position = c(0.5, 0.75))
p
ggsave(plot = p,
filename = 'myplot.png',
width = 80, height = 50, dpi = 300, units = 'mm')
p2 <- cowplot::plot_grid(plotlist = list(p, p, p, p), nrow = 1)
ggsave(plot = p2,
filename = 'mymultipleplot.png',
width = 169, height = 50, dpi = 300, units = 'mm')
Which returns the following two plots:
I can figure out how to handle some of the issues here (e.g. legend positions), but am having difficulty with the following:
How can I get ticks around top and right axes?
How can I get the sizes correct ...
These look much bigger than 10 pt. (download them or open in new window to see unscaled version)
The sizes are not maintained in the two figures despite being specified in the theme (font, line).
I don't know how to confirm that the lines are the correct size (in points or mm)... does ggsave do its own scaling?
update For my present task I exported as svg files and edited them in Inkscape. It took a few hours but was easier than getting ggplot to contort to the specifications.
But, it would be helpful to know for the future how to do this programmatically within ggplot2.
Answer to question:
1) as Henrik told in comments:
For question 1 (How can I get ticks around top and right axes?), see the new sec.axis argument in scale_ in ggplot 2.2.0. Try e.g. ggplot(mpg, aes(displ, hwy)) + geom_point() + scale_x_continuous(sec.axis = dup_axis()) + scale_y_continuous(sec.axis = dup_axis())
2) the problem here is that you have the same resolution with different sizes. Since the height of the two figures is the same, you can fix this problem scaling the font size by hand multiplying the font-size with the ratio of the width: e.g.
theme(text = element_text(family = 'Times', size = 10*(80/169), color = 'black')
The whole code should look like this:
library(ggplot2)
library(cowplot)
theme_set(theme_bw())
x <- rnorm(100)
mydata <- data.frame(x = x,
y = x^2 + runif(100),
z = rep(letters[1:4], 25))
p1 <- ggplot(data = mydata, aes(x, y)) +
geom_point(aes(color = z)) + scale_x_continuous(sec.axis = dup_axis()) +
scale_y_continuous(sec.axis = dup_axis()) +
geom_smooth(color = 'black', se = FALSE, size = 0.5) +
theme(text = element_text(family = 'Times', size = 10*(80/169), color = 'black'),
axis.ticks.length = unit(-0.1, 'cm'),
axis.text.x = element_text(margin = margin(t = 4, unit = 'mm')),
axis.text.y = element_text(margin = margin(r = 4, unit = 'mm')),
panel.grid = element_blank(),
axis.line = element_line(size = 0.25),
legend.position = c(0.5, 0.75))
p2 <- ggplot(data = mydata, aes(x, y)) +
geom_point(aes(color = z)) + scale_x_continuous(sec.axis = dup_axis()) +
scale_y_continuous(sec.axis = dup_axis()) +
geom_smooth(color = 'black', se = FALSE, size = 0.5) +
theme(text = element_text(family = 'Times', size = 10, color = 'black'),
axis.ticks.length = unit(-0.1, 'cm'),
axis.text.x = element_text(margin = margin(t = 4, unit = 'mm')),
axis.text.y = element_text(margin = margin(r = 4, unit = 'mm')),
panel.grid = element_blank(),
axis.line = element_line(size = 0.25),
legend.position = c(0.5, 0.75))
p1
ggsave(plot = p1,
filename = 'myplot.png',
width = 80, height = 50, dpi = 300, units = 'mm')
p2multi <- cowplot::plot_grid(plotlist = list(p2, p2, p2, p2), nrow = 1)
ggsave(plot = p2multi ,
filename = 'mymultipleplot.png',
width = 169, height = 50, dpi = 300, units = 'mm')

How to facet two plots side by side using ggplot2 in R

I have small data frame of statistical values obtained from different method. you can download from here.Dataset is look like this:
I need to facet (two plot side by side with same y axis labels) two plot of RMSE.SD and MB variable using ggplot2 package in R like the following example figure.
I wrote this code for plotting 1 plot for RMSE.SD variable.
library(ggplot2)
comparison_korea <- read.csv("comparison_korea.csv")
ggplot(data=comparison_korea, aes(R,X))+
geom_point(color = "black", pch=17, alpha=1,na.rm=T, size=4)+
labs(title = "", y = "")+
theme(plot.title= element_text(hjust = 0.5,size = 15, vjust = 0.5, face= c("bold")),
axis.ticks.length = unit(0.2,"cm") ,
panel.border = element_rect(colour = "black", fill=NA, size=0.5),
axis.text.x = element_text(angle = 0, vjust = 0.5, size = 14, hjust = 0.5,margin=margin(4,0,0,0), colour = "black"),
axis.text.y = element_text(angle = 0, vjust = 0.5, size = 14, hjust = 1,margin=margin(0,5,0,0), colour = "black"),
plot.margin = unit(c(1, 1.5, 1, 0.5), "lines"))
You should be able to do something like this:
library(ggplot2)
ds <- read.csv("comparison_korea.csv")
dat <- data.frame(labels = as.character(ds$X),
RMSE.SD = ds$RMSE.SD,
MB = ds$MB)
dat <- reshape2::melt(dat)
ggplot(dat, aes(y = labels, x = value)) +
geom_point(shape = "+", size = 5) +
facet_wrap(~variable) +
xlab("value / reference (mm)") +
ylab("") +
theme_bw()

Resources