Подтвердить что ты не робот

Упрощенная пирамида населения в ggplot2

Я хочу создать пирамиду населения с помощью ggplot2. Этот вопрос задавался до, но я считаю, что решение должно быть намного проще.

test <- (data.frame(v=rnorm(1000), g=c('M','F')))
require(ggplot2)
ggplot(data=test, aes(x=v)) + 
    geom_histogram() + 
    coord_flip() + 
    facet_grid(. ~ g)

Создает это изображение. На мой взгляд, единственный шаг, отсутствующий здесь для создания пирамиды населения, состоит в том, чтобы инвертировать ось x первой грани, так что она идет от 50 до 0, сохраняя при этом вторую нетронутую. Может ли кто-нибудь помочь?

Population pyramid

4b9b3361

Ответ 1

Вот решение без огранки. Сначала создайте фрейм данных. Я использовал значения от 1 до 20, чтобы гарантировать, что ни одно из значений не будет отрицательным (с пирамидами населения вы не получите отрицательных значений/возрастов).

test <- data.frame(v=sample(1:20,1000,replace=T), g=c('M','F'))

Затем комбинируются два geom_bar() вызова отдельно для каждого из значений g. Для F подсчеты рассчитываются так, как они есть, но для M количество отсчетов умножается на -1, чтобы получить бар в противоположном направлении. Затем scale_y_continuous() используется для получения хороших значений для оси.

require(ggplot2)
require(plyr)    
ggplot(data=test,aes(x=as.factor(v),fill=g)) + 
  geom_bar(subset=.(g=="F")) + 
  geom_bar(subset=.(g=="M"),aes(y=..count..*(-1))) + 
  scale_y_continuous(breaks=seq(-40,40,10),labels=abs(seq(-40,40,10))) + 
  coord_flip()

ОБНОВЛЕНИЕ

Поскольку аргумент subset=. устарел в последних версиях ggplot2, тот же результат может быть получен с помощью функции subset().

ggplot(data=test,aes(x=as.factor(v),fill=g)) + 
  geom_bar(data=subset(test,g=="F")) + 
  geom_bar(data=subset(test,g=="M"),aes(y=..count..*(-1))) + 
  scale_y_continuous(breaks=seq(-40,40,10),labels=abs(seq(-40,40,10))) + 
  coord_flip()

enter image description here

Ответ 2

Общий код ggplot, который

  1. Предотвращает некоторую суету вокруг разрывов надписей на горизонтальной оси
  2. Избегает subset или необходимости дополнительных пакетов (например, plyr). Это может быть особенно полезно, если вы хотите создать несколько пирамид на фасетном графике.
  3. Использует geom_bar() только один раз, что полезно, если вы хотите получить фасет.
  4. Имеет равные мужские и женские горизонтальные оси; limits = max(df0$Population) * c(-1,1), как обычно используют демографы... удалите, если не требуется.

Создание данных...

set.seed(1)
df0 <- data.frame(Age = factor(rep(x = 1:10, times = 2)), 
                  Gender = rep(x = c("Female", "Male"), each = 10),
                  Population = sample(x = 1:100, size = 20))

head(df0)
#   Age Gender Population
# 1   1 Female         27
# 2   2 Female         37
# 3   3 Female         57
# 4   4 Female         89
# 5   5 Female         20
# 6   6 Female         86

Код участка...

library(ggplot2)
ggplot(data = df0, 
       mapping = aes(x = Age, 
                     y = ifelse(test = Gender == "Male",  yes = -Population, no = Population), 
                     fill = Gender)) +
  geom_bar(stat = "identity") +
  scale_y_continuous(labels = abs, limits = max(df0$Population) * c(-1,1)) +
  labs(y = "Population") +
  coord_flip()

enter image description here

Обратите внимание, что если ваши данные представлены на индивидуальном уровне, а не суммированы по возрасту и полу, то ответ здесь также довольно обобщенный.

Ответ 3

Расширяя пост @gjabel, мы видим чистую популяционную пирамиду, опять же, просто используя ggplot2.

popPy1 <- ggplot(data = venDemo, 
   mapping = aes(
      x = AgeName, 
      y = ifelse(test = sex == "M",  yes = -Percent, no = Percent), 
      fill = Sex2,
      label=paste(round(Percent*100, 0), "%", sep="")
   )) +
geom_bar(stat = "identity") +
#geom_text( aes(label = TotalCount, TotalCount = TotalCount + 0.05)) +
geom_text(hjust=ifelse(test = venDemo$sex == "M",  yes = 1.1, no = -0.1), size=6, colour="#505050") +
#  scale_y_continuous(limits=c(0,max(appArr$Count)*1.7)) +
# The 1.1 at the end is a buffer so there is space for the labels on each side
scale_y_continuous(labels = abs, limits = max(venDemo$Percent) * c(-1,1) * 1.1) +
# Custom colours
scale_fill_manual(values=as.vector(c("#d23f67","#505050"))) +
# Remove the axis labels and the fill label from the legend - these are unnecessary for a Population Pyramid
labs(
  x = "",
  y = "",
  fill="", 
  family=fontsForCharts
) +
theme_minimal(base_family=fontsForCharts, base_size=20) +   
coord_flip() +
# Remove the grid and the scale
theme( 
  panel.grid.major = element_blank(), 
  panel.grid.minor = element_blank(),
  axis.text.x=element_blank(), 
  axis.text.y=element_text(family=fontsForCharts, size=20),
  strip.text.x=element_text(family=fontsForCharts, size=24),
  legend.position="bottom",
  legend.text=element_text(size=20)
)

popPy1

Population Pyramid