Extract slope of multiple trend lines from geom_smooth() - r

I am trying to plot multiple trend lines (every ten years) in a time series using ggplot.
Here's the data:
dat <- structure(list(YY = 1961:2010, a = c(98L, 76L, 83L, 89L, 120L,
107L, 83L, 83L, 92L, 104L, 98L, 91L, 81L, 69L, 86L, 76L, 85L,
86L, 70L, 81L, 77L, 89L, 60L, 80L, 94L, 66L, 77L, 85L, 77L, 80L,
79L, 79L, 65L, 70L, 80L, 87L, 84L, 67L, 106L, 129L, 95L, 79L,
67L, 105L, 118L, 85L, 86L, 103L, 97L, 106L)), .Names = c("YY",
"a"), row.names = c(NA, -50L), class = "data.frame")
Here's the script:
p <- ggplot(dat, aes(x = YY))
p <- p + geom_line(aes(y=a),colour="blue",lwd=1)
p <- p + geom_point(aes(y=a),colour="blue",size=2)
p <- p + theme(panel.background=element_rect(fill="white"),
plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm"),
panel.border=element_rect(colour="black",fill=NA,size=1),
axis.line.x=element_line(colour="black"),
axis.line.y=element_line(colour="black"),
axis.text=element_text(size=15,colour="black",family="serif"),
axis.title=element_text(size=15,colour="black",family="serif"),
legend.position = "top")
p <- p + scale_x_discrete(limits = c(seq(1961,2010,5)),expand=c(0,0))
p <- p + geom_smooth(data=dat[1:10,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
p <- p + geom_smooth(data=dat[11:20,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
p <- p + geom_smooth(data=dat[21:30,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
p <- p + geom_smooth(data=dat[31:40,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
p <- p + geom_smooth(data=dat[41:50,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
p <- p + labs(x="Year",y="Number of Days")
outImg <- paste0("test",".png")
ggsave(outImg,p,width=8,height=5)
This is the resulting image:
WHAT I WANT/PROBLEMS
I want to extract the slope and add them on the the trend lines in the figure. How can I extract the slope of each line from the geom_smooth()?
Currently, I am plotting the trend lines one by one. I want to know if there is an efficient way of doing this with adjustable time window. Suppose for example, I want to plot the trend lines for every 5 years. In the figure above the time window is 10.
Suppose, I only want to plot the significant trend lines (i.e., p-value < 0.05, null: no trend or slope equals 0), is it possible to implement this with geom_smooth()?
I'll appreciate any help.

So, each of these tasks are best handled before you pipe your data into ggplot2, but they are all made fairly easy using some of the other packages from the tidyverse.
Beginning with questions 1 and 2:
While ggplot2 can plot the regression line, to extract the estimated slope coefficients you need to work with the lm() object explicitly. Using group_by() and mutate(), you can add a grouping variable (my code below does this for 5 year groups just for example) and then calculate and extract just the slope estimate into columns in your existing data frame. Then those slope estimates can be plotted in ggplot using the geom_text() call. I've done this below in a quick and dirty way (placing each label at the mean of the x and y values they regress) but you can specify their exact placement in your dataframe.
Grouping variables and data prep makes question 2 a breeze too: now that you have the grouping variables explicitly in your dataframe there is no need to plot one by one, geom_smooth() accepts the group aesthetic.
Additionally, to answer question 3, you can extract the pvalue from the summary of your lm objects and filter out only those that are significant to the level you care about. If you pass this now complete dataframe to geom_smooth() and geom_text() you will get the plot you're looking for!
library(tidyverse)
# set up our base plot
p <- ggplot(dat, aes(x = YY, y = a)) +
geom_line(colour = "blue", lwd = 1) +
geom_point(colour = "blue", size = 2) +
theme(
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), "cm"),
panel.border = element_rect(colour = "black", fill = NA, size = 1),
axis.line.x = element_line(colour = "black"),
axis.line.y = element_line(colour = "black"),
axis.text = element_text(size = 15, colour = "black", family = "serif"),
axis.title = element_text(size = 15, colour = "black", family = "serif"),
legend.position = "top"
) +
scale_x_discrete(limits = c(seq(1961, 2010, 5)), expand = c(0, 0))
# add a grouping variable (or many!)
prep5 <- dat %>%
mutate(group5 = rep(1:10, each = 5)) %>%
group_by(group5) %>%
mutate(
slope = round(lm(YY ~ a)$coefficients[2], 2),
significance = summary(lm(YY ~ a))$coefficients[2, 4],
x = mean(YY), # x coordinate for slope label
y = mean(a) # y coordinate for slope label
) %>%
filter(significance < .2) # only keep those with a pvalue < .2
p + geom_smooth(
data = prep5, aes(x = YY, y = a, group = group5), # grouping variable does the plots for us!
method = "lm", se = FALSE, color = "black",
formula = y ~ x, linetype = "dashed"
) +
geom_text(
data = prep5, aes(x = x, y = y, label = slope),
nudge_y = 12, nudge_x = -1
)
Now you may want to be a little more careful about specifying the location of your text labels than I have been here. I used means and the nudge_* arguments of geom_text() to do a quick example but keep in mind since these values are mapped explicitly to x and y coordinates, you have complete control!
Created on 2018-07-16 by the reprex
package (v0.2.0).

Related

How to implement stacked bar graph with a line chart in R

I have a dataset containing y variable as Year and x variables as (A, B, C(%)). I have attached the dataset here.
dput(result)
structure(list(Year = 2008:2021, A = c(4L, 22L, 31L, 48L, 54L,
61L, 49L, 56L, 59L, 85L, 72L, 58L, 92L, 89L), B = c(1L, 2L, 6L,
7L, 14L, 21L, 15L, 27L, 27L, 46L, 41L, 26L, 51L, 62L), C... = c(25,
9.09, 19.35, 14.58, 25.93, 34.43, 30.61, 48.21, 45.76, 54.12,
56.94, 44.83, 55.43, 69.66)), class = "data.frame", row.names = c(NA,
-14L))
The variables A and B will be plotted as stacked bar graph and the C will be plotted as line chart in the same plot. I have generated the plot using excel like below:
How can I create the same plot in R?
You first need to reshape longer, for example with pivot_longer() from tidyr, and then you can use ggplot2 to plot the bars and the line in two separate layers. The fill = argument in the geom_bar(aes()) lets you stratify each bar according to a categorical variable - name is created automatically by pivot_longer().
library(ggplot2)
library(tidyr)
dat |>
pivot_longer(A:B) |>
ggplot(aes(x = Year)) +
geom_bar(stat = "identity", aes(y = value, fill = name)) +
geom_line(aes(y = `C(%)`), size = 2)
Created on 2022-06-09 by the reprex package (v2.0.1)
You're asking for overlaid bars, in which case there's no need to pivot, and you can add separate layers. However I would argue that this could confuse or mislead many people - usually in stacked plots bars are stacked, not overlaid, so thread with caution!
library(ggplot2)
library(tidyr)
dat |>
ggplot(aes(x = Year)) +
geom_bar(stat = "identity", aes(y = A), fill = "lightgreen") +
geom_bar(stat = "identity", aes(y = B), fill = "red", alpha = 0.5) +
geom_line(aes(y = `C(%)`), size = 2) +
labs(y = "", caption = "NB: bars are overlaid, not stacked!")
Created on 2022-06-09 by the reprex package (v2.0.1)
I propose this:
library(data.table)
library(ggplot2)
library(ggthemes)
dt <- fread("dataset.csv")
dt.long <- melt(dt, id.vars = c("Year"))
dt.AB <- dt.long[variable %in% c("A", "B"), ]
dt.C <- copy(dt.long[variable == "C(%)", .(Year, variable, value = value * 3/2)])
ggplot(dt.AB, aes(x = Year, y = value, fill = variable), ) +
geom_bar(stat = "identity") +
geom_line(data=dt.C, colour='red', aes(x = Year, y = value)) +
scale_x_continuous(breaks = pretty(dt.AB$Year,
n = length(unique(dt.AB$Year)))) +
scale_y_continuous(
name = "A&B",
breaks = seq (0, 150, 10),
sec.axis = sec_axis(~.*2/3, name="C(%)", breaks = seq (0, 100, 10))
) + theme_hc() +
scale_fill_manual(values=c("grey70", "grey50", "grey30")) +
theme(
axis.line.y = element_line(colour = 'black', size=0.5,
linetype='solid'))

How to use hjust to move the label on only one plot?

I am creating a multipanel graph using plot_grid of the relationship of discharge and surface area with species richness in Amazon Rivers. Here is my data:
riverssub<-structure(list(richness = c(127L, 110L, 89L, 74L, 62L, 18L, 22L,
71L, 38L, 91L, 56L, 39L, 90L, 37L, 147L, 53L, 92L, 207L, 52L,
126L, 79L, 32L, 100L, 181L, 83L, 690L), surface = c(33490, 4410,
770, 164.7, 288.5, 9.85, 33.1, 750, 46.9, 970, 85.2, 39.2, 780,
97.3, 3983.71, 220, 500, 11250, 115, 1350, 278, 23.05, 310, 2050,
560, 34570), disch = c(2640L, 687L, 170L, 353L, 384L, 16L, 31L,
513L, 32L, 392L, 50L, 32L, 206L, 81L, 1260L, 104L, 220L, 6100L,
308L, 2060L, 443L, 102L, 348L, 4758L, 913L, 40487L)), class = "data.frame", row.names = c(NA,
-26L))
Here is the code for my graphs and multiplot:
library(cowplot)
a <- ggplot(data = riverssub, aes(x = surface , y = richness)) +
geom_point() +
scale_y_log10() +
scale_x_log10() +
labs(x='Surface Area (100 km\u00b2)', y="Fish Species Richness") +
theme_bw()
b <- ggplot(data = riverssub, aes(x = disch , y = richness)) +
geom_point() +
scale_y_log10() +
scale_x_log10() +
labs(x=bquote('Mean Annual Discharge'~(m^3 * s^-1)), y=" ") +
theme_bw()
plot_grid(a, b + theme(axis.text.y = element_blank()),
nrow = 1, align = 'h', labels="AUTO", label_y=0.97, label_x=0.1)
I want the "A" label to be in the same position on the first plot as the "B" label is on the second plot. I know I can use hjust() within plot_grid() to achieve this, although I am unsure how to do it. Can anyone help? Thanks in advance.
Instead of fiddling around with hjust to place the labels I would suggest to add the labels on the plots before aligning them via plot_grid as already suggested by #Guillaume in his comment. One option to do so and to ensure that the labels will be put on the same relative positions would be to make use annotation_custom:
library(cowplot)
library(ggplot2)
library(magrittr)
a <- ggplot(data = riverssub, aes(x = surface, y = richness)) +
geom_point() +
scale_y_log10() +
scale_x_log10() +
labs(x = "Surface Area (100 km\u00b2)", y = "Fish Species Richness") +
theme_bw()
b <- ggplot(data = riverssub, aes(x = disch, y = richness)) +
geom_point() +
scale_y_log10() +
scale_x_log10() +
labs(x = bquote("Mean Annual Discharge" ~ (m^3 * s^-1)), y = " ") +
theme_bw() +
theme(axis.text.y = element_blank())
list(A = a, B = b) %>%
purrr::imap(function(x, y) x + annotation_custom(grid::textGrob(label = y, x = .05, y = .97, gp = grid::gpar(fontface = "bold")))) %>%
plot_grid(plotlist = ., nrow = 1, align = "h")

geom_tile fill in confusion matrix correspond to value

I am trying to get the colours of a confusion matrix to correspond to the percent value in the middle of each matrix.
I have tried adjusting the geom_tile section fill to various options of Freq, or percentage, but with no luck.
valid_actualFunc <- as.factor(c(conf$ObsFunc))
valid_predFunc <- as.factor(c(conf$PredFunc))
cfmFunc <- confusionMatrix(valid_actualFunc, valid_predFunc)
ggplotConfusionMatrix <- function(m){
mytitle <- paste("Accuracy", percent_format()(m$overall[1]),
"Kappa", percent_format()(m$overall[2]))
data_c <- mutate(group_by(as.data.frame(m$table), Prediction ),
percentage=percent(Freq/sum(Freq)))
p <-
ggplot(data = data_c,
aes(x = Reference, y = Prediction)) +
geom_tile(aes(fill = Freq/sum(Freq)), colour = "white") +
scale_fill_gradient(low = "white", high = "red", na.value="white") +
geom_text(aes(x = Reference, y = Prediction, label = percentage)) +
theme(axis.text.x=element_text(angle = -90, hjust = 0),
axis.ticks=element_blank(), legend.position="none") +
ggtitle(mytitle)+
scale_y_discrete(limits = rev(levels(as.factor(valid_predFunc))))
return(p)
}
conf2Func=ggplotConfusionMatrix(cfmFunc)
conf2Func
Currently the fill is not equal to the value in the middle, i.e. a tile with 89% is lighter than one with 70%
As per the comment the return is
dput(head(cfmFunc))
list(positive = NULL, table = structure(c(2331L, 102L, 262L,
52L, 290L, 1986L, 178L, 89L, 495L, 74L, 2966L, 52L, 189L, 58L,
92L, 800L), .Dim = c(4L, 4L), .Dimnames = list(Prediction = c("Algae",
"Hard Coral", "Other", "Other Inv"), Reference = c("Algae", "Hard Coral",
"Other", "Other Inv")), class = "table"), overall = c(Accuracy =
0.807008785942492,
Kappa = 0.730790156424558, AccuracyLower = 0.799141307917932,
AccuracyUpper = 0.814697342402988, AccuracyNull = 0.358126996805112,
AccuracyPValue = 0, McnemarPValue = 6.95780670112837e-62), byClass =
structure(c(0.848562067710229,
0.780967361384192, 0.826874825759688, 0.702370500438982,
0.866006328243225,
0.968687274187073, 0.917249961113703, 0.978258420637603,
0.705295007564297,
0.894594594594595, 0.847913093196112, 0.805639476334341,
0.938012218745343,
0.928553104155977, 0.904725375882172, 0.962429347223761,
0.705295007564297,
0.894594594594595, 0.847913093196112, 0.80563947633434, 0.848562067710229,
0.780967361384192, 0.826874825759688, 0.702370500438982,
0.770323859881031,
0.833928196514802, 0.837261820748059, 0.75046904315197, 0.274261182108626,
0.253893769968051, 0.358126996805112, 0.113718051118211,
0.232727635782748,
0.198282747603834, 0.296126198083067, 0.0798722044728434,
0.329972044728434,
0.221645367412141, 0.349241214057508, 0.0991413738019169,
0.857284197976727,
0.874827317785633, 0.872062393436696, 0.840314460538292), .Dim = c(4L,
11L), .Dimnames = list(c("Class: Algae", "Class: Hard Coral",
"Class: Other", "Class: Other Inv"), c("Sensitivity", "Specificity",
"Pos Pred Value", "Neg Pred Value", "Precision", "Recall", "F1",
"Prevalence", "Detection Rate", "Detection Prevalence", "Balanced
Accuracy"
))), mode = "sens_spec", dots = list())
If you check the structure of your dataset to be plotted str(data_c), you will see that percentage is a character vector, and needs to be converted to numeric to be used as continuous input to the fill gradient.
data_c$percentage.numeric <- as.numeric(gsub("%", "", data_c$percentage))
You can use percentage.numeric for aes fill and percentage for aes label.
ggplot(data = data_c,
aes(x = Reference, y = Prediction)) +
geom_tile(aes(fill = percentage.numeric), colour = "white") +
scale_fill_gradient(low = "white", high = "red", na.value="white") +
geom_text(aes(x = Reference, y = Prediction, label = percentage)) +
theme(axis.text.x=element_text(angle = -90, hjust = 0),
axis.ticks=element_blank(), legend.position="none") +
ggtitle(mytitle)
Note scale_y_discrete(limits = rev(levels(as.factor(valid_predFunc)))) produces an error in your example
Error in as.factor(valid_predFunc) : object 'valid_predFunc' not found

Scaling data to secondary axis in R (ggplot2)

I'm trying to build a line chart with ggplot2 in which I would like to have 2 lines, each adapted to a different axis. I'm trying the following code (where df4 is my data frame):
p1 = ggplot(df4, mapping = aes(x=taxon, y=cov, group = 1, colour = "Coverage", xlab("Cover"))) +
geom_line() +
labs (x = "Taxon", y = "Coverage") +
geom_line(aes(y=depth, colour = "Depth")) +
theme(axis.text.x = element_text(angle = 75, hjust= 1, vjust = 1)) +
scale_colour_manual(values = c("navyblue", "green4")) +
scale_y_continuous(sec.axis = sec_axis(~./4, name = "Depth"))
With this, I am able to build a chart with 2 y-axis and 2 lines, but both lines are adapted to the primary y-axis (the secondary axis is there, but it's useless). Is there maybe a parameter with which I can ask my data to follow this axis?
Blue line values only go until 1, so they should be adapted to the secondary axis
This is an example of my data:
structure(list(taxon = structure(c(80L, 57L, 74L, 32L, 1L, 3L,
41L, 9L, 70L, 12L), .Label = c("c__Tremellomycetes", "f__Listeriaceae",
"f__Saccharomycetaceae", "g__Escherichia", "g__Klebsiella", "g__Pseudomonas",
"g__Saccharomyces", "g__Salmonella", "g__Staphylococcus", "s__Bacillus_amyloliquefaciens",
"s__Bacillus_phage_phi105", "s__Bacillus_siamensis", "s__Bacillus_sp_JS",
"s__Bacillus_subtilis", "s__Bacillus_vallismortis", "s__Citrobacter_sp_30_2",
"s__Cronobacter_phage_ENT47670", "s__Enterobacter_cancerogenus",
"s__Enterobacteria_phage_BP_4795", "s__Enterobacteria_phage_cdtI",
"s__Enterobacteria_phage_ES18", "s__Enterobacteria_phage_fiAA91_ss",
"s__Enterobacteria_phage_HK629", "s__Enterobacteria_phage_IME10",
"s__Enterobacteria_phage_lambda", "s__Enterobacteria_phage_mEp237",
"s__Enterobacteria_phage_mEp460", "s__Enterobacteria_phage_Min27",
"s__Enterobacteria_phage_P22", "s__Enterobacteria_phage_YYZ_2008",
"s__Enterococcus_faecalis", "s__Enterococcus_gilvus", "s__Enterococcus_phage_phiEf11",
"s__Enterococcus_phage_phiFL1A", "s__Enterococcus_phage_phiFL3A",
"s__Escherichia_coli", "s__Escherichia_phage_HK639", "s__Escherichia_phage_P13374",
"s__Lactobacillus_fermentum", "s__Listeria_innocua", "s__Listeria_ivanovii",
"s__Listeria_marthii", "s__Listeria_monocytogenes", "s__Listeria_phage_2389",
"s__Listeria_phage_A118", "s__Listeria_phage_A500", "s__Paenibacillus_sp_ICGEB2008",
"s__Phage_Gifsy_1", "s__Phage_Gifsy_2", "s__Pseudomonas_aeruginosa",
"s__Pseudomonas_mendocina", "s__Pseudomonas_phage_B3", "s__Pseudomonas_phage_D3",
"s__Pseudomonas_phage_DMS3", "s__Pseudomonas_phage_F10", "s__Pseudomonas_phage_F116",
"s__Pseudomonas_phage_PAJU2", "s__Pseudomonas_phage_Pf1", "s__Pseudomonas_phage_phi297",
"s__Pseudomonas_sp_2_1_26", "s__Pseudomonas_sp_P179", "s__Salmonella_enterica",
"s__Salmonella_phage_Fels_1", "s__Salmonella_phage_Fels_2", "s__Salmonella_phage_SETP13",
"s__Salmonella_phage_ST64B", "s__Shigella_phage_Sf6", "s__Staphylococcus_aureus",
"s__Staphylococcus_phage_42E", "s__Staphylococcus_phage_55",
"s__Staphylococcus_phage_80alpha", "s__Staphylococcus_phage_P954",
"s__Staphylococcus_phage_phi2958PVL", "s__Staphylococcus_phage_phiMR25",
"s__Staphylococcus_phage_phiN315", "s__Staphylococcus_phage_phiNM3",
"s__Staphylococcus_phage_phiPVL_CN125", "s__Staphylococcus_phage_phiPVL108",
"s__Staphylococcus_phage_PT1028", "s__Staphylococcus_phage_StauST398_1",
"s__Staphylococcus_phage_StauST398_3", "s__Staphylococcus_prophage_phiPV83",
"s__Stx2_converting_phage_1717", "s__Stx2_converting_phage_86"
), class = "factor"), cov = c(0.987654320987654, 0.99685534591195,
0.994535519125683, 0.147003745318352, 0.390923694779116, 0.92831541218638,
0.99079754601227, 0.993055555555556, 0.497512437810945, 0.58144695960941
), depth = c(1.68148148148148, 0.99685534591195, 0.994535519125683,
0.147003745318352, 0.390923694779116, 0.92831541218638, 0.99079754601227,
1.34722222222222, 0.497512437810945, 0.58144695960941)), .Names = c("taxon",
"cov", "depth"), row.names = c(40L, 10L, 58L, 44L, 7L, 55L, 29L,
13L, 2L, 53L), class = "data.frame")
You just need to multiply the 'depth' geom_line with 4 :
ggplot(df4, mapping = aes(x=taxon, y=cov, group = 1, colour = "Coverage", xlab("Cover"))) +
geom_line() +
labs (x = "Taxon", y = "Coverage") +
geom_line(aes(y=depth * 4, colour = "Depth")) +
theme(axis.text.x = element_text(angle = 75, hjust= 1, vjust = 1)) +
scale_colour_manual(values = c("navyblue", "green4")) +
scale_y_continuous(sec.axis = sec_axis(~./4, name = "Depth"))

Look of arrows in ggplot2 geom_segment()

I'm trying to make a plot with arrows in ggplot2 looking something like this, which was made using base R grapics. (colors are not important)
Using ggplot2:
library(ggplot2)
library(scales)
library(grid)
df3 <- structure(list(value1 = c(51L, 57L, 59L, 57L, 56L, 56L, 60L,
66L, 61L, 61L), value2 = c(56L, 60L, 66L, 61L, 61L, 59L, 61L,
66L, 63L, 63L), group = c("A", "B", "C", "D", "E", "A", "B",
"C", "D", "E"), time = c("1999", "1999", "1999", "1999", "1999",
"2004", "2004", "2004", "2004", "2004"), y_position = c(1L, 2L,
3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L)), .Names = c("value1", "value2",
"group", "time", "y_position"), row.names = c(NA, -10L), class = "data.frame")
ggplot( df3, aes( x = value1, y = y_position, group = time, color = time)) +
geom_segment( x = min(df3$value1, df3$value2), xend = max( df3$value1, df3$value2 ),
aes( yend = y_position), color = "lightgrey", size = 19) +
scale_y_continuous( labels = df3$group, breaks = df3$y_position) +
theme_classic() + theme( axis.line = element_blank(), axis.title = element_blank() ) +
geom_segment( aes( yend = y_position, xend = value2, color = time, group = time), size = 19, alpha = 0.9,
arrow = arrow(length = unit(40, "points"),type = "closed", angle = 40) )
I get this:
The problem is that the arrows look wrong (in that they don't look like the first plot). Using geom_segment() is not important.
This question may give the answer but I was hoping for something less hacky:
Specifying gpar settings for grid arrows in R
update: ggplot2 v2.1.0.9001
If the plot is in your current window you can edit the shape of the arrow directly with
grid.force()
# change shape of arrows
grid.gedit("segments", gp=gpar(linejoin ='mitre'))
# change the shape in legend also
grid.gedit("layout", gp=gpar(linejoin ='mitre'))
If the plot is in your current window you can edit the shape of the arrow directly with
grid.gedit("segments", gp=gpar(linejoin ='mitre'))
ggplot now seems to have changed the legend key to an arrow shape, so if you want to change the shape of these as well, you can do this across the full plot with
grid.gedit("gTableParent", gp=gpar(linejoin ='mitre'))
original answer
Not less hacky, but perhaps easier?? You can edit the grobs returned by ggplotGrob.
If p is your plot:
g <- ggplotGrob(p)
idx <- grep("panel", g$layout$name)
nms <- sapply(g$grobs[[idx]]$children[[3]]$children , '[[', "name")
for(i in nms) {
g$grobs[[idx]]$children[[3]] <-
editGrob(g$grobs[[idx]]$children[[3]], nms[i],
gp=gpar(linejoin ='mitre'), grep=TRUE)
}
grid.newpage()
grid.draw(g)
The challenge seems to be that the arrow constructor from the grid package gets messed up if size is invoked in the geom_segment block.
so
p <- ggplot(df3) + coord_flip()
p1 <- p + geom_bar(aes(x=group,y=max(c(value1,value2))*1.1),width=0.2, stat="identity",position="identity",alpha=0.2)
df1<-filter(df3,time=="1999")
p1 + geom_segment(data=df1,aes(x=group,xend=group,y=value1,yend=value2),color="blue",size=8,arrow=arrow(angle=20,type="closed",ends="last",length=unit(1,"cm")))
looks ridiculous as you show. I tried the workaround of of separating the segment into just a fat segment and an arrow on a skinny segment (two layers) like so:
p2<-p1 + geom_segment(data=df1,aes(x=group,xend=group,y=value1,yend=value2), color="blue",arrow=arrow(angle=20,type="closed",ends="last",length=unit(1,"cm")))
p2 + geom_segment(data=df1,aes(x=group,xend=group,y=value1,yend=value2), color="blue",size=8)
but now the fat segment end is not mitred and so obscures the arrow.
Fixing the arrow parameter seems to be needed.

Resources