Plot with multiple facets which have different scales. Simple example:
require(data.table)
require(ggplot2)
nr <- 10000
inp.dt <- rbind(
data.table(type="A", month=sample(seq(as.Date("2011/1/1"), as.Date("2012/1/1"), by="month"), nr, replace=T)),
data.table(type="B", month=sample(seq(as.Date("2011/1/1"), as.Date("2012/1/1"), by="month"), 100*nr, replace=T))
)
plot.dt <- inp.dt[, .(count=.N), .(type,month)]
mnth <- sort(unique(plot.dt[["month"]]))
plot.dt[, ":="(type=factor(type), month=factor(month, label=format(mnth, format="%Y-%b"), ordered=TRUE))]
g <- ggplot(plot.dt, aes(x=month, y=count)) +
geom_bar(stat="identity") + expand_limits(y=0) + facet_grid(type~., scales="free_y")
print(g)
If I remove scales= the top facet becomes uninteresting. Is there a way of showing this information as facets (not on separate pages), while still conveying the vast difference in scales. Eg, how can I set the ymax for the top facet only to a higher number?
I'm not sure what you want the scales set to, so I just picked some numbers arbitrarily.
require(data.table)
require(ggplot2)
nr <- 10000
inp.dt <- rbind(
data.table(type="A", month=sample(seq(as.Date("2011/1/1"), as.Date("2012/1/1"), by="month"), nr, replace=T)),
data.table(type="B", month=sample(seq(as.Date("2011/1/1"), as.Date("2012/1/1"), by="month"), 100*nr, replace=T))
)
plot.dt <- inp.dt[, .(count=.N), .(type,month)]
mnth <- sort(unique(plot.dt[["month"]]))
plot.dt[, ":="(type=factor(type), month=factor(month, label=format(mnth, format="%Y-%b"), ordered=TRUE))]
# g <- ggplot(plot.dt, aes(x=month, y=count)) +
# geom_bar(stat="identity") + expand_limits(y=0) + facet_grid(type~., scales="free_y")
# print(g)
g1 <- ggplot(plot.dt[plot.dt$type=="A",], aes(x=month, y=count)) + scale_y_continuous(limits=c(0,1500))+
geom_bar(stat="identity") + expand_limits(y=0) #+ facet_grid(type~., scales="free_y")
print(g1)
g2 <- ggplot(plot.dt[plot.dt$type=="B",], aes(x=month, y=count)) + scale_y_continuous(limits=c(0,800000))+
geom_bar(stat="identity") + expand_limits(y=0) #+ facet_grid(type~., scales="free_y")
print(g2)
install.packages("gridExtra")
library(gridExtra)
gA <- ggplotGrob(g1)
gB <- ggplotGrob(g2)
p <- arrangeGrob(
gA, gB, nrow = 2, heights = c(0.80, 0.80))
plot(p)
Related
I have a plot like this:
p<-ggplot() +
geom_line(data= myData, aes(x = myData$x , y = myData$y)) +
scale_x_log10()+
scale_y_log10()
My x value is seq(9880000, 12220000, 10000)
There is only one break on the x-axis of the plot, what should I do if to get at least 3 breaks on the plot x-axis?
Here is fully reproducible example of the original poster's problem where a log-scaled plot only displays one break value on the x-axis. I demonstrate three possible solutions below.
library(ggplot2)
# Create a reproducible example data.frame using R functions.
x = seq(9880000, 12220000, 10000)
# Use set.seed() so that anyone who runs this code
# will get the same sequence of 'random' values.
set.seed(31415)
y = cumsum(runif(n=length(x), min=-1e5, max=1e5)) + 1e6
dat = data.frame(x=x, y=y)
# Original poster's plot.
p1 = ggplot(data=dat, aes(x=x, y=y)) +
geom_line() +
scale_x_log10() +
scale_y_log10() +
labs(title="1. Plot has only one x-axis break.")
# Add extra x-axis breaks manually.
x_breaks = c(10^7.0, 10^7.04, 10^7.08)
p2 = ggplot(data=dat, aes(x=x, y=y)) +
geom_line() +
scale_x_log10(breaks=x_breaks) +
scale_y_log10() +
labs(title="2. Add some x-axis breaks manually.")
# Add extra x-axis breaks in semi-automated manner.
x_breaks = 10^pretty(log10(x))
x_labels = formatC(x_breaks, format = "e", digits = 2)
p3 = ggplot(data=dat, aes(x=x, y=y)) +
geom_line() +
scale_x_log10(breaks=x_breaks, labels=x_labels) +
scale_y_log10() +
labs(title="3. Create x-axis breaks with R functions.")
# Skip the log10 scale because the x-values don't span multiple orders of magnitude.
p4 = ggplot(data=dat, aes(x=x, y=y)) +
geom_line() +
scale_y_log10() +
labs(title="4. Check appearance without log10 scale for x-axis.")
library(gridExtra)
ggsave("example.png", plot=arrangeGrob(p1, p2, p3, p4, nrow=2),
width=10, height=5, dpi=150)
I add: scale_x_log10(breaks=seq(9880000, 12220000, 1000000)).
This is my reproducible example:
library(random)
library(ggplot2)
z <- randomStrings(n=235, len=5, digits=TRUE, upperalpha=TRUE, loweralpha=TRUE, unique=TRUE, check=TRUE)
x <- seq(9880000, 12220000, 10000)
y <- randomNumbers(n=235, min=9880000, max=12220000, col=1)
df <- data.frame(z, x, y)
head(df)
V1 x V1.1
1 378VO 9880000 11501626
2 AStRK 9890000 10929705
3 sotp4 9900000 11305700
4 AS4DR 9910000 11302110
5 7iFdk 9920000 11611918
6 HIS7z 9930000 11175074
p<-ggplot() + geom_line(data= df, aes(x = df$x , y = df$V1.1)) + scale_y_log10()
p + scale_x_log10(breaks=seq(9880000, 12220000, 1000000))
Hope it is useful...
Add this between your parenthesis: breaks=seq(specify, breaks, here)
For example, if you wanted a break at 0, 10, 100:
scale_x_log10((breaks=seq(0,10,100))
By using this function, I can add outliers values into the plot of mpg
outlier_values. <- lapply(mtcars[-c(8,9)], function(x){outlier_values <- boxplot.stats(x)$out})
boxplot(mtcars$mpg, main="Pressure Height", boxwex=0.1)
mtext(paste("Outliers: ", paste(outlier_values., collapse=", ")), cex=0.6)
Buy now I want to add the outlier values (outlier1) to the plot of all variables:
library(reshape2)
library(ggplot2)
outlier <- do.call("cbind", lapply(mtcars[-c(8,9)], function(x) boxplot.stats(x)$out))
outlier1 <- melt(outlier)
mtcars_m = melt(mtcars[,-c(8,9)])
names(mtcars_m)=c("X2","CI")
box.plot<- ggplot(mtcars_m, aes(X2, CI,fill=Models)) +
geom_boxplot(width = 0.1) +
facet_wrap(~ Models, scales = "free") +
guides(fill=FALSE) +
labs(x="", y="") +
ggtitle("Box Plots")
How can I do that?
Your code contains some variables which are undefined (Models). I assume you meant X2. Here is the ggplot2 solution:
outlier1 <- melt(data.frame(outlier))
colnames(mtcars_m) <- colnames(outlier1) <- c("X2","CI")
mtcars_m$Outlier <- FALSE
outlier1$Outlier <- TRUE
ggData <- rbind(mtcars_m, outlier1)
ggplot(ggData, aes(x=X2, y=CI, fill=X2) ) +
geom_boxplot() +
geom_point(aes(colour=Outlier)) +
labs(x="",y="") +
ggtitle("Box Plots") +
guides(fill=FALSE) +
facet_wrap(~ X2, scales = "free")
I am trying to learn ggplot2 and have made below plots:
Using this code:
library(ggplot2); library(gridExtra)
gg <- ggplot(mydata,aes(x=Level))
plot1 <- gg + geom_line(aes(y=Experience,colour="xp"),size=1) +
labs(title="xp")
g <- ggplot(mydata,aes(x=Level))
plot2 <- g + geom_line(aes(y=Experience,colour="xp"),size=1) + geom_line(aes(y=Accu,colour="accu"),size=1) +
labs(title="xp vs Accumulated")
grid.arrange(plot1,plot2,ncol=2)
Where mydata is a data frame containing 3 columns (Level, xp and accu) and 30 rows.
What I am wondering is:
How to get the y-axis on the left-hand plot to have the same form as the
right-hand plot.
How to make the color of "xp" the same in both plots
without removing the descriptions of what the lines represent.
How about this (with some random data)?
library(ggplot2)
library(gridExtra)
library(scales)
gg <- ggplot(mydata,aes(x=Level))
plot1 <- gg + geom_line(aes(y=Experience,colour="xp"),size=1) +
labs(title="xp") + scale_y_continuous(labels = comma) +
scale_colour_manual(values = c("red"))
g <- ggplot(mydata,aes(x=Level))
plot2 <- g + geom_line(aes(y=Experience,colour="xp"),size=1) +
geom_line(aes(y=Accu,colour="accu"),size=1) +
labs(title="xp vs Accumulated") + scale_y_continuous(labels = comma) +
scale_colour_manual(values = c("blue", "red"))
grid.arrange(plot1,plot2,ncol=2)
I'm using ggplot and have two graphs that I want to display on top of each other. I used grid.arrange from gridExtra to stack them. The problem is I want the left edges of the graphs to align as well as the right edges regardless of axis labels. (the problem arises because the labels of one graph are short while the other is long).
The Question:
How can I do this? I am not married to grid.arrange but the ggplot2 is a must.
What I've tried:
I tried playing with widths and heights as well as ncol and nrow to make a 2 x 2 grid and place the visuals in opposite corners and then play with the widths but I couldn't get the visuals in opposite corners.
require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip()
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip()
grid.arrange(A, B, ncol=1)
Try this,
gA <- ggplotGrob(A)
gB <- ggplotGrob(B)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
grid.arrange(gA, gB, ncol=1)
Edit
Here's a more general solution (works with any number of plots) using a modified version of rbind.gtable included in gridExtra
gA <- ggplotGrob(A)
gB <- ggplotGrob(B)
grid::grid.newpage()
grid::grid.draw(rbind(gA, gB))
I wanted to generalize this for any number of plots. Here is a step-by-step solution using the approach by Baptiste:
plots <- list(A, B, C, D)
grobs <- list()
widths <- list()
collect the widths for each grob of each plot
for (i in 1:length(plots)){
grobs[[i]] <- ggplotGrob(plots[[i]])
widths[[i]] <- grobs[[i]]$widths[2:5]
}
use do.call to get the max width
maxwidth <- do.call(grid::unit.pmax, widths)
asign the max width to each grob
for (i in 1:length(grobs)){
grobs[[i]]$widths[2:5] <- as.list(maxwidth)
}
plot
do.call("grid.arrange", c(grobs, ncol = 1))
Using cowplot package:
A <- ggplot(CO2, aes(x = Plant)) + geom_bar() + coord_flip()
B <- ggplot(CO2, aes(x = Type)) + geom_bar() + coord_flip()
library(cowplot)
plot_grid(A, B, ncol = 1, align = "v")
On http://rpubs.com/MarkusLoew/13295 is a really easy solution available (last item)
Applied to this problem:
require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip()
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip()
grid.draw(rbind(ggplotGrob(A), ggplotGrob(B), size="first"))
you can also use this for both width and height:
require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip()
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip()
C <- ggplot(CO2, aes(x=conc)) + geom_bar() +coord_flip()
D <- ggplot(CO2, aes(x=uptake)) + geom_bar() +coord_flip()
grid.draw(cbind(
rbind(ggplotGrob(A), ggplotGrob(B), size="first"),
rbind(ggplotGrob(C), ggplotGrob(D), size="first"),
size='first'))
The egg package wraps ggplot objects into a standardised 3x3 gtable, enabling the alignment of plot panels between arbitrary ggplots, including facetted ones.
library(egg) # devtools::install_github('baptiste/egg')
library(ggplot2)
p1 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point()
p2 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
geom_point() + facet_wrap( ~ cyl, ncol=2, scales = "free") +
guides(colour="none") +
theme()
ggarrange(p1, p2)
Here is another possible solution using melt from the reshape2 package, and facet_wrap:
library(ggplot2)
library(reshape2)
dat = CO2[, c(1, 2)]
dat$id = seq(nrow(dat))
mdat = melt(dat, id.vars="id")
head(mdat)
# id variable value
# 1 1 Plant Qn1
# 2 2 Plant Qn1
# 3 3 Plant Qn1
# 4 4 Plant Qn1
# 5 5 Plant Qn1
# 6 6 Plant Qn1
plot_1 = ggplot(mdat, aes(x=value)) +
geom_bar() +
coord_flip() +
facet_wrap(~ variable, nrow=2, scales="free", drop=TRUE)
ggsave(plot=plot_1, filename="plot_1.png", height=4, width=6)
The patchwork package handles this by default:
library(ggplot2)
library(patchwork)
A <- ggplot(CO2, aes(x = Plant)) + geom_bar() + coord_flip()
B <- ggplot(CO2, aes(x = Type)) + geom_bar() + coord_flip()
A / B
Created on 2019-12-08 by the reprex package (v0.3.0)
I know this is an old post, and that it has already been answered, but may I suggest combining #baptiste's approach with purrr to make it nicer-looking:
library(purrr)
list(A, B) %>%
map(ggplotGrob) %>%
do.call(gridExtra::gtable_rbind, .) %>%
grid::grid.draw()
At best this is a hack:
library(wq)
layOut(list(A, 1, 2:16), list(B, 2:3, 1:16))
It feels really wrong though.
Let's say we have a simple plot of the following kind.
library(ggplot2)
df = data.frame(y=c(0,1.1,2.3,3.1,2.9,5.8,6,7.4,8.2,9.1),x=seq(1,100, length.out=10))
ggplot(df,aes(x=x,y=y)) + geom_point()
x perfectly correlates with z. The relation is: Constant=x^2*z=1.23
therefore I could rewrite the data.frame like this:
df = cbind(df,1.23/df$x^2)
The question is:
How can I display both variables xand zone the x-axis? It could be one at the bottom and one at the top of the graph or both at the bottom.
Here's a dangerous attempt. Previous version with a log-scale was just wrong.
library(ggplot2)
df = data.frame(y=c(0,1.1,2.3,3.1,2.9,5.8,6,7.4,8.2,9.1),
x=seq(1,100, length.out=10))
df$z = 1.23/df$x^2
## let's at least remove the gridlines
p1 <- ggplot(df,aes(x=x,y=y)) + geom_point() +
scale_x_continuous(expand=c(0,0)) +
theme(panel.grid.major=element_blank(),
panel.grid.minor = element_blank())
## make sure both plots have expand = c(0,0)
## otherwise data and top-axis won't necessarily be aligned...
p2 <- ggplot(df,aes(x=z,y=y)) + geom_point() +
scale_x_continuous(expand=c(0,0))
library(gtable)
g1 <- ggplotGrob(p1)
g2 <- ggplotGrob(p2)
tmp <- gtable_filter(g2, pattern="axis-b")
## ugly tricks to extract and reshape the axis
axis <- tmp[["grobs"]][[1]][["children"]][["axis"]] # corrupt the children
axis$layout <- axis$layout[2:1,]
axis$grobs[[1]][["y"]] <- axis$grobs[[1]][["y"]] - unit(1,"npc") + unit(0.15,"cm")
## back to "normality"
g1 <- gtable_add_rows(g1, sum(tmp$heights), 2)
gtableAddGrobs <- gtable_add_grob # alias, making sure #!hadley doesn't see this
g1 <- gtableAddGrobs(g1,
grobs=list(gtable_filter(g2, pattern="xlab"),axis),
t=c(1,3), l=4)
grid.newpage()
grid.draw(g1)
A both-on-the-bottom approach can be done with the excellent cowplot library.
library(ggplot2)
library(cowplot)
data <- data.frame(temp_c=runif(100, min=-5, max=30), outcome=runif(100))
plot <- ggplot(data) +
geom_point(aes(x=temp_c, y=outcome)) +
theme_classic() +
labs(x='Temperature (Celsius)')
x2plot <- ggplot(data) +
geom_point(aes(x=temp_c, y=outcome)) +
theme_classic() +
scale_x_continuous(label=function(x){round(x*(9/5) + 32)}) +
labs(x='Temperature (Fahrenehit)')
x <- get_x_axis(x2plot)
xl <- get_plot_component(x2plot, "xlab-b")
plot_grid(plot, ggdraw(x), ggdraw(xl), align='v', axis='rl', ncol=1,
rel_heights=c(0.8, 0.05, 0.05))