Search code examples
rggplot2plotlydata-visualizationggplotly

How to build customized Barchart in ggplotly?


I have bar chart with positive and negative bars. My goal is to do it in ggplotly and fill negative one with white color and keep borders with the same colors.

Code:

df <- data.frame (model = c("A","A","A","A","A","B","B","B","B","B"),
                  size = c("med","big","small","big","small","med","big","small","big","small"),
                  sale = c(1001,1050,-300,-150,-25,960,670,90,-105,-76),
                  area = c("med","large","narrow","large","narrow","med","large","narrow","large","narrow")
                  )



 ggplot() +
  # plot positive with fill and colour based on model
  geom_col(aes(sale, tidytext::reorder_within(size, sale, model),
               fill = size, color = size), 
           data = df,
           position = "stack") + 
  tidytext::scale_y_reordered() +
  labs(fill = "margin2") +
  facet_grid(model ~ ., switch = "y",scales = "free_y") +
  theme(axis.text.x = element_text(angle = 90),
        strip.background = element_rect(fill = "white"),
        strip.placement = "outside",
        strip.text.y.left = element_text(angle = 0),
        panel.spacing = unit(0, "lines")) + 
  theme(legend.position="none") + geom_vline(xintercept = 0)

Output Expexcted output:

Expexcted output


Solution

  • You could do a bit of data manipulation and add another layer:

    df %>%
      mutate(y = tidytext::reorder_within(size, sale, model)) %>%
      group_by(size, model) %>%
      mutate(sale_neg = sum(sale[sale < 0])) %>%
      ggplot(aes(sale, y, fill = size, color = size)) +
      geom_col(position = "stack") + 
      geom_col(position = 'identity', aes(x = sale_neg), fill = 'white') +
      tidytext::scale_y_reordered() +
      labs(fill = "margin2") +
      facet_grid(model ~ ., switch = "y",scales = "free_y") +
      theme(axis.text.x = element_text(angle = 90),
            strip.background = element_rect(fill = "white"),
            strip.placement = "outside",
            strip.text.y.left = element_text(angle = 0),
            panel.spacing = unit(0, "lines")) + 
      theme(legend.position="none") + geom_vline(xintercept = 0)
    

    enter image description here