R ggplot - calculate intercept of multiple plotted curves and geom_hline - r

I'm wanting to calculate interpolated x-intercepts for lines like these with geom_hline:
library(dplyr)
library(ggplot2)
g1=data.frame(grp="1", x=seq(1,50,1), y=rnorm(50,5,1))
g2=data.frame(grp="2", x=seq(1,30,1), y=rnorm(30,8,2))
g3=data.frame(grp="3", x=seq(1,45,1), y=rnorm(45,10,1))
comb.dat=rbind(g1,g2,g3)
plot.dat=comb.dat %>% group_by(grp) %>% mutate(cum=cumsum(y)/sum(y))
p1=ggplot(plot.dat, aes(x = x, y = cum, color=grp)) +geom_line()+ geom_hline(yintercept=.5, linetype="dashed", color = "black")
print(p1)
hline=data.frame(plot.dat %>% group_by(grp) %>% mutate(test=cum>0.49 & cum<0.51))#
print(hline[hline$test==T,])# only works when an exact value in the range exists
F1=approxfun(plot.dat$cum,plot.dat$x,ties=mean)
#data.frame(plot.dat %>% group_by(grp) %>% mutate(F1(0.50)))#works only on first group
g1b=plot.dat[plot.dat$grp=="1",]
F2=approxfun(g1b$cum,g1b$x)
F2(0.5)#works but inefficient
I have a lot of these plots and I am looking for the most efficient way to find the x-intercepts with the horizontal line for each factor level so the intercept values can be compared to each other and annotated to the plot. I thought there was a logic approach but then I realized I need interpolation, probably using approxfun. I have not found a way to do this without breaking the groups out of the data frame and doing it one by one...Thanks for setting me straight.

Here's a dplyr approach using base::approx.
x_seq = seq(1, 50, by = 0.01)
intersections <- plot.dat %>%
group_by(grp) %>%
summarise(interpolated = approx(x = x, y = cum, xout = x_seq)$y) %>%
mutate(x_seq = x_seq) %>%
slice_min(abs(interpolated - 0.5))
ggplot(plot.dat, aes(x = x, y = cum, color=grp)) +
geom_line() +
geom_hline(yintercept=.5, linetype="dashed", color = "black") +
geom_point(data = intersections, aes(x_seq, interpolated), size = 3) +
geom_text(data = intersections, aes(x_seq, interpolated, label = x_seq), vjust = -1)

Related

Adding a single label per group in ggplot with stat_summary and text geoms

I would like to add counts to a ggplot that uses stat_summary().
I am having an issue with the requirement that the text vector be the same length as the data.
With the examples below, you can see that what is being plotted is the same label multiple times.
The workaround to set the location on the y axis has the effect that multiple labels are stacked up. The visual effect is a bit strange (particularly when you have thousands of observations) and not sufficiently professional for my purposes. You will have to trust me on this one - the attached picture doesn't fully convey the weirdness of it.
I was wondering if someone else has worked out another way. It is for a plot in shiny that has dynamic input, so text cannot be overlaid in a hardcoded fashion.
I'm pretty sure ggplot wasn't designed for the kind of behaviour with stat_summary that I am looking for, and I may have to abandon stat_summary and create a new summary dataframe, but thought I would first check if someone else has some wizardry to offer up.
This is the plot without setting the y location:
library(dplyr)
library(ggplot2)
df_x <- data.frame("Group" = c(rep("A",1000), rep("B",2) ),
"Value" = rnorm(1002))
df_x <- df_x %>%
group_by(Group) %>%
mutate(w_count = n())
ggplot(df_x, aes(x = Group, y = Value)) +
stat_summary(fun.data="mean_cl_boot", size = 1.2) +
geom_text(aes(label = w_count)) +
coord_flip() +
theme_classic()
and this is with my hack
ggplot(df_x, aes(x = Group, y = Value)) +
stat_summary(fun.data="mean_cl_boot", size = 1.2) +
geom_text(aes(y = 1, label = w_count)) +
coord_flip() +
theme_classic()
Create a df_text that has the grouped info for your labels. Then use annotate:
library(dplyr)
library(ggplot2)
set.seed(123)
df_x <- data.frame("Group" = c(rep("A",1000), rep("B",2) ),
"Value" = rnorm(1002))
df_text <- df_x %>%
group_by(Group) %>%
summarise(avg = mean(Value),
n = n()) %>%
ungroup()
yoff <- 0.0
xoff <- -0.1
ggplot(df_x, aes(x = Group, y = Value)) +
stat_summary(fun.data="mean_cl_boot", size = 1.2) +
annotate("text",
x = 1:2 + xoff,
y = df_text$avg + yoff,
label = df_text$n) +
coord_flip() +
theme_classic()
I found another way which is a little more robust for when the plot is dynamic in its ordering and filtering, and works well for faceting. More robust, because it uses stat_summary for the text.
library(dplyr)
library(ggplot2)
df_x <- data.frame("Group" = c(rep("A",1000), rep("B",2) ),
"Value" = rnorm(1002))
counts_df <- function(y) {
return( data.frame( y = 1, label = paste0('n=', length(y)) ) )
}
ggplot(df_x, aes(x = Group, y = Value)) +
stat_summary(fun.data="mean_cl_boot", size = 1.2) +
coord_flip() +
theme_classic()
p + stat_summary(geom="text", fun.data=counts_df)

