rggplot2rotationstacked-bar-chartggforce

How to create a stacked-bar plot inclined 45 degrees as per W.E.B. DuBois' style in R using ggforce among others?


enter image description hereGiven the following data, I have tried different approaches in R with no success. Can someone Help?

structure(list(Category = c("Government", "Society", "Persons", 
"Property", "Miscellaneous"), Percent = c(0.7, 13.4, 27.6, 48.2, 
10.6)), class = "data.frame", row.names = c(NA, -5L))

These is the codes that I have tried:

 library(ggplot2)
library(ggforce)

# Data
df <- structure(list(Category = c("Government", "Society", "Persons", 
                                  "Property", "Miscellaneous"), Percent = c(0.7, 13.4, 27.6, 48.2, 10.6)), 
                 class = "data.frame", row.names = c(NA, -5L))

# Calculate endpoints for the lozenge shape
df$xend <- c(0, cumsum(df$Percent)[-length(df$Percent)])
df$xstart <- df$xend + df$Percent
df$y <- 1

# Set colors for the stacked bars
colors <- c("#E5C2A0", "#D3976A", "#B86F4A", "#A14F3D", "#802E2E")

# Create plot
ggplot(df, aes(x = y, y = xstart, fill = Category, group = Category)) +
  geom_polygon(aes(x = y, y = xstart, group = Category), fill = colors[1], color = NA) +
  geom_polygon(aes(x = y, y = xend, group = Category), fill = colors[2], color = NA) +
  geom_polygon(aes(x = y, y = xend, group = Category), fill = colors[3], color = NA) +
  geom_polygon(aes(x = y, y = xend, group = Category), fill = colors[4], color = NA) +
  geom_polygon(aes(x = y, y = xend, group = Category), fill = colors[5], color = NA) +
  scale_fill_manual(values = rev(colors)) +
  coord_flip() +
  theme_void() +
  theme(legend.position = "none") +
  geom_text(aes(x = 0.5, y = cumsum(Percent) - Percent/2, label = paste0(Percent, "%")),
            color = "white", size = 4, fontface = "bold", angle = 90, hjust = 0.5, vjust = 0.5)

Eric's code was tweaked to reproduce the original Dubois's Inclined Stacked Bar. I have used the rev() and apply() functions to reverse the order of the data.

Also, I have locked in the factor level order as same in the data so that ggplot2 plot them in the correct order.


library(ggplot2)
library(dplyr)
library(tidyr)

# Data
df <- structure(list(Category = c("Government", "Society", "Persons", 
                                  "Property", "Miscellaneous"), Percent = c(0.7, 13.4, 27.1, 48.2, 10.6)), 
                class = "data.frame", row.names = c(NA, -5L)) 

# calculating reverse
df1 <- apply(df, 2, rev)

# converting the result to dataframe
df1 <- as.data.frame(df1)

df1$Category <- factor(df1$Category, levels = df1$Category) 

#select incline angle
angle=-pi/4

#create rotation matrix
rotate_matrix = matrix(c(cos(angle),-sin(angle),sin(angle),cos(angle)),ncol = 2,byrow=T)

bar_width=30

#create polygon points, rotate, pivot long
df1 <- df1 %>%
  mutate(
    cum_pct = cumsum(Percent),
    x_start = 0,
    x_end = bar_width,
    y_start=lag(cum_pct),
    y_end=cum_pct
  ) %>%
  replace_na(list(y_start=0)) %>%
  rowwise() %>%
  mutate(
    p1_x = (rotate_matrix %*% c(x_start,y_start))[1],
    p1_y = (rotate_matrix %*% c(x_start,y_start))[2],
    p2_x = (rotate_matrix %*% c(x_start,y_end))[1],
    p2_y = (rotate_matrix %*% c(x_start,y_end))[2],
    p4_x = (rotate_matrix %*% c(x_end,y_start))[1],
    p4_y = (rotate_matrix %*% c(x_end,y_start))[2],
    p3_x = (rotate_matrix %*% c(x_end,y_end))[1],
    p3_y = (rotate_matrix %*% c(x_end,y_end))[2]
    ) %>%
  pivot_longer(p1_x:p3_y,names_to = c("point",".value"), names_sep="_") %>%
  arrange(Category,point)

#colors
colors <- c("#00aa00", "#000000", "#654321", "#ffd700", "#dc143c")

# lock in factor level order
df1$Category <- factor(df1$Category, levels = df1$Category) 

ggplot(df1, aes(x = x,y = y, color = Category, fill = Category))+
  geom_polygon()+
  theme_void()+
  scale_color_manual(values = colors)+[![enter image description here][1]][1]
  scale_fill_manual(values = colors)

Solution

  • library(ggplot2)
    library(dplyr)
    library(tidyr)
    
    # Data
    df <- structure(list(Category = c("Government", "Society", "Persons", 
                                      "Property", "Miscellaneous"), Percent = c(0.7, 13.4, 27.1, 48.2, 10.6)), 
                    class = "data.frame", row.names = c(NA, -5L)) 
    
    #select incline angle
    angle=-pi/4
    
    #create rotation matrix
    rotate_matrix = matrix(c(cos(angle),-sin(angle),sin(angle),cos(angle)),ncol = 2,byrow=T)
    
    bar_width=30
    
    #create polygon points, rotate, pivot long
    df <- df %>%
      mutate(
        cum_pct = cumsum(Percent),
        x_start = 0,
        x_end = bar_width,
        y_start=lag(cum_pct),
        y_end=cum_pct
      ) %>%
      replace_na(list(y_start=0)) %>%
      rowwise() %>%
      mutate(
        p1_x = (rotate_matrix %*% c(x_start,y_start))[1],
        p1_y = (rotate_matrix %*% c(x_start,y_start))[2],
        p2_x = (rotate_matrix %*% c(x_start,y_end))[1],
        p2_y = (rotate_matrix %*% c(x_start,y_end))[2],
        p4_x = (rotate_matrix %*% c(x_end,y_start))[1],
        p4_y = (rotate_matrix %*% c(x_end,y_start))[2],
        p3_x = (rotate_matrix %*% c(x_end,y_end))[1],
        p3_y = (rotate_matrix %*% c(x_end,y_end))[2]
        ) %>%
      pivot_longer(p1_x:p3_y,names_to = c("point",".value"), names_sep="_") %>%
      arrange(Category,point)
    
    #colors
    colors <- c("#E5C2A0", "#D3976A", "#B86F4A", "#A14F3D", "#802E2E")
    
    # Create plot
    ggplot(df, aes(x = x,y = y, color = Category, fill = Category))+
      geom_polygon()+
      theme_minimal()+
      scale_color_manual(values = colors)+
      scale_fill_manual(values = colors)+
      labs(title = "W.E.B Du Bois-Style Inclined Stacked Bar")
    

    enter image description here