Search code examples
rggplot2bar-chart

mixed bar plots creation and arrangement in a descending order


The problem is fairly straightforward. How to create a descending bar plot arrangement in which those bars where Item are same are shown as stacked but they are arranged according to the gross value as the case may be and also it is very difficult to get the labels for each bar properly centered. :

structure(list(Reporter = c("Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bangladesh", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "Bhutan", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "India", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Pakistan", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka", "Sri Lanka"), Partners = c(India = "India", Pakistan = "Pakistan", Pakistan = "Pakistan", India = "India", Pakistan = "Pakistan", China, mainland = "CHINA", India = "India", Pakistan = "Pakistan", India = "India", India = "India", India = "India", Pakistan = "Pakistan", Pakistan = "Pakistan", India = "India", Pakistan = "Pakistan", India = "India", Pakistan = "Pakistan", China, mainland = "CHINA", India = "India", Belgium = "Belgium", United Arab Emirates = "UAE", Netherlands (Kingdom of the) = "NLD", Philippines = "Philippines", T<fc>rkiye = "TURKEY", Poland = "Poland", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", Singapore = "Singapore", Japan = "Japan", India = "India", India = "India", Japan = "Japan", Belgium = "Belgium", India = "India", India = "India", India = "India", India = "India", Iran (Islamic Republic of) = "IRN", Saudi Arabia = "Saudi Arabia", China, mainland = "CHINA", Benin = "Benin", Iran (Islamic Republic of) = "IRN", Saudi Arabia = "Saudi Arabia", Benin = "Benin", Bangladesh = "Bangladesh", Sudan = "Sudan", Bangladesh = "Bangladesh", China, mainland = "CHINA", Bangladesh = "Bangladesh", United States of America = "USA", China, mainland = "CHINA", Malaysia = "Malaysia", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", United States of America = "USA", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", India = "India", China, mainland = "CHINA", United Arab Emirates = "UAE", Afghanistan = "Afghanistan", Kenya = "Kenya", Malaysia = "Malaysia", Saudi Arabia = "Saudi Arabia", United Arab Emirates = "UAE", Kenya = "Kenya", China, mainland = "CHINA", Malaysia = "Malaysia", Saudi Arabia = "Saudi Arabia", China, mainland = "CHINA", United Arab Emirates = "UAE", Viet Nam = "Viet Nam", China, mainland = "CHINA", Iraq = "Iraq", Russian Federation = "RUS", United Arab Emirates = "UAE", T<fc>rkiye = "TURKEY", Iran (Islamic Republic of) = "IRN", Azerbaijan = "Azerbaijan", China, mainland = "CHINA", Saudi Arabia = "Saudi Arabia", Libya = "Libya", United States of America = "USA", Mexico = "Mexico", United States of America = "USA", India = "India", India = "India", India = "India"), Item = structure(c(1L, 2L, 3L, 3L, 4L, 5L, 6L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 14L, 14L, 15L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 18L, 19L, 20L, 21L, 17L, 22L, 23L, 24L, 25L, 26L, 26L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 33L, 34L, 34L, 34L, 34L, 35L, 35L, 35L, 36L, 37L, 38L, 39L, 40L, 26L, 41L, 42L, 43L, 44L, 22L, 45L, 46L, 26L, 47L, 48L, 49L, 32L, 24L, 50L, 51L, 52L, 53L, 34L, 34L, 34L, 34L, 34L, 34L, 35L, 35L, 35L, 35L, 35L, 39L, 54L, 40L, 55L, 46L, 46L, 46L, 46L, 46L, 46L, 46L, 46L, 46L, 46L, 56L, 56L, 57L, 5L, 58L), .Label = c("Raisin", "Grape", "Bean", "Tomato", "Areca_nut", "Apricot", "Pistachio", "Spice", "Almond", "Cucumber", "Apple", "Other_spice", "Other_pulse", "Jute", "Other_oil", "Tobacco", "Other_beverage", "Cotton_waste", "Fatty_acid", "Bread", "Pastry", "Nutmeg", "Beer", "Food_preparation", "Ice", "Organic_material", "Fruit", "Mushroom", "Essential_oil", "Vegetable", "Tomato_paste", "Orange_juice", "Other_vegetable", "Rice", "MIlled_Rice", "Cotton", "Sugar", "Wheat", "Broken_rice", "Maize", "Castor_oil", "Buffalo_meat", "Soybean_oil", "Palm_oil", "Fruit_juice", "Tea", "Pet_food", "Sunflower_oil", "Rapeseed_cake", "Ginger", "Cereal_bran", "Pasta", "Pineapple_juice", "Cattle_meat", "Sesame", "Cinnamon", "Food_waste", "Pepper"), class = "factor"), 2022 = c(70170, 45225, 21034, 12639, 31972, 30551, 13541, 9741, 21791, 16870, 15190, 13996, 11759, 11190, 8983, 85727, 50933, 13873, 145552, 55120, 30817, 11560, 11447, 10925, 7994, 25753, 21422, 15522, 12939, 9348, 4798, 2628, 1877, 1116, 918, 374, 87, 44, 485, 280, 56, 49, 42, 41, 33, 1155110, 989793, 670286, 550932, 1154891, 989229, 546094, 941907, 768640, 734544, 601313, 575785, 564496, 497992, 489397, 186906, 186002, 46438, 35158, 29504, 27216, 20253, 18964, 18529, 6480, 6222, 6182, 5885, 4518, 3849, 361166, 235395, 176464, 175743, 152178, 106991, 232097, 175118, 157452, 151357, 106021, 203714, 173015, 127836, 95205, 153122, 131284, 124682, 75956, 73993, 68532, 50155, 46536, 43398, 42380, 92446, 41473, 115336, 68592, 67677), Item_largest = c(70170, 45225, 33673, 33673, 31972, 30551, 23282, 23282, 21791, 16870, 15190, 13996, 11759, 11190, 8983, 150533, 150533, 150533, 145552, 127863, 127863, 127863, 127863, 127863, 127863, 25753, 21422, 15522, 12939, 9348, 4798, 2628, 1877, 1116, 918, 505, 505, 505, 485, 280, 56, 49, 42, 41, 33, 3366121, 3366121, 3366121, 3366121, 2690214, 2690214, 2690214, 941907, 768640, 734544, 601313, 575785, 564496, 497992, 489397, 186906, 186002, 46438, 35158, 29504, 27216, 20253, 18964, 18529, 6480, 6222, 6182, 5885, 4518, 3849, 1207937, 1207937, 1207937, 1207937, 1207937, 1207937, 822045, 822045, 822045, 822045, 822045, 203714, 173015, 127836, 95205, 810038, 810038, 810038, 810038, 810038, 810038, 810038, 810038, 810038, 810038, 133919, 133919, 115336, 68592, 67677 ), Order = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L)), row.names = c(NA, -105L), class = c("tbl_df", "tbl", "data.frame"))

The code used is as follows:

# Define a discrete color palette
color_palette <- c("India" = "blue", "Pakistan" = "red", "CHINA" = "green", 
                   "Belgium" = "purple", "UAE" = "orange", "NLD" = "cyan", 
                   "Philippines" = "magenta", "TURKEY" = "yellow", 
                   "Poland" = "brown", "Singapore" = "grey", 
                   "Japan" = "pink", "IRN" = "lightblue", 
                   "Saudi Arabia" = "darkgreen", "Benin" = "lightgreen", 
                   "Sudan" = "darkred", "USA" = "darkblue", "Malaysia" = "lightyellow")


# Create the plot
ggplot(asx3, aes(x = Item, y = `2022`, fill = Partners)) +
  geom_bar(stat = "identity", position = "stack") +
  coord_flip() +
  facet_wrap(~Reporter, scales = "free", drop = TRUE, nrow = 4) +
  scale_fill_manual(values = color_palette) +
  labs(title = "South Asia's Top Export Partners, 2022, '000 USD",
       caption = "Source: fao.org") +
  theme(legend.title = element_blank(),
        legend.position = "none",
        axis.title.y = element_blank(),
        axis.text.y = element_text(size = 10),
        plot.caption = element_text(face = "italic")) +
  geom_text(aes(label = Partners), color = "white", size = 3)

the output


Solution

  • You have to reorder the variable mapped on the y axis according to the total value. Things get more complicated as you want to do that per facet. To this end you can use tidytext::reorder_within + tidytext::scale_x/y_reordered or do it manually as I do below using a helper column formed as the interaction of Item and Reporter.

    To align the labels with the bars you have use position_stack for the geom_text too. Note however, that even with the proper alignment this does not look great as the country names are in most cases quite long.

    Note: I switched x and y to get rid of coord_flip.

    library(tidyverse)
    
    asx3 <- asx3 |>
      # Clean labels
      mutate(
        Reporter = gsub("\n", " ", Reporter, fixed = TRUE),
        Item = gsub("_", " ", Item)
      ) |>
      # Get total
      mutate(
        total = sum(`2022`),
        .by = c(Reporter, Item)
      ) |>
      # Arrange 
      arrange(Reporter, total) |>
      # Set order
      mutate(group_y = fct_inorder(
        paste(Item, Reporter, sep = ".")
      ))
    
    ggplot(asx3, aes(y = group_y, x = `2022`, fill = Partners)) +
      geom_bar(stat = "identity", position = "stack") +
      facet_wrap(~Reporter, scales = "free", drop = TRUE, nrow = 4) +
      scale_fill_manual(values = color_palette) +
      # Clean axis text
      scale_y_discrete(
        labels = \(x) gsub("\\..*$", "", x)
      ) +
      labs(
        title = "South Asia's Top Export Partners, 2022, '000 USD",
        caption = "Source: fao.org",
        x = NULL, fill = NULL
      ) +
      geom_text(
        aes(label = Partners),
        color = "white", size = 3,
        position = position_stack(vjust = .5)
      ) +
      guides(fill = "none")
    

    enter image description here