1

For the dataset below, I'd like to customize my below plot by ordering states according to the total number of deaths experienced by age 65. I tried the below code.

The answer here does not answer my question because my x variables include 50 values whereas the response is helpful for variables with a few values.

Thanks,

NM

Here is my data:

CAPS_2019 <- structure(list(Age = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 
2L, 3L), .Label = c("30", "50", "65"), class = "factor"), Dx = c(3.057, 
7.847, 17.157, 2.851, 8.861, 21.885, 2.521, 7.889, 21.328), PopName = structure(c(1L, 
1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), .Label = c("AK", "AL", "AR"), class = "factor")), row.names = c(NA, 
-9L), class = c("tbl_df", "tbl", "data.frame"))

My code:

CAPS_plot_facet <- CAPS_2019 %>% 
  ggplot(aes(x = reorder(PopName, Dx), y = Dx, fill = factor(as.character(Age)))) +
  geom_col(position = position_stack(reverse = TRUE)) +
  facet_wrap("Age",scales="free_x")+
  theme_classic()+
  theme(strip.background = element_blank(), strip.text = element_blank())+
  coord_flip()+
  labs(x = "State", y = "Deaths (%)", caption = (""), face = "bold", fill = "Age")
CAPS_plot_facet 

My plot:

enter image description here

Nader Mehri
  • 514
  • 1
  • 5
  • 21
  • 2
    Does this answer your question? [Order discrete x scale by frequency/value](https://stackoverflow.com/questions/3253641/order-discrete-x-scale-by-frequency-value) – Limey Jun 07 '22 at 15:06
  • I don't think so! My x variables include 50 values whereas the response you are pointing to is helpful for variables with a few values. – Nader Mehri Jun 07 '22 at 15:12
  • 1
    I beg to differ. You have more work to do because you have more levels of your "factor". But I believe it gives you exactly the technique you need to use. – Limey Jun 07 '22 at 15:14

2 Answers2

2

@RobertoT's answer discusses how to sort by Age and Dx. If you want to do that inline using dplyr::arrange and forcats::fct_inorder:

Reorder by Age and Dx

library(dplyr)
library(forcats)

CAPS_2019 %>% 
  arrange(desc(Age), desc(Dx)) %>% 
  ggplot(aes(x = fct_inorder(PopName), y = Dx, fill = factor(as.character(Age)))) +
  geom_col(position = position_stack(reverse = TRUE)) +
  facet_wrap("Age",scales="free_x")+
  theme_classic()+
  theme(strip.background = element_blank(), strip.text = element_blank())+
  coord_flip()+
  labs(x = "State", y = "Deaths (%)", caption = (""), face = "bold", fill = "Age")



Reorder specifically by Dx at Age 65

If you want to specifically sort by Deaths for Age 65 (per the submission's question), you can do the following:

library(dplyr)
library(forcats)

CAPS_2019 %>% 
  group_by(PopName) %>%
  mutate(Dx_Age65 = Dx[Age == 65]) %>%
  ggplot(aes(x = fct_reorder(PopName, Dx_Age65, .desc = TRUE), y = Dx, fill = factor(as.character(Age)))) +
  geom_col(position = position_stack(reverse = TRUE)) +
  facet_wrap("Age",scales="free_x")+
  theme_classic()+
  theme(strip.background = element_blank(), strip.text = element_blank())+
  coord_flip()+
  labs(x = "State", y = "Deaths (%)", caption = (""), face = "bold", fill = "Age")
Or Gadish
  • 128
  • 5
1

Popname is a factor with some levels that already sort the values. You have to rearrange them:

> CAPS_2019$PopName
[1] AK AK AK AL AL AL AR AR AR
Levels: AK AL AR

You can arrange the df by descending order in Age and Dx so the first values in Popname are sorted.

CAPS_2019 %>% arrange(desc(Age),desc(Dx))

# A tibble: 9 x 3
  Age      Dx PopName
  <fct> <dbl> <fct>  
1 65    21.9  AL     
2 65    21.3  AR     
3 65    17.2  AK     
4 50     8.86 AL     
5 50     7.89 AR     
6 50     7.85 AK     
7 30     3.06 AK     
8 30     2.85 AL     
9 30     2.52 AR 

If you extract the unique values of Popname already sorted you can use them to reset the levels as you want. But, because you are using coord_flip() to flip the axis, the levels will be sorted the other way round in your plot. You can fix it in the ggplot code or just sort the levels in ascending order:

CAPS_2019 %>% arrange(desc(Age),Dx) %>% pull(PopName) %>% unique() %>% as.character()
[1] "AK" "AR" "AL"

Then, just edit the Popname column with the new levels:

CAPS_2019$PopName = factor(as.character(CAPS_2019$PopName), # the values
                           CAPS_2019 %>% arrange(desc(Age),Dx) %>% pull(PopName) %>% unique() %>% as.character()  # the levels sorted in ascending
)
[1] AK AK AK AL AL AL AR AR AR
Levels: AK AR AL

Next, plot the graph as it is. Changing the aesthetic for x-axis in ggplot() as: x = Popname

enter image description here

PS: Note if you don't flip the axis then the plot are sorted in ascending.

enter image description here

RobertoT
  • 1,663
  • 3
  • 12
  • Thanks! This is really helpful! How can I sort y ascendingly? I tried y=-Dx but it changed the alignment of the bars. – Nader Mehri Jun 07 '22 at 15:24
  • Look my edit. I realised that `coord_flip()` change the order of the levels upside down. – RobertoT Jun 07 '22 at 15:25
  • @RobertoT and what is the difference to the provided code of the OP. It gives exactly the same plot. Or do I overlook something? – TarJae Jun 07 '22 at 15:34
  • 1
    @TarJae In the previous code the x-axis is sorted with `x = reorder(PopName, Dx)`. This reorder the x-axis by total Dx among all Age categories. In my solution, the levels of PopName were sorted based only on Age == 65. It is just a coincidence that the order is the same in the example. The previous code it is like reordering using: `CAPS_2019 %>% group_by(PopName) %>% summarise(Dx=sum(Dx)) %>% arrange(Dx)` which for sure won't be the same for a big df. – RobertoT Jun 07 '22 at 16:38
  • 1
    Actually, it will be much cleaner applying only `x = reorder(PopName, Z)`, where Z is only the order using AGE == 65. However, I don't know how. – RobertoT Jun 07 '22 at 16:39