I've got three subplots I want to put together into one plot, and faceting would be a natural way to do it. However, one of these subplots would be easier/more natural to read with a reversed x-axis (whereas I'd like to leave the others alone). Is there a way to accomplish this using facet_grid() or facet_wrap()?
The other alternative I've considered is grid.arrange(), and the chief problem I've run into there is getting it to align the subplots based on plot area (inside the axes), rather than based on the edges of the images. (My axis titles and labels are not the same size, so the default behavior is fairly ugly.)
Edited to add a MWE with some data for context. Here, since larger is "better" for the beta and R-squared subplots, it would be more natural to reverse the axis for the p subplot. (In this case it would probably also be better to add the log transform to that scale, but my real problem doesn't need to get that fancy.)
df <- data.frame(z=c(rep("R-squared",15),rep("p",15),rep("beta",15)),
x=c(runif(15),exp(-runif(15,1,10)),rnorm(15,1,0.5)),
y=rep(letters[1:15],3))
plot <- ggplot(df) + geom_point(aes(x=x,y=y)) + facet_grid(.~z, scales="free_x", switch="x")
Here's a solution using patchwork
library(ggplot2)
library(dplyr)
df <- data.frame(z=c(rep("R-squared",15),rep("p",15),rep("beta",15)),
x=c(runif(15),exp(-runif(15,1,10)),rnorm(15,1,0.5)),
y=rep(letters[1:15],3))
p1 <- ggplot(filter(df, z == "beta"), aes(x, y)) +
geom_point()
p2 <- ggplot(filter(df, z == "p"), aes(x, y)) +
geom_point() +
scale_x_reverse() +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank())
p3 <- ggplot(filter(df, z == "R-squared"), aes(x, y)) +
geom_point() +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank())
#devtools::install_github("thomasp85/patchwork")
library(patchwork)
p1 + p2 + p3
Related
I am trying to make a lollipop plot that includes a text 'condition' and a value associated. The issue I am having is that, because there is so much data, the labels overlap. Is there an easy fix for this?
This is my code (and my issue):
library(ggplot2)
df <- read.table(file = '24 hpi MP BP.tsv', sep = '\t', header = TRUE)
group <- df$Name
value <- df$Bgd.count
data <- data.frame(
x=group,
y=value
)
ggplot(data, aes(x=x, y=y)) +
geom_segment( aes(x=x, xend=x, y=0, yend=y), color="skyblue") +
geom_point( color="blue", size=4, alpha=0.6) +
theme_light() +
coord_flip() +
theme(
panel.grid.major.y = element_blank(),
panel.border = element_blank(),
axis.ticks.y = element_blank()
)
I am hoping to get a clear separation on the labels
Your question does not provide a reproducible example, so here a more general answer.
The problem is that you want to plot hundreds of discrete values. That is bound to yield a crowded graphic.
your options:
reduce the labels (don’t label all axis) and show only few labels .
focus only on few important data points - I think this would be my preferred approach, as you also give your “story” more justice.
Group your values and show “aggregate values” such as means/error bars
Make your graph appropriately large (change the height of the so called graphic device)
Use facets (but this will not really help with the crowding in all cases)
Shorten your labels
Make the font smaller
Last, but definitely not least, change your visualisation strategy.
I looked for answers in other Qs, couldn't find this Q (or Answer).
Using ggplot2 to generate the two plots individually.
Then using plot_grid function from the cowplot package to combine them.
They two data have exactly the same number of common dates.
Thus the x-axis is same time, I want the two graph's grey box to start from the same vertical spot,
so that they are time aligned. Presently, due to ylabs of different size, they don't start from same vertical line. Here is a pictorial description:
This could be achieved via the patchwork package:
library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars, aes(hp, mpg)) +
geom_point()
p2 <- ggplot(mtcars, aes(hp, mpg * 1000)) +
geom_point()
p1 / p2
If you want a solution that only uses plot_grid, you could do the following (admittedly hackier than the patchwork package):
myPlot1 <- ggplot()
myPlot2 <- ggplot()
#get a ggplot that is the axis only
myYAxis1 <- get_y_axis(myPlot1)
myYAxis2 <- get_y_axis(myPlot2)
#remove all y axis stuff from the plots themselves
myPlot1 <- myPlot1 + theme(axis.text.y = element_blank(), axis.title.y = element_blank(), axis.ticks.y = element_blank())
myPlot2 <- myPlot2 + theme(axis.text.y = element_blank(), axis.title.y = element_blank(), axis.ticks.y = element_blank())
#reassemble plots
ratioAxisToPlot = .1 #determine what fraction of the arranged plot you want to be axis and what fraction you want to be plot)
plot1Reassembled <- plot_grid(myYAxis1, myPlot1, rel_widths = c(ratioAxisToPlot, 1), ncol=2)
plot2Reassembled <- plot_grid(myYAxis2, myPlot2, rel_widths = c(ratioAxisToPlot, 1), ncol=2)
#put it all together
finalPlot <- plot_grid(plot1Reassembled, plot2Reassembled, nrow=2)
I want to combine these two graphs :
p1 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
facet_wrap(~ Species)
p2 <- ggplot(iris, aes(Sepal.Length)) +
geom_density()
To combine, I do :
multiplot(p1, p2, cols = 2)
But it is not the desired shape.
I would like the graph p2 has the same dimensions than others and is situated just next to the last faceted graph.
Thanks for help
Not sure if this is applicable in you generic case, but with facet_grid instead of facet_wrap, you can use the margins argument:
library(ggplot2)
ggplot(iris, aes(Sepal.Length)) +
geom_density() +
facet_grid(. ~ Species, margins = T)
If you question is more generic the answer probably lies in grid.arrange.
Something like this could be a start:
library(gridExtra)
grid.arrange(arrangeGrob(p1, p2,
widths = c(3,1),
heights = c(1,20),
layout_matrix = matrix(c(1,1,NA,2),2)))
As you can see there are several problems (different axes, top strip), but working with grid could gets complicated quickly.
This code should work:
p1 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
ylim(limits = c(0, 1.25))+
facet_wrap(~ Species)
p2 <- ggplot(iris, aes(Sepal.Length)) +
geom_density() +
ggtitle("") + # ad empty title as place holder
labs(y = "", x = "") + # hide axis labels
ylim(limits = c(0, 1.25)) + # y axis values should be fixed in both plots
coord_fixed(ratio=20/1) + # ratio of x- and y-axis to reduce width of plot
theme(axis.ticks.y = element_blank(), axis.text.y = element_blank(), axis.line.y = element_blank(),
plot.margin=unit(c(0,0,0.65,-10), "lines")) # margin between plots = "0.65"
I fiddled a bit and used just different styling options to produce this result. If you have more plots than this one I would recommend to use one theme for all.
You can use either the multiplot function that you are already using
multiplot(p1, p2, cols = 2)
or you install the packages gridExtra and grid and use that one:
grid.arrange(p1, p2, ncol=2)
Hope this helps!
I have a empirical PDF + CDF combo I'd like to plot on the same panel. distro.df has columns pdf, cdf, and day. I'd like the pdf values to be plotted as bars, and the cdf as lines. This does the trick for making the plot:
p <- ggplot(distro.df, aes(x=day))
p <- p + geom_bar(aes(y=pdf/max(pdf)), stat="identity", width=0.95, fill=fillCol)
p <- p + geom_line(aes(y=cdf))
p <- p + xlab("Day") + ylab("")
p <- p + theme_bw() + theme_update(panel.background = element_blank(), panel.border=element_blank())
However, I'm having trouble getting a legend to appear. I'd like a line for the cdf and a filled block for the pdf. I've tried various contortions with guides, but can't seem to get anything to appear.
Suggestions?
EDIT:
Per #Henrik's request: to make a suitable distro.df object:
df <- data.frame(day=0:10)
df$pdf <- runif(length(df$day))
df$pdf <- df$pdf / sum(df$pdf)
df$cdf <- cumsum(df$pdf)
Then the above to make the plot, then invoke p to see the plot.
This generally involves moving fill into aes and using it in both the geom_bar and geom_line layers. In this case, you also need to add show_guide = TRUE to geom_line.
Once you have that, you just need to set the fill colors in scale_fill_manual so CDF doesn't have a fill color and use override.aes to do the same thing for the lines. I didn't know what your fill color was, so I just used red.
ggplot(df, aes(x=day)) +
geom_bar(aes(y=pdf/max(pdf), fill = "PDF"), stat="identity", width=0.95) +
geom_line(aes(y=cdf, fill = "CDF"), show_guide = TRUE) +
xlab("Day") + ylab("") +
theme_bw() +
theme_update(panel.background = element_blank(),
panel.border=element_blank()) +
scale_fill_manual(values = c(NA, "red"),
breaks = c("PDF", "CDF"),
name = element_blank(),
guide = guide_legend(override.aes = list(linetype = c(0,1))))
I'd still like a solution to the above (and will checkout #aosmith's answer), but I am currently going with a slightly different approach to eliminate the need to solve the problem:
p <- ggplot(distro.df, aes(x=days, color=pdf, fill=pdf))
p <- p + geom_bar(aes(y=pdf/max(pdf)), stat="identity", width=0.95)
p <- p + geom_line(aes(y=cdf), color="black")
p <- p + xlab("Day") + ylab("CDF")
p <- p + theme_bw() + theme_update(panel.background = element_blank(), panel.border=element_blank())
p
This also has the advantage of displaying some of the previously missing information, namely the PDF values.
I'm trying to use facet_grid or facet_wrap in conjunction with geom_raster. However, in each panel, the z aesthetic is on a different scale. For example,
##Data at end of question
ggplot(dd, aes(x,y)) +
geom_raster(aes(fill=z)) +
facet_grid(type ~ var)
gives
.
However, since the average values of C and D are around 0 and 100 respectively, we lose a lot of resolution. You could also try:
##Change C to D to get other panel
ggplot(subset(dd, var=="C"), aes(x,y))+
geom_raster(aes(fill=z)) +
facet_grid(type ~ var) +
theme(legend.position="bottom")
which gives
and
but I now have two y strips.
Question
Can I alter the first plot to give two legends for the fill aesthetic?
Or, if I do two separate graphs, can I remove the y strip on one of the plots to allow me to press them together - messing about with the theme, suggests this isn't possible.
Data
Data to reproduce graphs
dd = expand.grid(x=1:10, y=1:10)
dd = data.frame(dd, type=rep(LETTERS[1:2], each=100),
var =rep(c("C", "D"), each=200) )
dd$z = rnorm(400, rep(c(0, 100), each=200))
What about this:
library(gridExtra)
p1 <- ggplot(subset(dd, var=="C"), aes(x,y))+
geom_raster(aes(fill=z)) + facet_grid(type ~ var) +
theme(legend.position="bottom", plot.margin = unit(c(1,-1,1,0.2), "line"))
p2 <- ggplot(subset(dd, var=="D"), aes(x,y))+
geom_raster(aes(fill=z)) + facet_grid(type ~ var) +
theme(legend.position="bottom", plot.margin = unit(c(1,1,1,-0.8), "line"),
axis.text.y = element_blank(), axis.ticks.y = element_blank()) + ylab("")
grid.arrange(arrangeGrob(p1, p2, nrow = 1))
also you might want to play around with plot.margin. And it seems that a negative answer to your first question can be found here.