0

I want to plot a bar chart and order the x axis by value. I know that I managed to do that before, but I might have deleted that code somewhere. I have been stuck on that now for a while, so I'm asking you now.

As my dataframe contains more than 24,000 rows, here a sample data. I hope that it is enough to recreate it.

structure(list(country = c("Palestine", "Iraq", "Algeria", "Libya", 
"Lebanon", "Jordan", "Egypt", "Palestine", "Libya", "Egypt", 
"Libya", "Jordan", "Yemen", "Jordan", "Tunesia", "Iraq", "Lebanon", 
"Lebanon", "Morocco", "Algeria", "Jordan", "Egypt", "Kuwait", 
"Morocco", "Tunesia", "Palestine", "Yemen", "Lebanon", "Sudan", 
"Lebanon", "Libya", "Palestine", "Yemen", "Tunesia", "Sudan", 
"Yemen", "Morocco", "Jordan", "Palestine", "Palestine", "Libya", 
"Palestine", "Libya", "Jordan", "Jordan", "Lebanon", "Iraq", 
"Algeria", "Yemen", "Tunesia", "Lebanon", "Libya", "Yemen", "Egypt", 
"Yemen", "Libya", "Palestine", "Egypt", "Tunesia", "Sudan", "Tunesia", 
"Egypt", "Lebanon", "Iraq", "Kuwait", "Libya", "Tunesia", "Algeria", 
"Morocco", "Egypt", "Tunesia", "Morocco", "Palestine", "Kuwait", 
"Morocco", "Kuwait", "Morocco", "Palestine", "Morocco", "Lebanon", 
"Iraq", "Egypt", "Morocco", "Algeria", "Jordan", "Sudan", "Sudan", 
"Algeria", "Sudan", "Egypt", "Palestine", "Jordan", "Sudan", 
"Iraq", "Egypt", "Tunesia", "Sudan", "Yemen", "Lebanon", "Iraq"
), female_head_gov = structure(c(3L, 3L, 4L, 3L, 2L, 2L, 4L, 
2L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 1L, 3L, 2L, 3L, 3L, 1L, 1L, 3L, 
3L, 4L, 2L, 4L, 2L, 1L, 2L, 3L, 2L, 2L, 3L, 3L, 3L, 5L, 2L, 2L, 
4L, 2L, 4L, 2L, 4L, 3L, 2L, 1L, 4L, 3L, 2L, 2L, 2L, 2L, 1L, 3L, 
2L, 2L, 2L, 2L, 3L, 5L, 1L, 1L, 1L, 2L, 2L, 4L, 2L, 2L, 3L, 2L, 
4L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 2L, 2L, 3L, 2L, 4L, 1L, 2L, 
3L, 2L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 3L, 3L, 1L, 1L), .Label = c("I strongly agree", 
"I agree", "I disagree", "I strongly disagree", "Don't know"), class = "factor")), class = "data.frame", row.names = c(NA, 
-100L))

I tried the following code using forcats::fct_reorder, but it doesn't give me the desired outcome:

dataset %>%
  group_by(country) %>%
  filter(!is.na(female_head_gov), female_head_gov != "Don't know") %>%
  mutate(female_head_gov = fct_collapse(female_head_gov,
                                `Agree/strongly agree` = c("I strongly agree", "I agree"),
                                `Disagree/strongly disagree` = c("I disagree", "I strongly disagree"))
  ) %>%
  count(female_head_gov) %>%
  mutate(prop = n / sum(n)) %>%
  ggplot(aes(fct_reorder(country, prop), prop, fill = female_head_gov)) +
  geom_col(position = "fill")

enter image description here

I also tried this without calculating the proportions, but then I don't have variable to order the country variable with.

dataset %>%
  group_by(country) %>%
  filter(!is.na(female_head_gov), female_head_gov != "Don't know") %>%
  mutate(female_head_gov = fct_collapse(female_head_gov,
                                        `Agree/strongly agree` = c("I strongly agree", "I agree"),
                                        `Disagree/strongly disagree` = c("I disagree", "I strongly disagree"))
  ) %>%
  ggplot(aes(country, fill = female_head_gov)) +
  geom_bar(position = "fill")

Any ideas what I'm doing wrong? If you have any tips how to create such a bar chart more efficient, just let me know. :)

Nicosc
  • 313
  • 1
  • 7
  • Take a look at [this post](https://stackoverflow.com/a/3255448/8245406), maybe it can help. – Rui Barradas Jul 21 '20 at 11:26
  • Does this answer your question? [Order discrete x scale by frequency/value](https://stackoverflow.com/questions/3253641/order-discrete-x-scale-by-frequency-value) – tjebo Jul 21 '20 at 11:32
  • And how do I incorporate this with grouped bar charts? I don't want to order by frequency, but by proportions of one the possible values for each country. – Nicosc Jul 21 '20 at 11:35

2 Answers2

2

I guess this is because every country has two values for prop. If you specify the first value of prop it works as expected:

plot_df <- dataset %>%
  group_by(country) %>%
  filter(!is.na(female_head_gov), female_head_gov != "Don't know") %>%
  mutate(female_head_gov = fct_collapse(female_head_gov,
                                        `Agree/strongly agree` = c("I strongly agree", 
                                                             "I agree"),
                                        `Disagree/strongly disagree` = c("I disagree", 
                                                                     "I strongly disagree"))
  ) %>%
  count(female_head_gov) %>%
  mutate(prop = n / sum(n))

  plot_df$country <- fct_reorder(plot_df$country, plot_df$prop, function(x) -x[1])
  ggplot(plot_df, aes(country, prop, fill = female_head_gov)) +
  geom_col(position = "fill")

enter image description here

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • This is what I'm looking for, thanks! I noticed that I could reorder bar charts when there was just one value, but it didn't work with two values. Is there also a way to do reorder with two values inside the ggplot? – Nicosc Jul 21 '20 at 12:03
  • you may want to consider ```fct_reorder2``` which enables you to reorder ```country``` using two columns (```female_head_gov``` and ```prop```) – CourtesyBus Jul 23 '20 at 05:00
0

Solution with data.table

dataset <- data.table(dataset)

to_plot <- dataset[, .(
  female_head_gov = fifelse(
    female_head_gov %in% c("I strongly agree", "I agree"),
    'Agree/strongly agree',
    'Disagree/strongly disagree',
    na = 'Don not know'
  )
), country][, .(prop = .N), .(country, female_head_gov)][, .(prop = prop / sum(prop), female_head_gov), country]


to_plot <-
  merge(to_plot,
        to_plot[female_head_gov == 'Agree/strongly agree'][order(-prop)][, .(country, my_order = 1:.N)],
        by = 'country')

ggplot(to_plot, aes(reorder(country, my_order), prop, fill = female_head_gov)) +
  geom_bar(stat = "identity") 

enter image description here

K. Peltzer
  • 326
  • 3
  • 7