Spacing between x-axis groups bigger than within group spacing geom_col - ggplot2

I am trying to get double the space between the groups Automatic and Manual on the x-axis compared to the spaces within these groups. I am using geom_col() and experimted with different arguments, suchs as position_dodge, width and preserve = "single". I can't get this to work. What I am aiming for is a graph such as I have added as an image.
library(ggplot2)
library(ggthemes)
library(plyr)
#dataset
df <- mtcars
df$cyl <- as.factor(df$cyl)
df$am <- as.factor(df$am)
df$am <- revalue(df$am, c("0"="Automatic", "1"="Manual"))
ggplot(df, aes(fill = cyl, x = am, y = mpg)) +
geom_col(position = position_dodge(width = 0.9)) +
theme_bw()

Try using a combination of position=position_dodge(width=...) and width=...
For example:
ggplot(df, aes(fill = cyl, x = am, y = mpg)) +
geom_col(position = position_dodge(width = 0.9), width=0.8) +
theme_bw()
The width() command gives the displayed width of individual bars, while the position(width=) gives the space that is reserved for the bars.
The difference between the two values gives the space between bars within a group, while 1 - position_dodge(width=) gives the space between the groups.

Related

ggplot facet different Y axis order based on value

I have a faceted plot wherein I'd like to have the Y-axis labels and the associated values appear in descending order of values (and thereby changing the order of the labels) for each facet. What I have is this, but the order of the labels (and the corresponding values) is the same for each facet.
ggplot(rf,
aes(x = revenues,
y = reorder(AgencyName, revenues))) +
geom_point(stat = "identity",
aes(color = AgencyName),
show.legend = FALSE) +
xlab(NULL) +
ylab(NULL) +
scale_x_continuous(label = scales::comma) +
facet_wrap(~year, ncol = 3, scales = "free_y") +
theme_minimal()
Can someone point me to the solution?
The functions reorder_within and scale_*_reordered from the tidytext package might come in handy.
reorder_within recodes the values into a factor with strings in the form of "VARIABLE___WITHIN". This factor is ordered by the values in each group of WITHIN.
scale_*_reordered removes the "___WITHIN" suffix when plotting the axis labels.
Add scales = "free_y" in facet_wrap to make it work as expected.
Here is an example with generated data:
library(tidyverse)
# Generate data
df <- expand.grid(
year = 2019:2021,
group = paste("Group", toupper(letters[1:8]))
)
set.seed(123)
df$value <- rnorm(nrow(df), mean = 10, sd = 2)
df %>%
mutate(group = tidytext::reorder_within(group, value, within = year)) %>%
ggplot(aes(value, group)) +
geom_point() +
tidytext::scale_y_reordered() +
facet_wrap(vars(year), scales = "free_y")

How can I make the line appear besides the dots?

I tried to plot my data but I can only get the points, if I put "linetype" with geom:line it does not appear. Besides, I have other columns in my data set, called SD, SD.1 and SD.2, which are standard deviation values I calculated previously that appear at the bottom. I would like to remove them from the plot and put them like error bars in the lines.
library(tidyr)
long_data <- tidyr::pivot_longer(
data=OD,
cols=-Days,
names_to="Strain",
values_to="OD")
ggplot(long_data, aes(x=Days, y=OD, color=Strain)) +
geom_line() + geom_point(shape=16, size=1.5) +
scale_color_manual(values=c("Wildtype"="darkorange2", "Winter"="cadetblue3", "Flagella_less"="olivedrab3"))+
labs(title="Growth curve",x="Days",y="OD750",color="Legend")+
theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5,color="black",size=8),
axis.text.y=element_text(angle=0,hjust=1,vjust=0.5,color="black",size=8),
plot.title=element_text(hjust=0.5, size=13,face = "bold",margin = margin(t=0, r=10,b=10,l=10)),
axis.title.y =element_text(size=10, margin=margin(t=0,r=10,b=0,l=0)),
axis.title.x =element_text(size=10, margin=margin(t=10,r=10,b=0,l=0)),
axis.line = element_line(size = 0.5, linetype = "solid",colour = "black"))

double geom_bar, how to get the values for each bar

