How to wrap a wrapped plot plus another plot? [duplicate] - r

This question already has answers here:
Side-by-side plots with ggplot2
(14 answers)
Closed 2 years ago.
I want the six plots in one plot. And I would like to specify the titles of each plot. How can I do that?
p<-ggplot(df, aes(x=COD_NEIGHB))+
geom_bar(stat="count", width=0.3, fill="steelblue")+
theme_minimal()
# histogram of the strata in the whole dataset
s<-ggplot(data = df, mapping = aes(x = COD_NEIGHB)) +
geom_bar(stat="count", width=0.3, fill="steelblue")+
facet_wrap(~ fold)
plot_grid(p, s, ncol=2,label_size = 2)
After that, I did the suggestion
df$fold <- as.character(df$fold)
# Duplicate data. Set category in the duplicated dataset to "all"
df_all <- df
df_all$fold <- "all"
# Row bind the datasets
df_all <- rbind(df, df_all)
ggplot(df_all, aes(x=COD_NEIGHB)) +
geom_bar(stat="count", width=0.3, fill="steelblue")+
facet_wrap(~fold)
But now the problem is the scale. y-axis has to be on the proper scale.
any idea for that?
Thanks in advance!!!!

If I got you right you want a plot with facets by categories plus an additonal facet showing the total data. One option to achieve this is to duplicate your dataset to add an addtional category "all".
As no example data was provided I make use of mtcars to show you the basic idea:
library(ggplot2)
mtcars$cyl <- as.character(mtcars$cyl)
# Duplicate data. Set category in the duplicated dataset to "all"
mtcars_all <- mtcars
mtcars_all$cyl <- "all"
# Row bind the datasets
mtcars_all <- rbind(mtcars, mtcars_all)
ggplot(mtcars_all, aes(hp, mpg)) +
geom_point() +
facet_wrap(~cyl)

Here is another useful tool with the help of the ggarrange() function from the ggpubr package. You can arrange multiple plots on one page or multiple pages. You can also create a common, unique legend once you merge all your plots together.
Similar to previous answers, I used mtcars to demonstrate a simple use case:
#install.packages("ggpubr")
#library(ggpubr)
p1 <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
theme_minimal()
p2 <- ggplot(mtcars, aes(y = mpg, x = cyl)) +
geom_boxplot() +
theme_minimal()
ggarrange(p1, p2, ncol = 2)

Related

How to group bars in ggplot2 barplot

I'm trying to created a paired bar plot, with each pair comparing a preop and a postop score. 3 of the comparisons are from using procedure A (SDR), and the other 3 are from using procedure B (ITB). I'm looking for a way to categorize these bars with an additional variable (procedure).
Here's my code:
newMAS <- read.csv(header=TRUE, "allMASpaired.csv")
#Prevent Time from getting alphabeticalized
newMAS$Paper <- factor(newMAS$Paper,
levels=unique(as.character(newMAS$Paper)) )
newMAS$Time <- factor(newMAS$Time, levels=unique(as.character(newMAS$Time)) )
library(ggplot2)
pdf(file="allMASplotPAIRED.pdf")
ggplot(data=newMAS, aes(x=Paper, y=MAS, fill=Time)) +
geom_bar(stat="identity", position=position_dodge(), color="black") +
geom_text(aes(label=n), vjust=-1) +
scale_fill_brewer(palette="Set1") + theme_classic()
Thanks for the link to your data.
I added a column called surg.type. Guessed which papers where SDR and which
where ITB. Change accordingly.
library(dplyr)
#some data munging
allMAS %>% # adding a surg.type
mutate(surg.type = case_when(
(Paper %in% c("Ailon","D'Aquino","Ingale")) ~ "SDR",
TRUE ~ "ITB")) ->allMAS
Then plotted it, i did facet_wrap on surg.type, this groups papers of one type together in one panel and also did scales="free_x" so the x labels are not repeated. try it without it, to see what happens
ggplot(allMAS, aes(y=mas,x=paper)) +
geom_bar(aes(fill=time),stat="identity", position=position_dodge()) +
scale_fill_brewer(palette="Set1") +facet_wrap(~surg.type, scales = "free_x")

Keeping the width constant in ggplot in R

