Ошибки округления с плавающей запятой. 0,1 не могут быть представлены точно в базе-2, как в базе-10, из-за недостающего простого коэффициента 5. Так же, как 1/3 принимает бесконечное число цифр для представления в десятичной форме, но составляет «0,1» в базе-3, 0.1 принимает бесконечное число цифр в базе-2, где оно не находится в базе-10. И компьютеры не имеют бесконечного объема памяти.
Самый простой способ - дополнить свой набор данных так, чтобы каждая комбинация присутствовала, даже если она имеет NA
в качестве ее значения. Взяв более простой пример (поскольку у вас много ненужных функций):
dat <- data.frame(a=rep(LETTERS[1:3],3),
b=rep(letters[1:3],each=3),
v=1:9)[-2,]
ggplot(dat, aes(x=a, y=v, colour=b)) +
geom_bar(aes(fill=b), stat="identity", position="dodge")
[/g0]
Это показывает поведение, которое вы пытаетесь избежать: в группы «В», нет группы «а», поэтому полосы шире. Дополнение dat
с фреймворком данных со всеми комбинациями a
и b
:
dat.all <- rbind(dat, cbind(expand.grid(a=levels(dat$a), b=levels(dat$b)), v=NA))
ggplot(dat.all, aes(x=a, y=v, colour=b)) +
geom_bar(aes(fill=b), stat="identity", position="dodge")
[/g1]
Некоторые новые опции для position_dodge()
и новых position_dodge2()
, введенные в ggplot2 3.0.0, могут помочь.
Вы можете использовать preserve = "single"
в position_dodge()
, чтобы установить ширину с одного Элемент, поэтому ширина всех полос будет одинаковой.
ggplot(data = d, aes(x = Month, y = Quota, color = "Quota")) +
geom_line(size = 1) +
geom_col(data = d[c(-1:-5),], aes(y = Sepal.Width, fill = Species),
position = position_dodge(preserve = "single") ) +
scale_fill_manual(values = colours)
[/g0]
Использование position_dodge2()
изменяет способ центровки по центру, центрируя каждый набор баров в каждом месте оси x. У него есть padding
, поэтому используйте padding = 0
для удаления.
ggplot(data = d, aes(x = Month, y = Quota, color = "Quota")) +
geom_line(size = 1) +
geom_col(data = d[c(-1:-5),], aes(y = Sepal.Width, fill = Species),
position = position_dodge2(preserve = "single", padding = 0) ) +
scale_fill_manual(values = colours)
[/g1]
У меня была та же проблема, но я искал решение, которое работает с трубой (%>%
). Использование tidyr::spread
и tidyr::gather
из tidyverse
делает трюк. Я использую те же данные, что и @Brian Diggs, но с именами переменных верхнего регистра, которые не имеют двойных имен переменных при преобразовании в wide:
library(tidyverse)
dat <- data.frame(A = rep(LETTERS[1:3], 3),
B = rep(letters[1:3], each = 3),
V = 1:9)[-2, ]
dat %>%
spread(key = B, value = V, fill = NA) %>% # turn data to wide, using fill = NA to generate missing values
gather(key = B, value = V, -A) %>% # go back to long, with the missings
ggplot(aes(x = A, y = V, fill = B)) +
geom_col(position = position_dodge())
Edit:
еще более простое решение этой проблемы в сочетании с трубой. Использовать tidyr::complete
дает тот же результат в одной строке:
dat %>%
complete(A, B) %>%
ggplot(aes(x = A, y = V, fill = B)) +
geom_col(position = position_dodge())