Search code examples
juliabar-chartpercentagestacked-chart

Percentage stacked barplot in Julia


I would like to create a percentage stacked barplot in Julia. In R we may do the following:

set.seed(7)
data <- matrix(sample(1:30,6), nrow=3)
colnames(data) <- c("A","B")
rownames(data) <- c("V1","V2","V3")
library(RColorBrewer)
cols <- brewer.pal(3, "Pastel1") 
df_percentage <- apply(data, 2, function(x){x*100/sum(x,na.rm=T)})
barplot(df_percentage, col=cols, border="white", xlab="group")

Created on 2022-12-29 with reprex v2.0.2

I am now able to create the axis in percentages, but not to make it stacked and percentage for each stacked bar like above. Here is some reproducible code:

using StatsPlots

measles = [38556, 24472]
mumps = [20178, 23536]
chickenPox = [37140, 32169]
ticklabel = ["A", "B"]
foo = @. measles + mumps + chickenPox
my_range = LinRange(0, maximum(foo), 11)

groupedbar(
  [measles mumps chickenPox],
  bar_position = :stack,
  bar_width=0.7,
  xticks=(1:2, ticklabel),
  yticks=(my_range, 0:10:100),
  label=["measles" "mumps" "chickenPox"]
)

Output:

enter image description here

This is almost what I want. So I was wondering if anyone knows how to make a stacked percentage barplot like above in Julia?


Solution

  • You just need to change the maximum threshold of the LinRange to be fitted to the maximum value of bars (which is 1 in this case), and change the input data for plotting to be the proportion of each segment:

    my_range = LinRange(0, 1, 11)
    foo = @. measles + mumps + chickenPox
    groupedbar(
      [measles./foo mumps./foo chickenPox./foo],
      bar_position = :stack,
      bar_width=0.7,
      xticks=(1:2, ["A", "B"]),
      yticks=(my_range, 0:10:100),
      label=["measles" "mumps" "chickenPox"],
      legend=:outerright
    )
    

    enter image description here

    If you want to have the percentages on each segment, then you can use the following function:

    function percentages_on_segments(data)
      first_phase = permutedims(data)[end:-1:1, :]
      a = [0 0;first_phase]
      b = accumulate(+, 0.5*(a[1:end-1, :] + a[2:end, :]), dims=1)
      c = vec(b)
    
      annotate!(
        repeat(1:size(data, 1), inner=size(data, 2)),
        c,
        ["$(round(100*item, digits=1))%" for item=vec(first_phase)],
        :white
      )
    end
    
    percentages_on_segments([measles./foo mumps./foo chickenPox./foo])
    

    Note that [measles./foo mumps./foo chickenPox./foo] is the same data that I passed to the groupedbar function: enter image description here