Have already tried this link but it fails to work, moreover this question was asked 5 years ago so I hope there is a better way around than this lengthy code.
How to make the width of bars and spaces between them fixed for several barplots using ggplot, having different number of bars on each plot?
#with 10 bins
data <- data.frame(x=1:10,y=runif(10))
library(ggplot2)
ggplot(data, aes(x,y)) + geom_bar(stat="identity")
#with 3 bins
ggplot(data[1:3,], aes(x,y)) + geom_bar(stat="identity")
Adding width=1 to geom_bar(...) doesn't help as well. I need the second plot automatically to have less width and the same bar width and spaces as the first one.
One solution would be to adjust the coordinates to match:
ggplot(data[1:3,], aes(x,y)) + geom_bar(stat="identity") +
scale_x_continuous(limits = c(0.5,10)) # This is approximate but pretty close.
#
# For an exact match, you can go into the ggplot_build object and
# extract [["layout"]][["panel_params"]][[1]][["x.range"]]
# You could then use the exact values:
# scale_x_continuous(limits = c(0.055,10.945), expand = c(0,0))
Another would be to combine the bars into one plot, and then use facets to show the data on the same scale.
library(dplyr)
data2 <-
data %>% mutate(plot = "A") %>%
bind_rows(
data[1:3,] %>% mutate(plot = "B")
)
(a <- ggplot(data2, aes(x,y)) + geom_bar(stat="identity") +
facet_grid(~plot)
)
If you want to use this with plotly, you could then use plotly::ggplotly(a).

How to plot two histograms on the same axis scale?

