Ggplot2: удалить неиспользуемые коэффициенты в фасетном штриховом графике, но не иметь разной ширины штрихов между гранями

df <- structure(list(ID = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 
5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L), .Label = c("1", 
"2", "3", "4", "5", "6", "7"), class = "factor"), TYPE = structure(c(1L, 
2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 5L, 6L, 
1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 
5L, 6L, 1L, 2L, 3L), .Label = c("1", "2", "3", "4", "5", "6", 
"7", "8"), class = "factor"), TIME = structure(c(2L, 2L, 2L, 
2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 
1L, 1L, 1L), .Label = c("1", "5", "15"), class = "factor"), VAL = c(0.937377670081332, 
0.522220720537007, 0.278690102742985, 0.967633064137772, 0.116124767344445, 
0.0544306698720902, 0.470229141646996, 0.62017166428268, 0.195459847105667, 
0.732876230962574, 0.996336271753535, 0.983087373664603, 0.666449476964772, 
0.291554537601769, 0.167933790013194, 0.860138458199799, 0.172361251665279, 
0.833266809117049, 0.620465772924945, 0.786503327777609, 0.761877260869369, 
0.425386636285111, 0.612077651312575, 0.178726130630821, 0.528709076810628, 
0.492527724476531, 0.472576208412647, 0.0702785139437765, 0.696220921119675, 
0.230852259788662, 0.359884874196723, 0.518227979075164, 0.259466265095398, 
0.149970305617899, 0.00682218233123422, 0.463400925742462, 0.924704828299582, 
0.229068386601284)), .Names = c("ID", "TYPE", "TIME", "VAL"), row.names = c(NA, 
-38L), class = "data.frame")

Если я создам следующий график:

ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
  facet_wrap(~ TIME, ncol=1) +
  geom_bar(position="stack") +
  coord_flip()

plot

Затем я решил, что в идеале я хотел бы подавить любые факторы, которые будут показаны на грани, где у них нет данных. Я ссылался на различные вопросы и ответы, в которых говорится, что метод scale="free" - это путь (в отличие от drop=TRUE, который бы сбросил пустые грани, соответствующие неиспользуемым значениям в TIME), следующим образом:

ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
  facet_wrap(~TIME, ncol=1, scale="free") +
  geom_bar(position="stack") +
  coord_flip()

plot

Мой вопрос заключается в том, как предотвратить перемасштабирование баров, которые возникают для фасета, который имеет 4 бара против фасетки с 3 барами. Эффект тонкий в этом надуманном примере, что намного хуже с моими фактическими данными. Идеальный выход имел бы нижнюю грань с коэффициентами идентичности 1,4 и 6 по вертикальной оси с полосами, имеющими ту же ширину, что и верхняя грань, и поэтому общий вертикальный размер фасетки будет уменьшен.

Бонусные баллы, если вы можете мне помочь, почему подсчеты стекаются вместо числовых значений (Исправлено)

Обновление Bounty:

Как упоминалось в моем обзоре question, похоже, что лучшим решением может быть использование ggplot_build и ggplot_table и изменение объекта gtable. Я почти уверен, что смогу понять это время, но я надеюсь, что щедрость может побудить кого-то другого помочь мне. Кошке опубликовал несколько примеров этого.

Ответы

Ответ 1

Как насчет этого:

df$w <- 0.9
df$w[df$TIME == 5] <- 0.9 * 3/4
ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
   facet_wrap(~TIME, ncol=1, scale="free") +
   geom_bar(position="stack",aes(width = w),stat = "identity") +
   coord_flip()

enter image description here

Не уверен, что я получил арифметику прямо там, но вы поняли.

Ответ 2

Если вы в порядке с вертикальными барами, facet_grid отлично работает:

ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
  facet_grid(.~TIME, scale="free_x", space = "free_x") +
  geom_bar(position="stack")

enter image description here

Чтобы пойти немного дальше, вы можете повернуть все элементы диаграммы. Теперь у вас есть то, что вы хотите, если повернете голову на 90 °: -)

ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
  facet_grid(.~TIME, scale="free_x", space = "free_x") +
  geom_bar(position="stack") +
  opts(legend.text = theme_text(angle=90),
       legend.title = theme_text(angle=90),
       strip.text.x = theme_text(angle=90),
       axis.text.x = theme_text(angle=90),
       axis.text.y = theme_text(angle=90),
       axis.title.x = theme_text(angle=90)
       )

enter image description here

Ответ 3

В течение пяти лет с момента первоначального вопроса, поэтому он подумал, что он должен предоставить более современную и более чистую версию этого. Это в целом следует рекомендациям, приведенным здесь: http://ggplot2.tidyverse.org/reference/facet_grid.html

Двумя ключевыми аргументами являются space="free_y", которые позволяют увеличить высоту каждой панели пропорционально длине шкалы и scales="free_y", которая позволяет изменять масштаб для каждого столбца.

coord_flip() позволяет строить строчки горизонтально, и в качестве личного предпочтения метка фасете поворачивается в пределах опций theme.

ggplot(df, aes(x=ID, y=VAL, fill=TYPE)) +
  geom_bar(stat="identity") +
  coord_flip() +
  facet_grid(TIME~., scales = "free_y", space = "free_y") +
  theme(strip.text.y = element_text(angle = 0))

введите описание изображения здесь