How to put the text for each point of plan in r

I am new to R and I have problem with adding the text for each point in the coordinate xoy: assume that I have dataframe below:
library (dplyr)
library(ggplot2)
dat <- data.frame(
time = factor(c("Breakfast","Breakfast","Breakfast","Lunch","Lunch","Lunch","Dinner","Dinner","Dinner"), levels=c("Breakfast","Lunch","Dinner")),
total_bill_x = c(12.75,14.89,20.5,17.23,30.3,27.8,20.7,32.3,25.4), total_bill_y= c(20.75,15.29,18.52,19.23,27.3,23.6,19.75,27.3,21.48)
)
and here is my code:
dat %>%
group_by(time) %>%
summarise(
x = sum(total_bill_x),
y = sum(total_bill_y)
)%>%
ggplot(.,aes(x,y, col = time)) +
geom_point()
I know that we will use geom_text but i dont know which argument to add into it to know that which point represent breakfast, lunch, dinner.
Any help for this would be much appreciated.
You can use geom_text(aes(label = time), nudge_y = 0.5). nudge_y will vertical adjust the labels. If you want to move horizontally, you must use nudge_x.
dat %>%
group_by(time) %>% # group your data
summarise(
x = sum(total_bill_x),
y = sum(total_bill_y) # compute median YOU ARE NOT COMPUTING MEDIAN HERE
)%>%
ggplot(.,aes(x,y, col = time)) +
geom_point() +
geom_text(aes(label = time), nudge_y = 0.5)

is it possible to ggplot grouped partial boxplots w/o facets w/ a single `geom_boxplot()`?