I have a ggplot of countries (X axis) over two different time periods (Y axis), so double bar for each country.
I would like to see the values of each bar. I used geom_text but I get the values on the same line so they are not in place. How can I use geom_text for this type of plot ?
Rcountry %>%
gather("Type", "Value",-Country) %>%
ggplot(aes(Country, Value, fill = Type)) +
geom_bar(position = "dodge", stat = "identity") +
coord_flip()+
theme_minimal()+scale_fill_grey()+
theme(legend.position="bottom")+
theme(legend.title = element_blank())+
scale_fill_manual(values=c("darkslategray4", "darkslategrey"))+
labs(x="Country", y="Stock of robots per thousands worker in '000")+
geom_text(aes(label=c(X2010, X2018)), size=3.5)```
Thank you
This can be achieved by adding position = position_dodge(.9) to geom_text, i.e. you have to the positioning used in geom_bar to geom_text to get the labels right. Using mtcars as example data, try this:
library(ggplot2)
library(dplyr)
mtcars2 <- mtcars %>%
group_by(cyl, gear) %>%
summarise(mpg = mean(mpg)) %>%
ungroup()
ggplot(mtcars2, aes(x = factor(cyl), mpg, fill = factor(gear))) +
geom_bar(position = "dodge", stat = "identity") +
theme_minimal() +
scale_fill_grey() +
theme(legend.position="bottom")+
theme(legend.title = element_blank())+
labs(x="Country", y="Stock of robots per thousands worker in '000")+
geom_text(aes(label = mpg), position = position_dodge(.9), size=3.5) +
coord_flip()
Created on 2020-04-15 by the reprex package (v0.3.0)

Using 2nd variable to label axis ticks in ggplot2 facets

I am attempting to make a faceted t-chart using ggplot2, where the x-axis is represented a sequence of events and the y-axis represents the number of days between those events. The x-axis should be labelled with the event date, but it is not a time series since the distance between x-axis ticks should be uniform regardless of the real time between events.
Adding a faceting layer has been confusing me. Here's some sample data:
df <- data.frame(EventDT = as.POSIXct(c("2014-11-22 07:41:00", "2015-02-24 08:10:00",
"2015-06-10 13:54:00", "2015-07-11 02:43:00",
"2015-08-31 19:08:00", "2014-11-18 14:06:00",
"2015-06-09 23:10:00", "2016-02-29 07:55:00",
"2016-05-22 04:30:00", "2016-05-25 21:46:00",
"2014-12-22 16:19:00", "2015-05-13 16:38:00",
"2015-06-01 09:05:00", "2016-02-21 02:30:00",
"2016-05-13 01:36:00")),
EventNBR = rep(1:5, 3),
Group = c(rep('A', 5), rep('B',5), rep('C',5)),
Y = c(15.818750, 94.020139, 106.238889, 30.534028, 51.684028,
187.670139, 203.377778, 264.364583, 82.857639, 3.719444,
169.829861, 142.013194, 18.685417, 264.725694,81.962500))
Ignoring the date of the event, I can produce this:
g <- ggplot(df, aes(x=EventNBR, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
Plot should show EventDT along X-axis, not EventNBR
I have tried to use the labels parameter to scale_x_discrete without success:
xaxis.ticks <- function(x) {
df[which(df$EventNBR) == x] }
g + scale_x_discrete(labels = xaxis.ticks)
But that's wrong in a way I can't describe, because it cuts off my tick labels altogether.
Because there is a 1-1 correspondence between EventNBR and EventDT by Group for this dataset, it seems like there should be an easy solution, but I can't figure it out. Am I overlooking something painfully easy?
In general, this is a very problematic thing as mentioned here and there are several other topics on this.
But luckily in your case it is possible since you use scales='free_x'.
What you need to do is adding an unique index column like
df$id <- 1:nrow(df)
and afterwards you can overwrite these indexes with you column with correct labels.
g <- ggplot(df, aes(x=id, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
g + scale_x_continuous(breaks=df$id, labels=df$EventDT) +
theme(axis.text.x=element_text(angle=90, vjust=.5))
There might be easier solutions but this is working in your example.
Also, the labels seem to be gone since the x axis is numeric and not discrete. So using scale_x_continuous produces the correct labels.
EDIT:
So a full example looks like this
library(ggplot2)
df <- data.frame(EventDT = as.POSIXct(c("2014-11-22 07:41:00", "2015-02-24 08:10:00",
"2015-06-10 13:54:00", "2015-07-11 02:43:00",
"2015-08-31 19:08:00", "2014-11-18 14:06:00",
"2015-06-09 23:10:00", "2016-02-29 07:55:00",
"2016-05-22 04:30:00", "2016-05-25 21:46:00",
"2014-12-22 16:19:00", "2015-05-13 16:38:00",
"2015-06-01 09:05:00", "2016-02-21 02:30:00",
"2016-05-13 01:36:00")),
EventNBR = rep(1:5, 3),
Group = c(rep('A', 5), rep('B',5), rep('C',5)),
Y = c(15.818750, 94.020139, 106.238889, 30.534028, 51.684028,
187.670139, 203.377778, 264.364583, 82.857639, 3.719444,
169.829861, 142.013194, 18.685417, 264.725694,81.962500))
df$id <- 1:nrow(df)
g <- ggplot(df, aes(x=id, y=Y)) +
geom_point() +
geom_line() +
facet_wrap(~ Group, scales='free_x')
g + scale_x_continuous(breaks=df$id, labels=df$EventDT) +
theme(axis.text.x=element_text(angle=90, vjust=.5))
and produces the following output:

ggplot grobs align with tableGrob

I'm having difficulty to find solution for aligning ggplot grob and table grob. I tried to follow the instruction here but still didn't give the results I wanted.
library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col
plot1 <- ggplot(dat, aes(car, mpg)) +
geom_bar(stat = "identity") +
coord_flip()
g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl)
g1 <- gtable_add_cols(g1, unit(0.2, "npc"))
g1 <- gtable_add_grob(g1, grobs = tb1, t=3, l=ncol(g1), b=6, r=ncol(g1))
grid.newpage()
grid.draw(g1)
I would like that each cell in the table be aligned to related bar in histogram, but still couldn't understand how the t,l,b,r be implemented from the layout.This is the output I got
I had a similar question as above when trying to make something like a forestplot in R using ggplot2 and didn't find any of the other solutions fit my needs. The answer above didn't work for me - the table didn't show up. So I hacked together a codewise not that pretty solution, but I actually kind of like the cleanliness visual output.
The things I like about this solution are:
I aligned a set of custom text not in a table, but just in a figure on the right, where the alignment matched for each text entry and each label in the figure.
I used a centered ggtitle to align a "column heading" above each set of text. These could be strings of any kind (in my actual use, I had point estimates and confidence intervals).
library(gridExtra)
library(ggplot2)
dat <- data.frame(
label = c("A", "B", "C"),
point_est = c(1,2,3),
lb_ci = c(.5, 1.5, 2.5),
ub_ci = c(1.5, 2.5, 3.5),
n = c(50, 100, 150),
total = c(75, 150, 200)
)
plot1 <- ggplot(dat, aes(x=point_est, y=label)) +
geom_point() +
geom_errorbarh(aes(xmin=lb_ci, xmax=ub_ci), height=.5) +
ggtitle("Some measure") +
ylab(NULL) + xlab("some effect estimate")
tab_base <- ggplot(dat, aes(y=label)) +
ylab(NULL) + xlab(" ") +
theme(plot.title = element_text(hjust = 0.5, size=12), ## centering title on text
axis.text.x=element_text(color="white"), ## need text to be printed so it stays aligned with figure but white so it's invisible
axis.line=element_blank(),
axis.text.y=element_blank(),axis.ticks=element_blank(),
axis.title.y=element_blank(),legend.position="none",
panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),plot.background=element_blank())
tab1 <- tab_base +
geom_text(aes(x=1, label=n)) +
ggtitle("n")
tab2 <- tab_base +
geom_text(aes(x=1, label=total)) +
ggtitle("total")
lay <- matrix(c(1,1,1,1,1,1,2,3), nrow=1)
grid.arrange(plot1, tab1, tab2, layout_matrix = lay)
By default the cell heights have absolute sizes to accommodate the text, but you can change them to relative units so that they scale with the plot panel,
library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col
plot1 <- ggplot(dat, aes(car, mpg)) +
geom_bar(stat = "identity") +
coord_flip()
g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl, theme = ttheme_default(10))
tb1$heights = unit(rep(1/(nrow(tb1)), nrow(tb1)), "npc")
tb1$widths = unit.pmax(tb1$widths, unit(2, "lines"))
g1 <- gtable_add_cols(g1, sum(tb1$widths))
g1 <- gtable_add_grob(g1, grobs = tb1, t=6, l=ncol(g1), b=6, r=ncol(g1))
grid.newpage()
grid.draw(g1)