Recursive indexing error with facet wrap - r

I have two graphics side-by-side using facet_wrap and want to do the following things:
draw a square, but a different square in each facet
draw a vertical line, but a vertical line in a different location in each facet
I used this link to accomplish #1, but I can't do #2 in combination with that
ggplot2 - create different geom_path objects in facets
I created the following data frames
square1 = data.frame(x=c(.....),y=c(.....),z=a)
square2 = data.frame(x=c(.....),y=c(.....),z=b)
df1 = rbind(square1,square2) # 10*3 data frame that defines the dimensions of the squares to draw with z taking value of a or b
df2 = data.frame(x=c(..),z=c(a,b)) # 2*2 data frame with z taking value of a or b
The below code sets up the facets and all works fine:
RE <- ggplot(data, aes())
RE <- RE + geom_point(aes())
RE <- RE + xlab() + ylab() + ggtitle()
RE <- RE + coord_cartesian()
RE <- RE + scale_colour_brewer()
RE <- RE + theme_bw()
RE <- facet_wrap(~ v1 + v2, ncol=2)
But running this code results in the following error:
RE <- RE + geom_path(aes(x = x, y = y), data = df1)
RE <- RE + geom_vline(aes(xintercept = x), data = df2)
Error in panel$x_scales[[this_panel$SCALE_X]] : recursive indexing
failed at level 4
Note that I can run one or the other lines of code but not both.

You have not provided any data so I have created some data following the pattern you provided in your earlier post. Note that the data frame contains x and y coordinates for the points and the paths; a variable facet to tell ggplot in which panel to draw the points and paths; and a variable vline which gives the location of the vertical lines (in the v1 panel, the vline intercept is at x=2; in the v2 panel, the vline intercept is at x=3).
library(ggplot2)
square1 <- data.frame(x = c(1, 5, 5, 1, 1),
y = c(1, 1, 5, 5, 1),
facet = "v1",
vline = 2)
square2 <- data.frame(x = c(2, 4, 4, 2, 2),
y = c(2, 2, 4, 4, 2),
facet = "v2",
vline = 3)
df1 = rbind(square1,square2)
df1
ggplot(df1, aes(x, y)) +
geom_point(colour = "red", size = 5) +
geom_path(colour = "red", size = 2) +
geom_vline(aes(xintercept = vline),colour = "blue", size = 2) +
theme_bw() +
facet_wrap(~ facet, ncol=2)

Related

Indicating the maximum values and adding corresponding labels on a ggplot

ggplot(data = dat) + geom_line(aes(x=foo,y=bar)) +geom_line(aes(x=foo_land,y=bar_land))
which creates a plot like the following:
I want to try and indicate the maximum values on this plot as well as add corresponding labels to the axis like:
The data for the maximum x and y values is stored in the dat file.
I was attempting to use
geom_hline() + geom_vline()
but I couldn't get this to work. I also believe that these lines will continue through the rest of the plot, which is not what I am trying to achieve. I should note that I would like to indicate the maximum y-value and its corresponding x value. The x-value is not indicated here since it is already labelled on the axis.
Reproducible example:
library(ggplot2)
col1 <- c(1,2,3)
col2 <- c(2,9,6)
df <- data.frame(col1,col2)
ggplot(data = df) +
geom_line(aes(x=col1,y=col2))
I would like to include a line which travels up from 2 on the x-axis and horizontally to the y-axis indicating the point 9, the maximum value of this graph.
Here's a start, although it does not make the axis text red where that maximal point is:
MaxLines <- data.frame(col1 = c(rep(df$col1[which.max(df$col2)], 2),
-Inf),
col2 = c(-Inf, rep(max(df$col2), 2)))
MaxLines creates an object that says where each of three points should be for two segments.
ggplot(data = df) +
geom_line(aes(x=col1,y=col2)) +
geom_path(data = MaxLines, aes(x = col1, y = col2),
inherit.aes = F, color = "red") +
scale_x_continuous(breaks = c(seq(1, 3, by = 0.5), df$col1[which.max(df$col2)])) +
scale_y_continuous(breaks = c(seq(2, 9, by = 2), max(df$col2)))

R vertical ridgeline plot, error on width and stat parameters

