Две горизонтальные гистограммы с общей осью в ggplot2 (аналогичные пирамиде населения)

Я хочу построить две переменные на одном графике, похожие на пирамиду населения, подобную этой:

plot

Этот сюжет почти там, но не совсем, по причинам, которые я приведу ниже.

Я произвел этот график со следующим кодом:

DATA <- data.frame(
    state = c("AK", "TX", "CA", "MT", "NM", "AZ", "NV", "CO", "OR", "WY", "MI", "MN", "UT", "ID", "KS", "NE", "SD", "WA", "ND", "OK"),
    sales_staff = c(20,30,40,10,15,35,18,25,22,7,12,22,3,4,5,8,14,28,24,32)
)

set.seed(1)
DATA$sales <- DATA$sales_staff * 50 + (runif(nrow(DATA)) * 1000)

# Order the state factor by number of sales staff so that it is plotted in that order
DATA$state <- factor(DATA$state, levels = DATA[order(DATA$sales_staff),"state"])

Я хочу "склеить" два графика назад, поэтому я использую функцию multipot() дословно http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_%28ggplot2%29/

(Я не буду воспроизводить код для этой функции здесь для краткости и ясности)

Мой код для заключительного графика:

library(ggplot2)

g1 <- ggplot(data = DATA, aes(x = state, y = sales_staff)) +
  geom_bar(stat = "identity") + ggtitle("Number of sales staff") +
  theme(axis.title.x = element_blank(), axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), plot.margin = unit(c(1,0,1,0), "mm")) +
  scale_y_reverse() + coord_flip()

g2 <- ggplot(data = DATA, aes(x = state, y = sales)) +
  geom_bar(stat = "identity") + ggtitle("Sales (x $1000)") +
  theme(axis.title.x = element_blank(), axis.title.y = element_blank(), plot.margin = unit(c(1,5,1,0), "mm")) +
  coord_flip()

multiplot(g1, g2, cols = 2)

OK. Итак, что не так с этим сюжетом?

  • Мне нужно получить отметки на правой оси левого сюжета. Я не могу понять, как это сделать.
  • Два графика имеют разную ширину. Это происходит из-за того, что состояния вниз по середине являются метками оси с правого графика и используют часть пространства для этого графика.

Я ударил кирпичную стену, получив этот сюжет к "качеству производства". Я начинаю задаваться вопросом, не буду ли я делать это неправильно, потому что я думаю, что следующим шагом будет рисование меток оси как отдельный третий столбец между двумя графиками. (Я еще не знаю, как это сделать). Это решит проблему "равного размера" и позволит мне добавить заголовок "state", так что это все равно может пойти. Но я просто не могу не задаться вопросом, есть ли более простой способ...

Любые советы или помощь оценены!

Ответы

Ответ 1

Здесь очень длинный обход для вашего сюжета. Идея заключается в создании нового сюжета, который содержит только имена состояний и тики с обеих сторон, а затем использовать это как средний сюжет.

Для этого сюжета я добавил название без имени, чтобы получить пробел, и ylab(NULL), чтобы удалить пробел. Для левого и правого значений поля -1, чтобы получить график ближе к другим графикам. Библиотека grid должна быть добавлена ​​перед построением, чтобы использовать функцию unit() для полей графика.

library(grid)
g.mid<-ggplot(DATA,aes(x=1,y=state))+geom_text(aes(label=state))+
  geom_segment(aes(x=0.94,xend=0.96,yend=state))+
  geom_segment(aes(x=1.04,xend=1.065,yend=state))+
  ggtitle("")+
  ylab(NULL)+
  scale_x_continuous(expand=c(0,0),limits=c(0.94,1.065))+
  theme(axis.title=element_blank(),
        panel.grid=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        panel.background=element_blank(),
        axis.text.x=element_text(color=NA),
        axis.ticks.x=element_line(color=NA),
        plot.margin = unit(c(1,-1,1,-1), "mm"))

Оба оригинальных графика изменены. Сначала удалите ось y для второго графика, а также сделайте левое/правое поле равным -1.

g1 <- ggplot(data = DATA, aes(x = state, y = sales_staff)) +
  geom_bar(stat = "identity") + ggtitle("Number of sales staff") +
  theme(axis.title.x = element_blank(), 
        axis.title.y = element_blank(), 
        axis.text.y = element_blank(), 
        axis.ticks.y = element_blank(), 
        plot.margin = unit(c(1,-1,1,0), "mm")) +
  scale_y_reverse() + coord_flip()

g2 <- ggplot(data = DATA, aes(x = state, y = sales)) +xlab(NULL)+
  geom_bar(stat = "identity") + ggtitle("Sales (x $1000)") +
  theme(axis.title.x = element_blank(), axis.title.y = element_blank(), 
        axis.text.y = element_blank(), axis.ticks.y = element_blank(),
        plot.margin = unit(c(1,0,1,-1), "mm")) +
  coord_flip()

Теперь используйте библиотеку gridExtra и функцию d grid.arrange() для объединения графиков. Перед графикой все графики сделаны в виде грызунов.

library(gridExtra)
gg1 <- ggplot_gtable(ggplot_build(g1))
gg2 <- ggplot_gtable(ggplot_build(g2))
gg.mid <- ggplot_gtable(ggplot_build(g.mid))

grid.arrange(gg1,gg.mid,gg2,ncol=3,widths=c(4/9,1/9,4/9))

enter image description here