R - ggplot dodging geom_lines
You have actually two issues here:
If the two lines are plotted using two layers of
geom_line()
(because you have two data frames), then each line "does not know" about the other. Therefore, they can not dodge each other.position_dodge()
is used to dodge in horizontal direction. The standard example is a bar plot, where you place various bars next to each other (instead of on top of each other). However, you want to dodge in vertical direction.
Issue 1 is solved by combining the data frames into one as follows:
library(dplyr)
df_all <- bind_rows(Group1 = df1, Group2 = df2, .id = "group")
df_all
## Source: local data frame [4 x 4]
##
## group id var id_num
## (chr) (fctr) (dbl) (dbl)
## 1 Group1 A 1 1.0
## 2 Group1 A 10 1.0
## 3 Group2 A 1 0.9
## 4 Group2 A 15 0.9
Note how setting .id = "Group"
lets bind_rows()
create a column group
with the labels taken from the names that were used together with df1
and df2
.
You can then plot both lines with a single geom_line()
:
library(ggplot2)
ggplot(data = df_all, aes(x=var, y=id, colour = group)) +
geom_line(position = position_dodge(width = 0.5)) +
scale_color_manual("",values=c("salmon","skyblue2"))
I also used position_dodge()
to show you issue 2 explicitly. If you look closely, you can see the red line stick out a little on the left side. This is the consequence of the two lines dodging each other (not very successfully) in vertical direction.
You can solve issue 2 by exchanging x and y coordinates. In that situation, dodging horizontally is the right thing to do:
ggplot(data = df_all, aes(y=var, x=id, colour = group)) +
geom_line(position = position_dodge(width = 0.5)) +
scale_color_manual("",values=c("salmon","skyblue2"))
The last step is then to use coord_flip()
to get the desired plot:
ggplot(data = df_all, aes(y=var, x=id, colour = group)) +
geom_line(position = position_dodge(width = 0.5)) +
scale_color_manual("",values=c("salmon","skyblue2")) +
coord_flip()
R ggplot2 geom_line position dodge
I don't think you can dodge vertically, but another option is just to add a little dodging yourself. For example:
eps = 0.05
ggplot(sa, aes(x=value, y=ifelse(type=="typ1", id + eps, id - eps),
group=grp, color=type)) +
geom_line(size=6) +
scale_y_continuous(breaks=1:2, limits=c(min(sa$id-eps), max(sa$id+eps)))
You'll have to play around with the amount of dodging, axis limits, etc., to get the look you want for a given aspect ratio.
using position_dodge with geom_line
Just move group = Behaviour
to ggplot(..., aes(..., group = Behaviour))
.
ggplot(rep, aes(x = stage, y = Repeatability, shape = Behaviour, colour=Age, group = Behaviour)) +
geom_point(
position = position_dodge(width = 0.3),
size = 3) +
geom_line(
position = position_dodge(width = 0.3),
data = function(x) inner_join(x, my_colors %>% filter(color == 'black')))+
scale_colour_manual(
values = c("orange", "black", "red", "black", "black", "pink", "black"),
name = "Study",
breaks=c("A","A1","A2", "CY", "PE","PW", "PW2"))+
geom_errorbar(
aes(ymin=LCI, ymax=UCI),
position=pd,
width=0.1,
size=0.5)
Ok, here is another option. The idea is to pre-compute the dodged positions using jitter
. This will turn the categorial variable stage
into a continuous variable stage.jitter
that requires manually specifying x-axis labels through scale_x_continuous
.
rep %>%
mutate(stage.jitter = jitter(as.numeric(stage), 0.5)) %>%
ggplot(aes(x = stage.jitter, y = Repeatability, shape = Behaviour, colour=Age, group = Behaviour)) +
geom_point(size = 3) +
geom_line(
data = function(x) inner_join(x, my_colors %>% filter(color == 'black')))+
scale_colour_manual(
values = c("orange", "black", "red", "black", "black", "pink", "black"),
name = "Study",
breaks=c("A","A1","A2", "CY", "PE","PW", "PW2")) +
scale_x_continuous(
"stage",
labels = function(x) rep %>% pull(stage) %>% levels() %>% .[x]) +
geom_errorbar(
aes(ymin = LCI, ymax = UCI),
width = 0.1,
size = 0.5)
You may have to play around with the amount of jitter by changing the factor
value inside jitter
.
How to combine position_dodge() and geom_line() with overlapping groupings?
One option to achieve your desired result would be to convert your x axis variable to a numeric and adjust the positions manually instead of making use of position_dodge
:
library(tidyverse)
tbl = tibble(name = rep(paste("name", 1:12), each = 2),
grouping1 = rep(c("A", "B"), 12),
grouping2 = c(rep("X", 8), rep("Y",8), rep("Z",8)),
value = 1:24)
width <- .125
tbl1 <- tbl %>%
mutate(grouping2 = factor(grouping2),
x = as.numeric(grouping2) + width * if_else(grouping1 == "A", -1, 1))
breaks <- unique(as.numeric(tbl1$grouping2))
labels <- unique(tbl1$grouping2)
ggplot(tbl1, aes(x = x, y = value, color = grouping1)) +
geom_line(aes(group = name), color = "grey44") +
geom_point() +
scale_x_continuous(breaks = breaks, labels = labels)
Displaying multiple lines on ggplot with grouped (dodged) bars
Try this
ggplot(line_data,aes(x=month, y=water_val)) +
geom_col(data=bar_data, aes(fill = water_type), position="dodge") +
geom_line(aes(color=water_type)) +
ggtitle("V1 and V2") +
scale_y_continuous(breaks = seq(0,25,10)) +
xlab("Month") +
ylab("(cm)") +
facet_wrap(~year,nrow=2)
R - ggplot2 geom_line dodge
This is much easier to accomplish if you reshape your summary data:
dt <- mtcars %>%
group_by(am, cyl) %>%
summarise(m = mean(disp)) %>%
spread(am, m)
cyl 0 1
* <dbl> <dbl> <dbl>
1 4 135.8667 93.6125
2 6 204.5500 155.0000
3 8 357.6167 326.0000
While "0" and "1" are poor column names, they can still be used in aes()
if you quote them in backticks. The calls to position_dodge()
also become unnecessary:
dt %>% ggplot(aes(x = factor(cyl), y = `0`, fill = factor(cyl))) +
geom_bar(stat = 'identity') +
geom_point(aes(x = factor(cyl), y = `1`), colour = 'black') +
geom_segment(aes(x = factor(cyl), xend = factor(cyl), y = `0`, yend = `1`))
Cannot change width of position_dodge using geom_line
As I already said in my comment to achieve your final goal is IMHO not possible using position="dodge"
, i.e. you dodge all error bars by the same amount or none. Instead I would suggest to do the dodging manually via the x positions. To this end first determine the dates where the error bars overlap. For these dates you could then add or subtract the amount by which you want the errors to be dodged. In my code below I dodge by one day:
library(ggplot2)
library(dplyr)
library(tidyr)
dodge_width <- 1 # days
yield <- yield |>
mutate(lo = Yield - se, hi = Yield + se) |>
select(-Yield, -se) |>
pivot_wider(names_from = Treatment, values_from = c(lo, hi)) |>
mutate(is_dodge = (lo_Ash >= lo_Control & lo_Ash <= hi_Control) |
(hi_Ash >= lo_Control & hi_Ash <= hi_Control) |
(lo_Control >= lo_Ash & lo_Control <= hi_Ash) |
(hi_Control >= lo_Ash & hi_Control <= hi_Ash)) |>
select(Year, Date, is_dodge) |>
right_join(yield) |>
mutate(dodge = Date + case_when(
is_dodge & Treatment == "Ash" ~ -lubridate::days(dodge_width),
is_dodge & !Treatment == "Ash" ~ lubridate::days(dodge_width),
TRUE ~ lubridate::days(0)
))
#> Joining, by = c("Year", "Date")
ggplot(yield, aes(x = Date, y = Yield, color = Treatment, group = Treatment)) +
geom_line(size = 1) +
geom_point(size = 2) +
geom_errorbar(aes(x = dodge, ymin = Yield - se, ymax = Yield + se), color = "black") +
theme(
panel.background = element_blank(),
panel.border = element_rect(colour = "black", fill = NA)
) +
theme(text = element_text(size = 13)) +
facet_grid(. ~ Year, scales = "free_x") +
labs(y = "Average Yield (L)")
Related Topics
Creating a Table with Individual Trials from a Frequency Table in R (Inverse of Table Function)
Fill Missing Values Rowwise (Right/Left)
Ggplot2 Violin Plot: Fill Central 95% Only
Margins Between Plots in Grid.Arrange
R: Check If Value from Dataframe Is Within Range Other Dataframe
Modifying Plot in Ggplot2 Using As.Yearmon from Zoo
Visualizing Distance Between Nodes According to Weights - with R
How to Get The Intersection Point of Two Vector
Using Inst/Extdata with Vignette During Package Checking R 2.14.0
Existing Function to Combine Standard Deviations in R
How to Define a Function in Dplyr
How to Create a Prop.Table() for a Three Dimension Table
How to Create Dynamic Number of Observeevent in Shiny
Get Country (And Continent) from Longitude and Latitude Point in R
How to Manually Set Colours to a Categorical Variables Using Ggplot()
How to Show Only The Lower Triangle in Ggpairs
Merge Data Based on Nearest Date R
How to Filter Cases in a Data.Table by Multiple Conditions Defined in Another Data.Table