How can I reformat this ridgeline plot so that is a vertical ridgeline plot?
My real dataset is the actual PDF. For a minimum reproducible example, I generate distributions and extract the PDFs to use in a dummy function. The dataframe has a model name (for grouping), x values paired with PDF ordinates, and an id field that separates the different ridgeline levels (i.e., ridgeline y axis).
set.seed(123)
makedfs <- function(name, id, mu, sig) {
vals <- exp(rnorm(1000, mean=mu, sd=sig))
pdf <-density(vals)
model <- rep(name, length(pdf$x))
prox <- rep(id, length(pdf$x))
df <- data.frame(model, prox, pdf$x, pdf$y)
colnames(df) <- c("name", "id", "x", "pdf")
return(df)
}
df1 <- makedfs("model1", 0, log(1), 1)
df2 <- makedfs("model2", 0, log(0.5), 2)
df3 <- makedfs("model1", 1, log(0.2), 0.8)
df4 <- makedfs("model2", 1, log(1), 1)
df <- rbind(df1, df2, df3, df4)
From this answer, R Ridgeline plot with multiple PDFs can be overlayed at same level, I have a standard joyplot:
ggplot(df, aes(x=x, y=id, height = pdf, group = interaction(name, id), fill = name)) +
geom_ridgeline(alpha = 0.5, scale = .5) +
scale_y_continuous(limits = c(0, 5)) +
scale_x_continuous(limits = c(-6, 6))
I am trying the code below based on https://wilkelab.org/ggridges/reference/geom_vridgeline.html but it throws an error on the width parameter.
p <- ggplot(df, aes(x=id, y=x, width = ..density.., fill=id)) +
geom_vridgeline(stat="identity", trim=FALSE, alpha = 0.85, scale = 2)
Error in `f()`:
! Aesthetics must be valid computed stats. Problematic aesthetic(s): width = ..density...
Did you map your stat in the wrong layer?
If you wanted the same graph, just vertically oriented, you need to use the same parameters when you use geom_vridgeline.
I swapped the limits you originally set so you can see that it's the same.
ggplot(df, aes(x = id, y = x, width = pdf, fill = name,
group = interaction(name, id))) +
geom_vridgeline(alpha = 0.85, scale = .5) +
scale_x_continuous(limits = c(0, 5)) + # <-- note that the x & y switched
scale_y_continuous(limits = c(-6, 6))

Change point shape in gig-lot only for certain observations