I have two dataframes: dataf1, dataf2. They have the same structure and columns.
3 columns names are A,B,C. And they both have 50 rows.
I would like to plot the histogram of column B on dataf1 and dataf2. I can plot two histograms separately but they are not of the same scale. I would like to know how to either put them on the same histogram using different colors or plot two histograms of the same scale?
ggplot() + aes(dataf1$B)+ geom_histogram(binwidth=1, colour="black",fill="white")
ggplot() + aes(dataf2$B)+ geom_histogram(binwidth=1, colour="black", fill="white")
Combine your data into a single data frame with a new column marking which data frame the data originally came from. Then use that new column for the fill aesthetic for your plot.
data1$source="Data 1"
data2$source="Data 2"
dat_combined = rbind(data1, data2)
You haven't provided sample data, so here are a few examples of possible plots, using the built-in iris data frame. In the plots below, dat is analogous to dat_combined, Petal.Width is analogous to B, and Species is analogous to source.
dat = subset(iris, Species != "setosa") # We want just two species
ggplot(dat, aes(Petal.Width, fill=Species)) +
geom_histogram(position="identity", colour="grey40", alpha=0.5, binwidth=0.1)
ggplot(dat, aes(Petal.Width, fill=Species)) +
geom_histogram(position="dodge", binwidth=0.1)
ggplot(dat, aes(Petal.Width, fill=Species)) +
geom_histogram(position="identity", colour="grey40", binwidth=0.1) +
facet_grid(Species ~ .)
As Zheyuan says, you just need to set the y limits for each plot to get them on the same scale. With ggplot2, one way to do this is with the lims command (though scale_y_continuous and coord_cartesian also work, albeit slightly differently). You also should never use data$column indside aes(). Instead, use the data argument for the data frame and unquoted column names inside aes(). Here's an example with some built-in data.
p1 = ggplot(mtcars, aes(x = mpg)) + geom_histogram() + lims(y = c(0, 13))
p2 = ggplot(iris, aes(x = Sepal.Length)) + geom_histogram() + lims(y = c(0, 13))
gridExtra::grid.arrange(p1, p2, nrow = 1)
Two get two histograms on the same plot, the best way is to combine your data frames. A guess, without seeing what your data looks like:
dataf = rbind(dataf1["B"], dataf2["B"])
dafaf$source = c(rep("f1", nrow(dataf1)), rep("f2", nrow(dataf2))
ggplot(dataf, aes(x = B, fill = source)) +
geom_histogram(position = "identity", alpha = 0.7)

Removing Empty Facet Categories

Am having trouble making my faceted plot only display data, as opposed to displaying facets with no data.
The following code:
p<- ggplot(spad.data, aes(x=Day, y=Mean.Spad, color=Inoc))+
geom_point()
p + facet_grid(N ~ X.CO2.)
Gives the following graphic:
I have played around with it for a while but can't seem to figure out a solution.
Dataframe viewable here: https://docs.google.com/spreadsheets/d/11ZiDVRAp6qDcOsCkHM9zdKCsiaztApttJIg1TOyIypo/edit?usp=sharing
Reproducible Example viewable here: https://docs.google.com/document/d/1eTp0HCgZ4KX0Qavgd2mTGETeQAForETFWdIzechTphY/edit?usp=sharing
Your issue lies in the missing observations for your x- and y variables. Those don't influence the creation of facets, that is only influenced by the levels of faceting variables present in the data. Here is an illustration using sample data:
#generate some data
nobs=100
set.seed(123)
dat <- data.frame(G1=sample(LETTERS[1:3],nobs, T),
G2 = sample(LETTERS[1:3], nobs, T),
x=rnorm(nobs),
y=rnorm(nobs))
#introduce some missings in one group
dat$x[dat$G1=="C"] <- NA
#attempt to plot
p1 <- ggplot(dat, aes(x=x,y=y)) + facet_grid(G1~G2) + geom_point()
p1 #facets are generated according to the present levels of the grouping factors
#possible solution: remove the missing data before plotting
p2 <- ggplot(dat[complete.cases(dat),], aes(x=x, y=y)) + facet_grid(G1 ~G2) + geom_point()
p2

How to use scale from previous plot in current plot with ggplot2?

I am using ggplot2 to produce a plot that has 3 facets. Because I am comparing two different data sets, I would like to then be able to plot a second data set using the same y scale for the facets as in the first plot. However, I cannot find a simple way to save the settings of the first plot to then re-use them with the second plot. Since each facet has its own y scale, it will be a pain to specify them by hand for the second plot. Does anyone know of a quick way of re-using scales? To make this concrete, here is how I am generating first my plot:
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + facet_wrap(~ cyl, scales = "free_y")
EDIT
When applying one of the suggestions below, I found out that my problem was more specific than described in the original post, and it had to do specifically with scaling of the error bars. Concretely, the error bars look weird when I rescale the second plot as suggested. Does anyone have any suggestions on how to keep the same scale for both plots and dtill display the error bars correctly? I am attaching example below for concreteness:
#Create sample data
d1 <- data.frame(fixtype=c('ff','ff','fp','fp'), detype=c('det','pro','det','pro'),
diffscore=c(-1,-15,3,-17),se=c(2,3,1,2))
d2 <- data.frame(fixtype=c('ff','ff','fp','fp'), detype=c('det','pro','det','pro'),
diffscore=c(-1,-3,-2,-1),se=c(4,3,5,3))
#Plot for data frame 1, this is the scale I want to keep
lim_d1 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) +
geom_point(aes(size=1), shape=15) +
geom_errorbar(lim_d1, width=0.2,size=1) +
facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")
#Plot for data frame 2 original scale
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d2, aes(colour=detype, y=diffscore, x=detype)) +
geom_point(aes(size=1), shape=15) +
geom_errorbar(lim_d2, width=0.2,size=1) +
facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")
#Plot for data frame 2 adjusted scale. This is where things go wrong!
#As suggested below, first I plot the first plot, then I draw a blank screen and try
#to plot the second data frame on top.
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) +
geom_blank() +
geom_point(data=d2, aes(size=1), shape=15) +
geom_errorbar(lim_d2, width=0.2,size=1) +
facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")
#If the error bars are fixed, by adding data=d2 to geom_errorbar(), then
#the error bars are displayed correctly but the scale gets distorted again
lim_d2 <- aes(ymax = diffscore + se, ymin=diffscore - se)
ggplot(d1, aes(colour=detype, y=diffscore, x=detype)) +
geom_blank() +
geom_point(data=d2, aes(size=1), shape=15) +
geom_errorbar(data=d2,lim_d2, width=0.2,size=1) +
facet_wrap(~fixtype, nrow=2, ncol=2, scales = "free_y")
You may first call ggplot on your original data where you add a geom_blank as a first layer. This sets up a plot area, with axes and legends based on the data provided in ggplot.
Then add geoms which use data other than the original data. In the example, I use a simple subset of the original data.
From ?geom_blank: "The blank geom draws nothing, but can be a useful way of ensuring common scales between different plots.".
ggplot(data = mtcars, aes(mpg, wt)) +
geom_blank() +
geom_point(data = subset(mtcars, wt < 3)) +
facet_wrap(~ cyl, scales = "free_y")
Here is an ugly hack that assumes you have an identical facetting layout in both plots.
It replaces the panel element of the ggplot build.
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p1 <- p + facet_wrap(~ cyl, scales = "free_y") + labs(title = 'original')
# create "other" data.frame
n <- nrow(mtcars)
set.seed(201405)
mtcars2 <- mtcars[sample(seq_len(n ),n-15),]
# create this second plot
p2 <- p1 %+% mtcars2 + labs(title = 'new data')
# and a copy so we can attempt to fix
p3 <- p2 + labs(title = 'new data original scale')
# use ggplot_build to construct the plots for rendering
p1b <- ggplot_build(p1)
p3b <- ggplot_build(p3)
# replace the 'panel' information in plot 2 with that
# from plot 1
p3b[['panel']] <- p1b[['panel']]
# render the revised plot
# for comparison
library(gridExtra)
grid.arrange(p1 , p2, ggplot_gtable(p3b))

Resources