Вы должны использовать в этом случае другой формат данных и расплавить его.
require(reshape2)
require(tidyverse)
# format data
melted_data <- l8tc.df_17_18 %>%
select(landcover, tcw_17, tcw_18) %>%
melt('landcover', variable.name = 'tcw')
# plot
ggplot(melted_data, aes(x = as.factor(landcover), y = value)) + geom_boxplot(aes(fill = tcw))
Уклонение должно быть автоматическим, но если вы не хотите экспериментировать, используйте geom_boxplot(aes(fill = tcw), position = position_dodge())
https://ggplot2.tidyverse.org/reference/position_dodge.html
Вы можете записать его в одну строку, не создавая временный файл
l8tc.df_17_18 %>%
select(landcover, tcw_17, tcw_18) %>%
melt('landcover', variable.name = 'tcw') %>%
ggplot(aes(x = as.factor(landcover), y = value)) + geom_boxplot(aes(fill = tcw))