I'm plotting a graph in R using ggplot2. It's a lined graph with points for every observations, the points represent p-values. Three of them are not significant, and I want these points to show up differently (any other shape/color, doesn't matter). Now I'm not sure how to do this.
I've tried scale_shape_manual(values = c(valueA, valueB, valueC)) and
scale_color_manual, but I don't get any results. No error messages either, just nothing happens.
Can anyone help?
ggplot(data = dataframe) +
geom_line(aes(x=Time, y=Treatment), color="#00AFBB")+
geom_point(aes(x=Time, y=Treatment)) +
scale_y_reverse()+
scale_x_continuous( breaks = c(1, 2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20))
Thanks!
--
Edit: here a reproducible sample (I hope it works?):
A <- c(1,2,3,4,5)
B <- c(1,2,3,4,5)
df <- data.frame(cbind(A, B))
Here's an example, hopefully helpful. I use scale_color_identity and scale_shape_identity because my data (in this case created through the if_else statements) specifies the literal color/shape I want to use.
Time <- c(1,2,3,4,5)
Treatment <- c(1,2,3,4,5)
df <- data.frame(Time = 1:5, Treatment = 1:5)
ggplot(data = df) +
geom_line(aes(x=Time, y=Treatment), color = "#00AFBB") +
geom_point(aes(x=Time, y=Treatment,
shape = if_else(Treatment < 5, 18, 1),
color = if_else(Treatment < 5, "#00AFBB", "black")), size = 4) +
scale_y_reverse()+
scale_x_continuous( breaks = 1:20) +
scale_color_identity() +
scale_shape_identity()

How to get different colors related to treatment for boxplot and violin plot (ggplot / using geom_split_violin) that are plotted in one?

I am trying to show a boxplot and a violin plot in one.
I can fill in the colors of the boxplot and violin plot based on the treatment. But, I don't want them in exactly the same color, I'd prefer the violin plot or the boxplot filling to be lighter.
Also, I am able to get the outer lines of the boxplot in different colors if I add col=TM to the aes of the geom_boxplot. But, then I can not choose these colors or don't know how to (they are now automatically pink and blue).
BACKGROUND:
I am working with a data set that looks something like this:
TM yax X Zscore
Org zscore zhfa -1.72
Org zscore zfwa -0.12
I am plotting the z-scores based on the X (zhfa e.d.) per treatment (TM).
#Colours
ocean = c('#BBDED6' , '#61C0BF' , '#FAE3D9' , '#FFB6B9' )
## Plot ##
z <- ggplot(data = data, aes(x = X, y = Zscore,fill=TM)) +
geom_split_violin(col="white", fill="white") +
geom_boxplot(alpha = 1, width=0.3, aes(fill=TM), position = position_dodge(width = 0.3))
z + theme(axis.text = element_text(size = 12),legend.position="top") +
stat_compare_means(method="t.test", label.y=2.8, label.x=0.3, size=3) +
scale_fill_manual(values=ocean, labels=c("Mineral fertilizer", "Organic fertilizer"))
Now, half of the violin plot is filled white, but not both (which would already be better). If I would plot geom_split_violin() it would get exactly the same colors as the boxplot.
Furthermore, should the violinplot of zhfa be on the left side but it get's switched and is displayed at the right side, while it matched the data of the organic (left) boxplot.
The graph now:
I don't know if it can be solved by adding something related to the scale_fill_manual or if this is an impossible request
Sample Data:
data <- data.frame(TM = c(rep("org", 5), rep("min", 5),rep("org", 5), rep("min", 5),rep("org", 5), rep("min", 5)),
Zscore = runif(30,-2,2),
X = c(rep("zwfa", 10), rep("zhfa", 10), rep("zbfa", 10)))
You can add an additional column to your data that is the same structure as TM but different values, then scale the fill:
Sample Data:
data <- data.frame(TM = c(rep("org", 5), rep("min", 5),rep("org", 5), rep("min", 5),rep("org", 5), rep("min", 5)),
Zscore = runif(30,-2,2),
X = c(rep("zwfa", 10), rep("zhfa", 10), rep("zbfa", 10)))
Begin solution:
data <- data %>% mutate(TMm = c(rep("orgM", 5), rep("minM", 5),rep("orgM", 5), rep("minM", 5),rep("orgM", 5), rep("minM", 5)))
#Colours
ocean = c('#BBDED6' , '#FAE3D9', '#61C0BF' , '#FFFFFF')
## Plot ##
z <- ggplot(data = data, aes(x = X, y = Zscore,fill=TM)) +
geom_split_violin(mapping = aes(fill=TMm)) +
geom_boxplot(alpha = 1, width=0.3, aes(fill=TM), position = position_dodge(width = 0.3))
z + theme(axis.text = element_text(size = 12),legend.position="top") +
stat_compare_means(method="t.test", label.y=2.8, label.x=0.3, size=3) +
scale_fill_manual(breaks = c("org", "min"), values=ocean, labels=c("Mineral fertilizer", "Organic fertilizer"))
In your data you may have to change breaks = c("org", "min") to whatever you call the factor levels in the TM variable
Or if you want the whole violin plot white:
ocean = c('#BBDED6' , '#FFFFFF', '#61C0BF' , '#FFFFFF')
New Plot:

How to add ggplot legend of two different lines R?

I need to add a legend of the two lines (best fit line and 45 degree line) on TOP of my two plots. Sorry I don't know how to add plots! Please please please help me, I really appreciate it!!!!
Here is an example
type=factor(rep(c("A","B","C"),5))
xvariable=seq(1,15)
yvariable=2*xvariable+rnorm(15,0,2)
newdata=data.frame(type,xvariable,yvariable)
p = ggplot(newdata,aes(x=xvariable,y=yvariable))
p+geom_point(size=3)+ facet_wrap(~ type) +
geom_abline(intercept =0, slope =1,color="red",size=1)+
stat_smooth(method="lm", se=FALSE,size=1)
Here is another approach which uses aesthetic mapping to string constants to identify different groups and create a legend.
First an alternate way to create your test data (and naming it DF instead of newdata)
DF <- data.frame(type = factor(rep(c("A", "B", "C"), 5)),
xvariable = 1:15,
yvariable = 2 * (1:15) + rnorm(15, 0, 2))
Now the ggplot code. Note that for both geom_abline and stat_smooth, the colour is set inside and aes call which means each of the two values used will be mapped to a different color and a guide (legend) will be created for that mapping.
ggplot(DF, aes(x = xvariable, y = yvariable)) +
geom_point(size = 3) +
geom_abline(aes(colour="one-to-one"), intercept =0, slope = 1, size = 1) +
stat_smooth(aes(colour="best fit"), method = "lm", se = FALSE, size = 1) +
facet_wrap(~ type) +
scale_colour_discrete("")
Try this:
# original data
type <- factor(rep(c("A", "B", "C"), 5))
x <- 1:15
y <- 2 * x + rnorm(15, 0, 2)
df <- data.frame(type, x, y)
# create a copy of original data, but set y = x
# this data will be used for the one-to-one line
df2 <- data.frame(type, x, y = x)
# bind original and 'one-to-one data' together
df3 <- rbind.data.frame(df, df2)
# create a grouping variable to separate stat_smoothers based on original and one-to-one data
df3$grp <- as.factor(rep(1:2, each = nrow(df)))
# plot
# use original data for points
# use 'double data' for abline and one-to-one line, set colours by group
ggplot(df, aes(x = x, y = y)) +
geom_point(size = 3) +
facet_wrap(~ type) +
stat_smooth(data = df3, aes(colour = grp), method = "lm", se = FALSE, size = 1) +
scale_colour_manual(values = c("red","blue"),
labels = c("abline", "one-to-one"),
name = "") +
theme(legend.position = "top")
# If you rather want to stack the two keys in the legend you can add:
# guide = guide_legend(direction = "vertical")
#...as argument in scale_colour_manual
Please note that this solution does not extrapolate the one-to-one line outside the range of your data, which seemed to be the case for the original geom_abline.

Resources