I've created a plot of categorical data using facet in ggplot.
Example script here:
#script to produce plot with dummy data
rm(list=ls(all=TRUE))
library(ggplot2)
require(gridExtra)
#put dummy data in df
dummy_data<-data.frame(experiment_number=c(rep("exp_1",15),rep("exp_2",15)),
group=rep(c("A","B","C"),5),yvalue=runif(30, 0.0, 0.05))
# make plot
plot1<-ggplot(data = dummy_data)+
geom_point(aes(x = group, y = yvalue,
colour=group,shape=group),size=3.5,position = position_jitter(w = 0.2)) +
facet_wrap( ~ experiment_number) +
ylab("yvalue") +
xlab("")
#plot
plot1
I now want to add text & bars below the plot to show the p values relating to a statistical test between the groups -an example where I've just drawn it in my hand is attached (p values just made up).
Note the p values will be different in the two different panels. I've played around with annotate & custom annotate but cant seem to get it to work. Any ideas?
thanks v much
Here's a totally ridiculous way of doing something similar to what you are asking for. I used geom_errorbar for the bars, so I had to flip the coordinate system. Anyway, you should be able to customize this to do what you need.
rm(list=ls(all=TRUE))
library(ggplot2)
#put dummy data in df
dummy_data<-data.frame(experiment_number=c(rep("exp_1",15),rep("exp_2",15)),
group=rep(c("A","B","C"),5),yvalue=runif(30, 0.0, 0.05))
# make plot
plot1<-ggplot(data = dummy_data)+
geom_point(aes(y = group, x = yvalue, #changed x and y
colour=group,shape=group),size=3.5,position = position_jitter(h = 0.2)) + # changed w=... to h=...
facet_wrap( ~ experiment_number) +
xlab("yvalue") +
ylab("") + coord_flip() # flipped coordinate system
#plot
rng <- range(dummy_data$yvalue) # range
df.lines <- data.frame(ymin=LETTERS[1:3], ymax=LETTERS[c(2,3,1)], x=rng[1]-diff(rng)*1:3/12) #data for geom_errorbar
# data for geom_text
df.txt <- data.frame(y=c("AB", "BC", "B"),
x=rng[1]-diff(rng)*(1:3+.5)/12,
label=c("p=0.003", "p=0.05", "p=0.6",
"p=0.2", "p=0.1", "p=0.05"),
experiment_number=rep(c("exp_1", "exp_2"), each=3))
# add some space and geom_errorbar and geom_text
plot2 <- plot1 + scale_x_continuous(limits=c(rng[1]-diff(rng)/3, rng[2]+diff(rng)/5)) +
geom_errorbar(data=df.lines, aes(x=x, ymin=ymin, ymax=ymax)) +
scale_y_discrete(breaks=LETTERS[1:3], limits=c("A", "AB", "B", "BC", "C")) +
geom_text(data=df.txt, aes(x=x, y=y, label=label), xjust=0.5)
plot2
Related
This question already has an answer here:
Setting individual y axis limits with facet wrap NOT with scales free_y
(1 answer)
Closed 4 years ago.
I'm trying to create a facet_wrap() where the unit of measure remains identical across the different plots, while allowing to slide across the y axis.
To clearify with I mean, I have created a dataset df:
library(tidyverse)
df <- tibble(
Year = c(2010,2011,2012,2010,2011,2012),
Category=c("A","A","A","B","B","B"),
Value=c(1.50, 1.70, 1.60, 4.50, 4.60, 4.55)
)
with df, we can create the following plot using facet_wrap:
ggplot(data = df, aes(x=Year, y=Value)) + geom_line() + facet_wrap(.~ Category)
Plot 1
To clarify the differences between both plots, one can use scale = "free_y":
ggplot(data = df, aes(x=Year, y=Value)) + geom_line()
+ facet_wrap(.~ Category, scale="free_y")
Plot 2
Although it's more clear, the scale on the y-axis in plot A isequal to 0.025, while being 0.0125 in B. This could be misleading to someone who's comparing A & B next to each other.
So my question right now is to know whether there exist an elegant way of plotting something like the graph below (with y-scale = 0.025) without having to plot two seperate plots into a grid?
Thanks
Desired result:
Code for the grid:
# Grid
## Plot A
df_A <- df %>%
filter(Category == "A")
plot_A <- ggplot(data = df_A, aes(x=Year, y=Value)) + geom_line() + coord_cartesian(ylim = c(1.5,1.7)) + ggtitle("A")
## Plot B
df_B <- df %>%
filter(Category == "B")
plot_B <- ggplot(data = df_B, aes(x=Year, y=Value)) + geom_line() + coord_cartesian(ylim = c(4.4,4.6)) + ggtitle("B")
grid.arrange(plot_A, plot_B, nrow=1)
Based on the info at Setting individual y axis limits with facet wrap NOT with scales free_y you can you use geom_blank() and manually specified y-limits by Category:
# df from above code
df2 <- tibble(
Category = c("A", "B"),
y_min = c(1.5, 4.4),
y_max = c(1.7, 4.6)
)
df <- full_join(df, df2, by = "Category")
ggplot(data = df, aes(x=Year, y=Value)) + geom_line() +
facet_wrap(.~ Category, scales = "free_y") +
geom_blank(aes(y = y_min)) +
geom_blank(aes(y = y_max))
The following sample or R code displays contour levels and the data points used in generating the contours.
n <- 10
x <- c(rnorm(n,-1,0.5), rnorm(n,1,0.5))
y <- c(rnorm(n,-1,1), rnorm(n,1,0.5))
df <- data.frame(x,y)
# categorise the points
df$cat <- sample(c(1,2), n, replace=T)
library(ggplot2)
p <- ggplot(df)
# for manual colouring of points, but not showing contours due to error
#p <- p + geom_point(aes(x=x,y=y,col=factor(cat)))
#cols <- c("1"="red", "2"="blue")
#p <- p + scale_color_manual(values=cols)
# this works fine except I am not controlling the colours
p <- p + geom_point(aes(x=x,y=y,col=cat))
p <- p + geom_density2d(aes(x=x,y=y,color=..level..))
print(p)
I am able to colour the points according to their binary category (see commented out code above) manually if I do not display the contours, but adding the contours results in a "Continuous value supplied to discrete scale" error.
Various attempts have failed.
The question: Is it possible to colour the points (according to category) and independently colour the contour levels (according to height)?
You can try
library(tidyverse)
df %>%
ggplot(aes(x=x,y=y)) +
stat_density_2d(aes(fill = ..level..), geom = "polygon") +
geom_point(aes(color=factor(cat)), size=5) +
theme_bw()
Or switch to points where fill is working like shape=21
df %>%
ggplot(aes(x=x,y=y)) +
geom_density2d(aes(color=..level..))+
geom_point(aes(fill=factor(cat)),color="black",shape=21, size=5) +
theme_bw() +
scale_fill_manual(values = c(2,4)) +
scale_color_continuous(low = "green", high = "orange")
or try to add scale_color_gradientn(colours = rainbow(10)) instead.
For the general plot in R, legend is used to number a figure.
set.seed(100)
Mydata=rnorm(65)
Year=1950:2014
plot(x=Year,y=Mydata,type = "l")
legend("topleft","(a)",bty = "n")
I wonder how we can do the same thing using ggplot2. Thanks.
Using grid it can be done independently of the data:
library(ggplot2)
qplot(Year, Mydata, geom = "line")
library(grid)
grid.text("(a)", 0.15, 0.85)
As of version 2.2.0, ggplot2 allows to plot subtitles and captions which can be utilized for this purpose.
subtitle (top left)
# create data frame as required by ggplot2
mydf <- data.frame(Year, Mydata)
library(ggplot2)
p <- ggplot(mydf, aes(Year, Mydata)) +
geom_line()
# plot subtitle (top left)
p + labs(subtitle = "(a)")
caption (bottom right)
# plot caption (bottom right)
p + labs(caption = "(a)")
A way with annotate:
library(ggplot2)
set.seed(100)
Mydata=rnorm(65)
Year=1950:2014
data <- data.frame(Mydata = Mydata, Year = Year)
#plot
ggplot(data, aes(Year, Mydata)) +
geom_line() +
annotate('text', x = 1960, y = 2, label = '(a)')
Output:
I have data where I look at the difference in growth between a monoculture and a mixed culture for two different species. Additionally, I made a graph to make my data clear.
I want a barplot with error bars, the whole dataset is of course bigger, but for this graph this is the data.frame with the means for the barplot.
plant species means
Mixed culture Elytrigia 0.886625
Monoculture Elytrigia 1.022667
Monoculture Festuca 0.314375
Mixed culture Festuca 0.078125
With this data I made a graph in ggplot2, where plant is on the x-axis and means on the y-axis, and I used a facet to divide the species.
This is my code:
limits <- aes(ymax = meansS$means + eS$se, ymin=meansS$means - eS$se)
dodge <- position_dodge(width=0.9)
myplot <- ggplot(data=meansS, aes(x=plant, y=means, fill=plant)) + facet_grid(. ~ species)
myplot <- myplot + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
myplot <- myplot + scale_fill_manual(values=c("#6495ED","#FF7F50"))
myplot <- myplot + labs(x = "Plant treatment", y = "Shoot biomass (gr)")
myplot <- myplot + opts(title="Plant competition")
myplot <- myplot + opts(legend.position = "none")
myplot <- myplot + opts(panel.grid.minor=theme_blank(), panel.grid.major=theme_blank())
So far it is fine. However, I want to add two different horizontal lines in the two facets. For that, I used this code:
hline.data <- data.frame(z = c(0.511,0.157), species = c("Elytrigia","Festuca"))
myplot <- myplot + geom_hline(aes(yintercept = z), hline.data)
However if I do that, I get a plot were there are two extra facets, where the two horizontal lines are plotted. Instead, I want the horizontal lines to be plotted in the facets with the bars, not to make two new facets. Anyone a idea how to solve this.
I think it makes it clearer if I put the graph I create now:
Make sure that the variable species is identical in both datasets. If it a factor in one on them, then it must be a factor in the other too
library(ggplot2)
dummy1 <- expand.grid(X = factor(c("A", "B")), Y = rnorm(10))
dummy1$D <- rnorm(nrow(dummy1))
dummy2 <- data.frame(X = c("A", "B"), Z = c(1, 0))
ggplot(dummy1, aes(x = D, y = Y)) + geom_point() + facet_grid(~X) +
geom_hline(data = dummy2, aes(yintercept = Z))
dummy2$X <- factor(dummy2$X)
ggplot(dummy1, aes(x = D, y = Y)) + geom_point() + facet_grid(~X) +
geom_hline(data = dummy2, aes(yintercept = Z))
I have two graphs with the same x axis - the range of x is 0-5 in both of them.
I would like to combine both of them to one graph and I didn't find a previous example.
Here is what I got:
c <- ggplot(survey, aes(often_post,often_privacy)) + stat_smooth(method="loess")
c <- ggplot(survey, aes(frequent_read,often_privacy)) + stat_smooth(method="loess")
How can I combine them?
The y axis is "often privacy" and in each graph the x axis is "often post" or "frequent read".
I thought I can combine them easily (somehow) because the range is 0-5 in both of them.
Many thanks!
Example code for Ben's solution.
#Sample data
survey <- data.frame(
often_post = runif(10, 0, 5),
frequent_read = 5 * rbeta(10, 1, 1),
often_privacy = sample(10, replace = TRUE)
)
#Reshape the data frame
survey2 <- melt(survey, measure.vars = c("often_post", "frequent_read"))
#Plot using colour as an aesthetic to distinguish lines
(p <- ggplot(survey2, aes(value, often_privacy, colour = variable)) +
geom_point() +
geom_smooth()
)
You can use + to combine other plots on the same ggplot object. For example, to plot points and smoothed lines for both pairs of columns:
ggplot(survey, aes(often_post,often_privacy)) +
geom_point() +
geom_smooth() +
geom_point(aes(frequent_read,often_privacy)) +
geom_smooth(aes(frequent_read,often_privacy))
Try this:
df <- data.frame(x=x_var, y=y1_var, type='y1')
df <- rbind(df, data.frame(x=x_var, y=y2_var, type='y2'))
ggplot(df, aes(x, y, group=type, col=type)) + geom_line()