I would like to plot a bar chart and a table below it using ggplot2 and knitting to word via Rmd. However, I need my plot to be a bit bigger and my respective table to be a bit smaller. The current code produces a very small bar plot. Below is a working example.
library(tidyverse)
library(grid)
library(gridExtra)
#plot
g <- ggplot(mpg, aes(class))
g<-g + geom_bar()
#table
dat<-mpg %>% count(class) %>%
t() %>%
as.data.frame() %>%
row_to_names(row_number = 1)
table <- tableGrob(dat)
#table and plot
plot2_fin<-grid.arrange(arrangeGrob(nullGrob(), g ,
widths=c(3,8)),
arrangeGrob(arrangeGrob(nullGrob(),table, widths=c(3,18,1)),
heights=c(1,1)))
plot2_fin
You might consider moving from grid to cowplot
library(tidyverse)
library(grid)
library(gridExtra)
#plot
g <- ggplot(mpg, aes(class))
g<-g + geom_bar()
#table
dat<-mpg %>% count(class) %>%
t() %>%
as.data.frame() %>%
row_to_names(row_number = 1)
table <- tableGrob(dat)
#table and plot
library(cowplot)
plot_grid(g, table,
ncol = 1,
rel_heights = c(4, 1))
Related
With code below (edited basing on code from here) I generates two example tables with gt package:
library(tidyverse)
library(patchwork)
library(gt)
p1 <- mtcars %>%
head(5) %>%
gt()
p2 <- mtcars %>%
tail(5) %>%
gt()
# using wrap elements because this seems to be the answer to non-ggplot grobs e.g. #164
wrap_elements(full = p1 | p2)
grid.arrange(p1, p2, ncol=2, top="Main Title")
Out:
Error in p1 | p2 :
operations are possible only for numeric, logical or complex types
I hope to combine them into one as for ggplot objects: p <- (p1 | p2) using patchwork package, but I didn't find an effective answer yet.
I also try to convert it to ggplot using as_ggplot() function:
library(bstfun)
mtcars %>%
head(5) %>%
gt() %>%
as_ggplot()
But it raises an error:
Error: '.assert_package' is not an exported object from 'namespace:broom.helpers'
Is it possible to do so? Thanks for your help at advance.
Reference:
R - combine two gt objects in a single page output
I can offer to you this solution:
1. We take your data:
p1 <- mtcars %>%
head(5) %>%
gt()
p2 <- mtcars %>%
tail(5) %>%
gt()
2. Let's save your tables into .png's:
p1 %>%
gtsave("p11.png", path = "Your_working_dir")
p2 %>%
gtsave("p12.png", path = "Your_working_dir")
3. Let's combine your tables:
library(cowplot)
p111 <- ggdraw() + draw_image("p11.png", scale = 0.8)
p112 <- ggdraw() + draw_image("p12.png", scale = 0.8)
plot_grid(p111, p112)
Our result:
I am trying to obtain a bar plot where each bar is made of a pile of squares, so that it is easier to count the observations on each bar. Here is a minimal example
library(ggplot2)
d = data.frame(p = rbinom(20,10,.3))
d %>% ggplot(aes(x=p))+geom_bar(fill="white",color="black",position="stack",alpha=.5)+
theme_void()
Which gives something like:
Basically, I'd like to have horizontal separating lines at every unit on the bars.
This approach can be useful:
library(ggplot2)
library(dplyr)
#Data
d = data.frame(p = rbinom(20,10,.3))
#Plot
d %>%
group_by(p) %>%
mutate(col=row_number()) %>%
ggplot(aes(x=p,fill=factor(col)))+
geom_bar(position="stack",alpha=.5,color='black')+
theme_void()+
scale_fill_manual(values=rep('white',5))+
theme(legend.position = 'none')
Output:
For my data.frame full below, I'm wondering how to create a two-panel geom_point such that on the first panel, we have ols.(Intercept) (x-axis) plotted against hlm.(Intercept), AND on the second panel, we have ols.ses (x-axis) plotted against hlm.ses?
library(lme4)
library(tidyverse)
hsb <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/hsb.csv')
fit <- lmer(math~ses+(ses|sch.id), data= hsb)
ch <- unique(hsb$sch.id)
ols <- map_dfr(ch,~coef(lm(math~ses, data=hsb,subset=sch.id==.)))
mlm <- coef(fit)$sch
full <- cbind(ols=ols, hlm=mlm, sch.id=ch)
head(full, n = 1)
ols.(Intercept) ols.ses hlm.(Intercept) hlm.ses sch.id
1224 10.80513 2.508582 11.06002 2.504083 1224
One approach to achieve this is by making two separate plots and glue them together using e.g. patchwork:
library(lme4)
library(tidyverse)
library(patchwork)
hsb <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/hsb.csv')
fit <- lmer(math~ses+(ses|sch.id), data= hsb)
ch <- unique(hsb$sch.id)
ols <- map_dfr(ch,~coef(lm(math~ses, data=hsb,subset=sch.id==.)))
mlm <- coef(fit)$sch
full <- cbind(ols=ols, mlm=mlm, sch.id=ch)
p1 <- ggplot(full, aes(`ols.(Intercept)`, `mlm.(Intercept)`)) +
geom_point()
p2 <- ggplot(full, aes(ols.ses, mlm.ses)) +
geom_point()
p1 + p2
And as a second approach with some data wrangling one can achieve a similar plot using facet_wrap:
library(lme4)
#> Loading required package: Matrix
library(tidyverse)
hsb <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/hsb.csv')
fit <- lmer(math~ses+(ses|sch.id), data= hsb)
ch <- unique(hsb$sch.id)
ols <- map_dfr(ch,~coef(lm(math~ses, data=hsb,subset=sch.id==.)))
mlm <- coef(fit)$sch
full <- cbind(ols=ols, mlm=mlm, sch.id=ch)
full %>%
pivot_longer(- sch.id, names_to = "var", values_to = "value") %>%
separate(var, into = c("var1", "category"), sep = "\\.") %>%
pivot_wider(names_from = var1, values_from = value) %>%
ggplot(aes(ols, mlm)) +
geom_point() +
facet_wrap(~ category)
An option with facets. The solution from #stefan was really nice and quick. You could set an entire data pipeline by smartly separating your strings and then after reshaping you can have the desired variables in a format to be plotted using facet_wrap(). Here the code:
library(tidyverse)
#Plot
full %>% select(-sch.id) %>% pivot_longer(everything()) %>%
separate(name,c('V1','V2'),sep='\\.') %>%
arrange(V2,V1) %>%
group_by(V2,V1) %>% mutate(id=row_number()) %>%
pivot_wider(names_from = V1,values_from=value) %>% ungroup() %>%
select(-id) %>%
ggplot(aes(x=ols,y=mlm))+
geom_point()+
facet_wrap(.~V2,nrow = 1,scales = 'free')
Output:
Similar to the answer using patchwork, you can plot them as two separate ggplot() graphs and then put them side-by-side with the plot_grid() function from the cowplot package.
https://cran.r-project.org/web/packages/cowplot/vignettes/introduction.html
How can I make the panels of separate ggplots align when the y-axis labels change in length across plots? Below I've saved two subsets of mtcars with longer and shorter model names. Although the overall plots are the same size, the panels are smaller in the mt_long plot because the y-axis labels take up more of the plot.
library(dplyr)
library(ggplot2)
ds_mt <- mtcars %>% rownames_to_column("model")
mt_short <- ds_mt %>% arrange(nchar(model)) %>% slice(1:4)
mt_long <- ds_mt %>% arrange(-nchar(model)) %>% slice(1:4)
plot_short <-
mt_short %>%
ggplot(aes(x = model, y = mpg)) +
geom_col() +
coord_flip()
plot_long <-
mt_long %>%
ggplot(aes(x = model, y = mpg)) +
geom_col() +
coord_flip()
plot_short
plot_long
For this reprex, it is important that the plots be separate. Is there any way to set just the panel dimensions of the plot rather than the overall size of the plot?
We can use gridarrange from the egg package
library(egg)
ggarrange(plot_short, plot_long, ncol = 1)
To save, use
gg <- ggarrange(plot_short, plot_long, ncol = 1)
ggsave("file.png", gg)
try egg::set_panel_size(plot_short)
I have the following workflow:
rm(list=ls())
data(mtcars)
attach(mtcars)
library(ggplot2)
library(plyr)
library(dplyr)
library(scales)
library(reshape2)
library(lazyeval)
my_func <- function(x, y) {
test<<-mtcars %>% group_by_(x, y) %>%
summarise(Freq = n()) %>%
mutate(Freq = Freq/sum(Freq))
test
}
my_func('gear', 'cyl')
ggplot(test, aes(x=gear, y=Freq))+
geom_bar(stat="identity", aes(fill=cyl), position=position_dodge(width=0.1))+
scale_y_continuous(labels=percent_format(), limits = c(0,1))
However, the resulting plot does not show the bars next to one another, but rather some on top of one another. What gives and how do I fix this?
You need to convert the cyl column to factor.
test$cyl <- as.factor(test$cyl)
ggplot(test, aes(x=gear, y=Freq))+
geom_bar(stat="identity", aes(fill=cyl), position=position_dodge(width=1))+
scale_y_continuous(labels=percent_format(), limits = c(0,1))