I needed to add some partial boxplots to the following plot:
library(tidyverse)
foo <- tibble(
time = 1:100,
group = sample(c("a", "b"), 100, replace = TRUE) %>% as.factor()
) %>%
group_by(group) %>%
mutate(value = rnorm(n()) + 10 * as.integer(group)) %>%
ungroup()
foo %>%
ggplot(aes(x = time, y = value, color = group)) +
geom_point() +
geom_smooth(se = FALSE)
I would add a grid of (2 x 4 = 8) boxplots (4 per group) to the plot above. Each boxplot should consider a consecutive selection of 25 (or n) points (in each group). I.e., the firsts two boxplots represent the points between the 1st and the 25th (one boxplot below for the group a, and one boxplot above for the group b). Next to them, two other boxplots for the points between the 26th and 50th, etcetera. If they are not in a perfect grid (which I suppose would be both more challenging to obtain and uglier) it would be even better: I prefer if they will "follow" their corresponding smooth line!
That all without using facets (because I have to insert them in a plot which is already facetted :-))
I tried to
bar <- foo %>%
group_by(group) %>%
mutate(cut = 12.5 * (time %/% 25)) %>%
ungroup()
bar %>%
ggplot(aes(x = time, y = value, color = group)) +
geom_point() +
geom_smooth(se = FALSE) +
geom_boxplot(aes(x = cut))
but it doesn't work.
I tried to call geom_boxplot() using group instead of x
bar %>%
ggplot(aes(x = time, y = value, color = group)) +
geom_point() +
geom_smooth(se = FALSE) +
geom_boxplot(aes(group = cut))
But it draws the boxplots without considering the groups and loosing even the colors (and add a redundant call including color = group doesn't help)
Finally, I decided to try it roughly:
bar %>%
ggplot(aes(x = time, y = value, color = group)) +
geom_point() +
geom_smooth(se = FALSE) +
geom_boxplot(data = filter(bar, group == "a"), aes(group = cut)) +
geom_boxplot(data = filter(bar, group == "b"), aes(group = cut))
And it works (maintaining even the correct colors from the main aes)!
Does someone know if it is possible to obtain it using a single call to geom_boxplot()?
Thanks!
This was interesting! I haven't tried to use geom_boxplot with a continuous x before and didn't know how it behaved. I think what is happening is that setting group overrides colour in geom_boxplot, so it doesn't respect either the inherited or repeated colour aesthetic. I think this workaround does the trick; we combine the group and cut variables into group_cut, which takes 8 different values (one for each desired boxplot). Now we can map aes(group = group_cut) and get the desired output. I don't think this is particularly intuitive and it might be worth raising it on the Github, since usually we expect aesthetics to combine nicely (e.g. combining colour and linetype works fine).
library(tidyverse)
bar <- tibble(
time = 1:100,
group = sample(c("a", "b"), 100, replace = TRUE) %>% as.factor()
) %>%
group_by(group) %>%
mutate(
value = rnorm(n()) + 10 * as.integer(group),
cut = 12.5 * ((time - 1) %/% 25), # modified this to prevent an extra boxplot
group_cut = str_c(group, cut)
) %>%
ungroup()
bar %>%
ggplot(aes(x = time, y = value, colour = group)) +
geom_point() +
geom_smooth(se = FALSE) +
geom_boxplot(aes(group = group_cut), position = "identity")
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Created on 2019-08-13 by the reprex package (v0.3.0)

Make multiple smoothed lines more visible in relation to confidence interval fills using ggplot geom_smooth

I'm making a graph of the expression of multiple genes among multiple subjects, displaying the data points and smoothed conditional means with the respective confidence intervals, but the points and lines are obscured by the fill of the confidence intervals. Is there a way to put the points and lines back on the first plane or make the confidence interval fill lighter, to make the points and lines more visible?
data1
library(forcats)
library(ggplot2)
library(tidyr)
tbl_long <- data1 %>%
gather(gene, expression, -X)
tbl_long %>%
ggplot(aes(x = fct_inorder(X), y = expression, color = gene, group = gene)) +
geom_point() +
geom_smooth(aes(fill=gene)) +
theme_classic()
I`m a begginer R user, so any help would be much appreciated
library(dplyr)
library(forcats)
library(ggplot2)
library(readr)
library(tidyr)
"X,ALDOA,ALDOC,GPI,GAPDHS,LDHA,PGK1,PKLR
C1,-0.643185598,-0.645053078,-0.087097464,-0.343085671,-0.770712771,0.004189881,0.088937264
C2,-0.167424935,-0.414607255,0.049551335,-0.405339423,-0.182211808,-0.127414498,-0.313125427
C3,-0.81858642,-0.938110755,-1.141371324,-0.212165875,-0.582733509,-0.299505078,-0.417053296
C4,-0.83403929,-0.36359332,-0.731276681,-1.173581357,-0.42953985,-0.14434282,-0.861271021
C5,-0.689384044,-0.833311409,-0.622961915,-1.13983245,0.479864518,-0.353765462,-0.787467172
C6,-0.465153207,-0.740128773,-0.05430084,0.499455778,-0.692945684,-0.215067456,-0.460695935
S2,0.099525323,0.327565645,-0.315537278,0.065457821,0.78394394,0.189251447,0.11684847
S3,0.33216583,0.190001824,0.749459725,0.224739679,-0.138610536,-0.420150288,0.919318891
S4,0.522281547,0.278411886,1.715325626,0.534957031,1.130054777,-0.129296273,1.803756399
S5,0.691225088,0.665540011,1.661124529,0.662320212,0.267803229,0.853683613,1.105808889
S6,1.269616976,1.86390714,2.069219749,1.312324149,1.498836807,1.794147633,0.842335285
S7,1.254166133,1.819075004,0.44893804,0.438435159,0.482694339,0.446939822,0.802671992
S8,0.751743085,0.702057721,0.657752337,1.668582798,-0.186354601,1.214976683,0.287904556
S9,0.091028475,-0.214746307,0.037471169,-0.90747123,-0.172209571,0.062382102,0.136354703
S10,1.5792826,1.736452158,0.194961866,0.706323594,1.396245579,0.208168636,0.883114282
R2,-0.36289097,-0.252649755,0.026497148,-0.026676693,-0.720750516,-0.087657548,0.390400605
R3,0.106992251,0.290831853,-0.815393104,-0.020562949,-0.579128953,-0.222087138,0.603723294
R4,0.208230649,0.533552023,-0.116632671,1.126588341,-0.09646495,0.157577458,-0.402493353
R5,-0.10781116,0.436174594,-0.969979695,-1.298192703,0.541570124,-0.07591813,-0.704663307
R6,-0.282867322,-0.960902616,0.184185506,-1.215118472,0.856165556,-0.256458847,-1.528611038
R7,-0.300331377,-0.918484952,0.191947526,-0.895049036,1.200294702,0.7120941,-0.047383224
R8,0.278804568,-0.07335879,0.300083636,0.37631121,-0.288228181,0.427576413,0.631281194
R9,0.393632652,0.228379711,-0.201269856,1.731887958,0.141541807,0.242716283,0.154875397
R10,0.731821818,0.058779515,-0.310899832,0.578285435,-0.474621274,0.126920851,0.017104493" %>%
read_csv() -> tbl_wide
tbl_long <- tbl_wide %>%
gather(gene, expression, -X)
tbl_long %>%
ggplot(aes(x = fct_inorder(X), y = expression, color = gene, fill = gene, group = gene)) +
geom_smooth(method = "loess", alpha = 0.1) +
geom_point() +
labs(x = "Location",
y = "Expression",
color = "Gene",
fill = "Gene") +
theme_classic()

How to mark minimum point from ggplot line plot [duplicate]

I am using the built-in economics (from the ggplot2 package) dataset in R, and have plotted a time-series for each variable in the same graph using the following code :
library(reshape2)
library(ggplot2)
me <- melt(economics, id = c("date"))
ggplot(data = me) +
geom_line(aes(x = date, y = value)) +
facet_wrap(~variable, ncol = 1, scales = 'free_y')
Now, I further want to refine my graph, For each series, I want to display a red point for the smallest and the largest value.
So I thought if I could find the co-ordinates of the min and max of each time-series, I could find a way to plot a red dot at beginning and ending of each time series. For this I used the following code :
which(pce == min(economics$pce), arr.ind = TRUE)
which(pca == max(pca), arr.ind = TRUE)
This doesnt really lead me anywhere.
Thank you:)
Method 1: Using Joins
This can be nice when you want to save the filtered subsets
library(reshape2)
library(ggplot2)
library(dplyr)
me <- melt(economics, id=c("date"))
me %>%
group_by(variable) %>%
summarise(min = min(value),
max = max(value)) -> me.2
left_join(me, me.2) %>%
mutate(color = value == min | value == max) %>%
filter(color == TRUE) -> me.3
ggplot(data=me, aes(x = date, y = value)) +
geom_line() +
geom_point(data=me.3, aes(x = date, y = value), color = "red") +
facet_wrap(~variable, ncol=1, scales='free_y')
Method 2: Simplified without Joins
Thanks #Gregor
me.2 <- me %>%
group_by(variable) %>%
mutate(color = (min(value) == value | max(value) == value))
ggplot(data=me.2, aes(x = date, y = value)) +
geom_line() +
geom_point(aes(color = color)) +
facet_wrap(~variable, ncol=1, scales="free_y") +
scale_color_manual(values = c(NA, "red"))

Resources