How to sum different factor values in R?

Viewed 46

I have a sample that consists of 2787 rows and 259 columns.

To put this into context, it is a survey of how people in Spain perceive their current economic situation versus the one that was 6 months ago, carried out by a Spanish research institute, CIS.

Thus, I have a column (P3) with 5 answers: "better", "worse", "same", "don't know", and "don't answer". Also, I have another column (P19) with 2 options ("1" for males and "2" for females).

What I would like to get to know is how people rate their current versus past economic situation based on their gender (and plot this). In other words, to see how many males fare their situation "better", how many rate it "worse", and so on; and the same, with females.

To achieve this, I've been trying to run the following code:

CVSPastIndividualSituationMales<- aggregate(CIS$P3 ~ CIS$P19 == "1", CIS, sum)
CVSPastIndividualSituationFemales<- aggregate(CIS$P3 ~ CIS$P19 == "2", CIS, sum)


CurrentVSPastIndividualSituationMales<-ggplot(CIS,mapping=aes(x=CVSPastIndividualSituationMales))+geom_bar(fill="LightGreen")+xlab("Current VS Past Individual Situation for Males")
CurrentVSPastIndividualSituationFemales <-ggplot(CIS,mapping=aes(CVSPastIndividualSituationFemales))+geom_bar(fill="Green") + xlab("Current VS Past Individual Situation for Females")

ggarrange(CurrentVSPastIndividualSituationMales, CVSPastIndividualSituationFemales, ncol = 1, nrow = 1)

However, I get the following error:

Don't know how to automatically pick scale for object of type data.frame. Defaulting to continuous.
Error in `check_aesthetics()`:
! Aesthetics must be either length 1 or the same as the data (2787): x
Backtrace:
  1. ggpubr::ggarrange(...)
  2. purrr::map(...)
  3. ggpubr (local) .f(.x[[i]], ...)
  4. cowplot::plot_grid(plotlist = plotlist, ...)
  5. cowplot::align_plots(...)
     ...
 16. ggplot2 (local) by_layer(function(l, d) l$compute_aesthetics(d, plot))
 17. ggplot2 (local) f(l = layers[[i]], d = data[[i]])
 18. l$compute_aesthetics(d, plot)
 19. ggplot2 (local) f(..., self = self)
 20. ggplot2:::check_aesthetics(evaled, n)
 Error in check_aesthetics(evaled, n) :

Does anyone know what I am doing wrong and how I could possible get to the desired outcome?

Many thanks in advance!

P.S. Maybe a Dplyr solution might be available?

2 Answers

The issue is that you map your aggregated datasets on the x aesthetic but pass the original dataframe to the data argument.

Using some fake data to mimic your real data I first reproduce your issue:

library(ggplot2)
library(ggpubr)

set.seed(123)

CIS <- data.frame(
  P19 = sample(c(1:2), 100, replace = TRUE),
  P3 = sample(1:5, 100, replace = TRUE)
)

CVSPastIndividualSituationMales<- aggregate(CIS$P3 ~ CIS$P19 == "1", CIS, sum)
CVSPastIndividualSituationFemales<- aggregate(CIS$P3 ~ CIS$P19 == "2", CIS, sum)

CurrentVSPastIndividualSituationMales<-ggplot(CIS,mapping=aes(x=CVSPastIndividualSituationMales))+geom_bar(fill="LightGreen")+xlab("Current VS Past Individual Situation for Males")
CurrentVSPastIndividualSituationFemales <-ggplot(CIS,mapping=aes(CVSPastIndividualSituationFemales))+geom_bar(fill="Green") + xlab("Current VS Past Individual Situation for Females")

ggarrange(CurrentVSPastIndividualSituationMales, CVSPastIndividualSituationFemales, ncol = 1, nrow = 1)
#> Don't know how to automatically pick scale for object of type data.frame. Defaulting to continuous.
#> Error in `check_aesthetics()`:
#> ! Aesthetics must be either length 1 or the same as the data (100): x

While it's not a big task to fix this issue, overall you could achieve your result much easier with just ggplot2 like so. First, geom_bar will already compute the counts by default. So we don't need aggregate. Second, instead of making two plots you could make one plot and use facet_wrap to get separate plots per gender. Finally you could map gender on fill and set your desired colors via scale_fill_manual:

library(ggplot2)

set.seed(123)

CIS <- data.frame(
  P19 = sample(c(1:2), 100, replace = TRUE),
  P3 = sample(1:5, 100, replace = TRUE)
)

CIS$P3 <- factor(CIS$P3, labels = c("better", "worse", "same", "don't know", "don't answer"))
CIS$P19 <- factor(CIS$P19, labels = c("Males", "Females"))

ggplot(CIS, aes(P3, fill = P19)) +
  geom_bar() +
  scale_fill_manual(values = c("LightGreen", "Green"), guide = "none") +
  facet_wrap(~P19) +
  xlab("Current VS Past Individual Situation")

This can also be accomplished using base R

set.seed(1000)
spain_data<-data.frame(P3=sample(c("better","worse","same","don't know","don't answer"),30,replace = TRUE),P19=sample(c(1,2),30,replace = TRUE)) 
male_pos<-which(spain_data$P19==1)
female_pos<-which(spain_data$P19==2)
male_response<-spain_data$P3[male_pos]
female_response<-spain_data$P3[female_pos]
bar<-barplot(rbind(table(male_response),table(female_response)),beside = TRUE,col = c("red","green"),ylim = c(0,( max(rbind(table(male_response),table(female_response)))+2)))
text(bar,rbind(table(male_response),table(female_response))+0.2,labels = as.character(rbind(table(male_response),table(female_response))))
legend("topleft",c("Male","Female"),fill=c("red","green"),bty = "n",cex=0.9)

If it is desired to generate separate barplots for male and female, then

barplot(table(male_response))
barplot(table(female_response))
Related