I would like to facet a plot, but with a reference plot in each panel. Let me try to show with pictures what I want to achieve: My example data_frame:
require(dplyr)
df <- data_frame( id = c(rep('ctr',40), rep('pat',80)),
class = c(rep('ctr',40), rep(c('a','b'), each = 40)),
rank = rep (1:20,6),
mean = c(rep(seq(3,-3, length.out = 20),2),
rep(seq(1,-4, length.out = 20),2),
rep(seq(-2,-8, length.out = 20),2)),
sd = rep(seq(1.2,0.8, length.out = 20), times = 6),
exam = rep(c('blue','red'), each = 20, times = 3))
My plot:
# first, create reference plot of the 'controls'
require(ggplot2)
p_ctr <- ggplot() +
geom_line(data = filter(df, id == 'ctr'),
aes(x=rank, y=mean, color=exam), linetype=1) +
geom_ribbon(data = filter(df, id == 'ctr'),
aes(x = rank, ymax = mean+sd, ymin = mean-sd,
fill = exam), alpha = .1) +
scale_colour_manual(values = c("#00b6eb","#eb0041")) +
scale_fill_manual(values = c("#00b6eb","#eb0041"))
# then, overlay with plot of 'patients'
p_ctr + geom_line(data = filter(df, id == 'pat'),
aes(x=rank, y=mean, linetype = class)) +
geom_ribbon(data = filter(df, id == 'pat'),
aes(x = rank, ymax = mean+sd, ymin = mean-sd,
group = class),
alpha = .1) +
facet_wrap(~exam)
That is halfway there:
Ideally, however, I would like to plot the different "classes" in separate panels, but with the control plot as a reference in each panel:
Expected result:
I have tried different combinations of facetting, without good result. I guess, there must be a simple solution?
Maybe like so.
library(dplyr)
library(ggplot2)
df1 <- filter(df, id == 'ctr')
df2 <- filter(df, id == 'pat')
df2 <- dplyr::rename(df2, class_2 = class)
p_ctr <- ggplot() +
geom_line(data = df1, aes(x=rank, y=mean, color=exam)) +
geom_ribbon(data = df1,
aes(x = rank, ymax = mean+sd, ymin = mean-sd, fill = exam),
alpha = .1) +
scale_colour_manual(values = c("#00b6eb","#eb0041")) +
scale_fill_manual(values = c("#00b6eb","#eb0041")) +
geom_line(data = df2,
aes(x=rank, y=mean)) +
geom_ribbon(data = df2,
aes(x = rank, ymax = mean+sd, ymin = mean-sd),
alpha = .1) +
facet_grid(class_2 ~ exam)
p_ctr
Using facet_wrap gives me the following error:
error in gList(list(x = 0.5, y = 0.5, width = 1, height = 1, just = "centre", :
only 'grobs' allowed in "gList"
You probably came across this plot while looking for the solution.
p_ctr + geom_line(data = filter(df, id == 'pat'),
aes(x=rank, y=mean)) +
geom_ribbon(data = filter(df, id == 'pat'),
aes(x = rank, ymax = mean+sd, ymin = mean-sd),
alpha = .1) +
# facet_wrap(~exam) +
facet_grid(class ~ exam)
This is basically your reference plot and its overlay, without the linetype and group arguments. Additionally I faceted by class ~ exam. From this plot you see that 'the problem' is that class contains three unique elements: a, b and ctr. That's why I renamed the variable class in df2 to be class_2 which has only two unique elements: a and b. Faceting by class_2 ~ exam then gives the desired output.
I hope this helps.
Related
Here's my R code
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha=0.08)+
geom_jitter()+
scale_fill_brewer(palette="Spectral")+
theme_minimal()
Like you can see the dots are in the middle of the boxplots. What can I add in geom_jitter to have each point in the righ boxplot and not in the middle like this ? I also tried geom_point, it gave the same result !
Thanks to the help now It works, but I wanted to add a line to connect the dots and I got this.. can someone tell how to really connect the dots with lines
I think if you group by interaction(Group, Type) and use position_jitterdodge() you should get what you're looking for.
ggplot(mtcars, aes(as.character(am), mpg, color = as.character(vs),
group = interaction(as.character(vs), as.character(am)))) +
geom_boxplot() +
geom_jitter(position = position_jitterdodge()) # same output with geom_point()
Edit - here's an example with manual jittering applied to data where the each subject appears once in each Group.
I looked for a built-in way to do this, and this answer comes close, but I couldn't get it to work in terms of using position_jitterdodge with position defined by the groups of Group/Type, but line grouping defined by id alone and not by Group/Type. Both aesthetics (position adjustment and series identification) rely on the same group parameter, but they each need a different value for it.
Table = data.frame(id = 1:4,
value = rnorm(8),
Group = rep(c("a","b"), each = 4),
Type = c("1", "2"))
library(dplyr)
Table %>%
mutate(x = as.numeric(as.factor(Group)) +
0.2 * scale(as.numeric(as.factor(Type))) +
rnorm(n(), sd = 0.06)) %>%
ggplot(aes(x = Group, y = value, fill = Type, group = interaction(Group, Type))) +
geom_boxplot(alpha=0.2)+
geom_point(aes(x = x)) +
geom_line(aes(x = x, group = id), alpha = 0.1) +
scale_fill_brewer(palette="Spectral")+
theme_minimal()
Best to use position_dodge instead if you want them to line up:
library(ggplot2)
Table <- tibble::tibble(
Group = rep(c("A", "B"), each = 20),
Type = factor(rep(c(1:2, 1:2), each = 10)),
value = rnorm(40, mean = 10)
)
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha=0.08)+
geom_point(position = position_dodge(width = 0.75))+
scale_fill_brewer(palette="Spectral")+
theme_minimal()
To add a line, make sure group = ID goes in both the geom_point and geom_line calls:
library(ggplot2)
Table <- tibble::tibble(
Group = rep(c("A", "B"), each = 20),
Type = factor(rep(c(1:2, 1:2), each = 10)),
ID = factor(rep(1:20, times = 2)),
value = rnorm(40, mean = 10)
)
ggplot(dat = Table, aes(x = Group, y = value, fill = Type)) +
geom_boxplot(alpha = 0.08) +
geom_point(aes(group = ID), position = position_dodge(width = 0.75))+
geom_line(aes(group = ID), position = position_dodge(width = 0.75), colour = "grey")+
scale_fill_brewer(palette = "Spectral") +
theme_minimal()
I am currently trying to customize my plot with the goal to have a plot like this:
If I try to specify the color or linetype in either aes() or mapping = aes(), I get two different smooths. One for each class. This makes sense, because the smoothing will be applied once for each type.
If I use group = 1 in the aestetics, I will get one line, also one color/linetype.
But I can not find a solution to have one smooth line with different colors/linetypes for each class.
My code:
ggplot(df2, aes(x = dateTime, y = capacity)) +
#geom_line(size = 0) +
stat_smooth(geom = "area", method = "loess", show.legend = F,
mapping = aes(x = dateTime, y = capacity, fill = type, color = type, linetype = type)) +
scale_color_manual(values = c(col_fill, col_fill)) +
scale_fill_manual(values = c(col_fill, col_fill2))
The result for my data:
Reproduceable code:
File: enter link description here (I can not make this file shorter and copy it hear, else I get errors with smoothing for too few data points)
df2 <- read.csv("tmp.csv")
df2$dateTime <- as.POSIXct(df2$dateTime, format = "%Y-%m-%d %H:%M:%OS")
col_lines <- "#8DA8C5"
col_fill <- "#033F77"
col_fill2 <- "#E5E9F2"
ggplot(df2, aes(x = dateTime, y = capacity)) +
stat_smooth(geom = "area", method = "loess", show.legend = F,
mapping = aes(x = dateTime, y = capacity, fill = type, color = type, linetype = type)) +
scale_color_manual(values = c(col_fill, col_fill)) +
scale_fill_manual(values = c(col_fill, col_fill2))
I would suggest to model the data outside the plotting function and then plot it with ggplot. I used the pipes (%>%) and mutate from the tidyversefor convenient reasons, but you don't have to. Also, I prefer to have a line and a fill separated to avoid the dashed line on the right side of your plot.
df2$index <- as.numeric(df2$dateTime) #create an index for the loess model
model <- loess(capacity ~ index, data = df2) #model the capacity
plot <- df2 %>% mutate(capacity_predicted = predict(model)) %>% # use the predicted data for the capacity
ggplot(aes(x = dateTime, y = capacity_predicted)) +
geom_ribbon(aes(ymax = capacity_predicted, ymin = 0, fill = type, group = type)) +
geom_line(aes( color = type, linetype = type)) +
scale_color_manual(values = c(col_fill, col_fill)) +
scale_fill_manual(values = c(col_fill, col_fill2)) +
theme_minimal() +
theme(legend.position = "none")
plot
Please tell me if it works (I don't have the original data to test it), and if you would like a version without tidyverse functions.
EDIT:
Not very clean, but a smoother curve can be obtained with this code:
df3 <- data.frame(index = seq(min(df2$index), max(df2$index), length.out = 300),
type = "historic", stringsAsFactors = F)
modelling_date_index <- 1512562500
df3$type[df3$index <= modelling_date_index] = "predict"
plot <- df3 %>% mutate(capacity_predicted = predict(model, newdata = index),
dateTime = as.POSIXct(index, origin = '1970-01-01')) %>%
# arrange(dateTime) %>%
ggplot(aes(x = dateTime, y = capacity_predicted)) +
geom_ribbon(aes(ymax = capacity_predicted, ymin = 0, fill = type, group =
type)) +
geom_line(aes( color = type, linetype = type)) +
scale_color_manual(values = c(col_fill, col_fill)) +
scale_fill_manual(values = c(col_fill, col_fill2)) +
theme_minimal()+
theme(legend.position = "none")
plot
I have created a DF based on the following code.
sex <- c("m","f","m","m","m","m","m","f","f","f")
age <- c(">10",">20",">30",">10",">20",">30",">10",">20",">30",">10")
df1 <- data.frame(sex,age)
ggplot (df1, aes(sex, fill = factor(age))) + geom_bar()
I want to individually label the counts of combination of age and sex
sex="f" and age = ">10" = 1, sex="f" and age = ">20" = 2, sex="f" and
age = ">30" = 1, sex="m" and age = ">10" = 3, sex="m" and age = ">20"
= 1, sex="m" and age = ">30" = 2
I think you want something like this:
ggplot(df1, aes(sex, fill = factor(age))) + geom_bar() +
geom_text(stat = "count", aes(y = ..count.., label = ..count..), position = "stack", vjust = 3)
Not sure if I understood your question correctly, but do you mean something like this:
df2 <- as.data.frame(table(df1))
df2$sex_age <- paste(df2$sex, df2$age, sep = "_")
ggplot(df2, aes(x = sex_age, y = Freq)) + geom_bar(stat = "identity")
I am having trouble with geom_errorbars particularly in utilizing position_dodge() effectively in this script.
library(ggplot2)
library(plyr)
Dose <- rep(c(3,10,30,100), each = 6)
Visit <- rep(c(1,28), each = 3, times = 4)
Animal <- rep(1:3, times = 8)
Estimate <- runif(24)
Dose <- factor(Dose)
Visit <- factor(Visit)
df <- data.frame(Animal, Dose, Visit, Estimate)
e <- ddply(df, .(Dose, Visit), summarise, mean = mean(Estimate), sd = sd(Estimate), n = length(Estimate))
e$se = e$sd/sqrt(e$n)
trace.out <- ggplot(data = e, aes(x = Visit, y = mean, colour = Dose))
trace.out <- trace.out +
geom_point(data = e, aes(y = mean), size = 3, postion = position_dodge(width = 0.2)) +
geom_line(data = e, aes(y = mean, group = Dose), position = position_dodge(width = 0.2)) +
geom_errorbar(aes(ymin= mean - se, ymax = mean + se), postion = position_dodge(0.2), colour='black', width= 0.3) +
labs(y = 'Estimate') +
theme_bw()
print(trace.out)
The output for me looks like:
I would like for the points, lines and error bars to line up and to have the errorbars not overlap. Is there some way to do that? Additionally I get an error of:
ymax not defined: adjusting position using y instead
Would this have anything to do with it? Thanks in Advance!
Maybe facets are an option:
trace.out <- ggplot(data = e, aes(x = Visit, y = mean, colour = Dose, ymin= mean - se, ymax = mean + se, group = Dose))
trace.out <- trace.out +
geom_point(size = 3, postion = position_dodge(width = 0.2)) +
geom_line(position = position_dodge(width = 0.2), ) +
geom_errorbar(postion = position_dodge(0.2), colour='black', width= 0.3) +
labs(y = 'Estimate') +
theme_bw()
print(trace.out + facet_grid(~Dose) )
i was hoping to plot two time series and shade the space between the series according to which series is larger at that time.
here are the two series-- first in a data frame with an indicator for whichever series is larger at that time
d1 <- read.csv("https://dl.dropbox.com/s/0txm3f70msd3nm6/ribbon%20data.csv?dl=1")
And this is the melted series.
d2 <- read.csv("https://dl.dropbox.com/s/6ohwmtkhpsutpig/melted%20ribbon%20data.csv?dl=1")
which I plot...
ggplot() + geom_line(data = d2,
aes(x = time, y = value, group = variable, color = variable)) +
geom_hline(yintercept = 0, linetype = 2) +
geom_ribbon(data = d1[d1$big == "B",],
aes(x = time, ymin = csa,
ymax = csb),
alpha = .25,
fill = "#9999CC") +
geom_ribbon(data = d1[d1$big == "A",],
aes(x = time, ymin = csb,
ymax = csa),
alpha = .25,
fill = "#CC6666") +
scale_color_manual(values = c("#CC6666" , "#9999CC"))
which results in...
why is there a superfluous blue band in the middle of the plot?
Here is a solution. I replaced data = d1[d1$big == "B",] in the first geom_ribbon function with:
data = rbind(d1[d1$big == "B",],
d1[c((which(diff(as.numeric(d1$big)) == -1) + 1),
(which(diff(as.numeric(d1$big)) == 1))), ])
This is necessary since the first and last rows of d1$big == "B" sequences often contain different csa and csb values. As a result, there is a visible ribbon connecting the data. The above command uses the last rows before and the first rows after these sequences together with the data for the first ribbon.
This problem does not exist for d1$big == "A" (the base for the second ribbon).
The complete code:
ggplot() +
geom_line(data = d2,
aes(x = time, y = value, group = variable, color = variable)) +
geom_hline(yintercept = 0, linetype = 2) +
geom_ribbon(data = rbind(d1[d1$big == "B",],
d1[c((which(diff(as.numeric(d1$big)) == -1) + 1),
(which(diff(as.numeric(d1$big)) == 1))), ]),
aes(x = time, ymin = csa, ymax = csb),
alpha = .25, fill = "#9999CC") +
geom_ribbon(data = d1[d1$big == "A",],
aes(x = time, ymin = csb, ymax = csa),
alpha = .25, fill = "#CC6666") +
scale_color_manual(values = c("#CC6666" , "#9999CC"))