# PlotlyJS.jl: grouped + stacked bar charts

**URL:** https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657
**Category:** General Usage
**Tags:** plotting
**Created:** [August 9, 2023, 11:24pm UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657 "2023-08-09T23:24:58Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![VivMendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivmendes/32/16477_2.png) [@VivMendes](https://discourse.julialang.org/u/VivMendes)
#### Post date: [August 9, 2023, 11:24pm UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/1 "2023-08-09T23:24:58Z")

</div>

Hi,  
I need to create a plot like the one below using PlotlyJS.jl. I have done my best and extensively searched this forum and others online. Still, there seems to be very little information about stacked + grouped bar charts in Plotly to produce this type of plot in the Julia environment (there is some discussion on this issue, for example, [here](https://stackoverflow.com/questions/65289591/python-plotly-stacked-grouped-bar-chart) and [here](https://github.com/plotly/plotly.js/issues/1835), but apparently it was never settled as a standard functionality in Plotly). For me, whether the bars are vertically or horizontally oriented is irrelevant.

Some help would be very much appreciated. Thank you.

 ![a](https://global.discourse-cdn.com/julialang/original/3X/b/d/bd5e03853d3d3d80c6a3ab4bcf2207b6bae5201b.png)

---

<div class="post-metadata">

### Author: ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)
#### Post date: [August 10, 2023, 11:54am UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/2 "2023-08-10T11:54:28Z")

</div>

In this thread is given an example of grouped stacked bars. [https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/6](https://discourse.julialang.org/t/use-mapbox-to-place-images-with-plotlyjs/86758/6).

---

<div class="post-metadata">

### Author: ![VivMendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivmendes/32/16477_2.png) [@VivMendes](https://discourse.julialang.org/u/VivMendes)
#### Post date: [August 11, 2023, 12:27am UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/3 "2023-08-11T00:27:25Z")

</div>

@empet, thanks for your help. Actually, I was misled by one (or by some) of the threads I consulted with, as I have found out that the official documentation already includes an example of how to implement a grouped stacked bar plot using PlotlyJS.jl. See the last entry [here](https://plotly.com/julia/bar-charts/).

The code is as follows. I am using PlotlyBase.jl inside Pluto:

```julia
let
	x = [
		["BB+", "BB+", "BB+", "BB", "BB", "BB", "BB-", "BB-", "BB-"],
    	[16, 17, 18, 16, 17, 18, 19 , 20, 21] ]
	
	y1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] # to let direct labels
	y2 = [9, 8, 7, 6, 5, 4, 3, 2, 1] # to let direct labels
	
	Plot([bar(x=x, y=y1, text=y1, textposition="auto"),
		  bar(x=x, y=y2, text=y2, textposition="auto")], 
		  Layout(barmode="stack"))
end

```

 ![aa](https://global.discourse-cdn.com/julialang/original/3X/d/d/dd92cec9ce0536ab9b04645bb54377c57c6555ed.png)

---

<div class="post-metadata">

### Author: ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)
#### Post date: [August 11, 2023, 12:39am UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/4 "2023-08-11T00:39:40Z")

</div>

Your last example illustrates only stacked bars. The item 2. In my comment, included in the linked thread above, describes how from a specially defined daraframe we can get grouped and stacked bars.

---

<div class="post-metadata">

### Author: ![VivMendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivmendes/32/16477_2.png) [@VivMendes](https://discourse.julialang.org/u/VivMendes)
#### Post date: [August 11, 2023, 11:00pm UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/5 "2023-08-11T23:00:58Z")

</div>

Hi @empet,

Thanks for helping. I used your code and my data set (long version), but I am making some mistakes because the plot I got is not what I was looking for. The figure I get is the following:

 ![a](https://global.discourse-cdn.com/julialang/original/3X/b/e/be7fdf4b76028d66a4cf34aad7dca1804e29d81e.png)

And your code is (I am using PlotlyBase inside Pluto, so the function `Plot` instead of `plot`):

```julia
fig = Plot(long_data, kind="bar", x=:Year, y=:Percent, color=:Status, 
              Layout(barmode="stack" ))

```

In case you want to have a go and replicate that figure, my data is the following (I think you can save it into a txt file, I did it with your data example):

```julia
Year,Levels,Status,Percent
2011,Less than a High School Diploma,Employment,53.2
2011,High School Diploma ,Employment,66.9
2011,"Some College, No Degree ",Employment,70.4
2011,Associate Degree,Employment,76.2
2011,Bachelor’s Degree or Higher,Employment,81.5
2016,Less than a High School Diploma,Employment,56.1
2016,High School Diploma ,Employment,68.3
2016,"Some College, No Degree ",Employment,72.7
2016,Associate Degree,Employment,77.6
2016,Bachelor’s Degree or Higher,Employment,82.9
2021,Less than a High School Diploma,Employment,54.8
2021,High School Diploma ,Employment,66.6
2021,"Some College, No Degree ",Employment,71.3
2021,Associate Degree,Employment,75.9
2021,Bachelor’s Degree or Higher,Employment,82.9
2011,Less than a High School Diploma,Unemployment,9
2011,High School Diploma ,Unemployment,7.1
2011,"Some College, No Degree ",Unemployment,6.7
2011,Associate Degree,Unemployment,5.5
2011,Bachelor’s Degree or Higher,Unemployment,3.6
2016,Less than a High School Diploma,Unemployment,4.6
2016,High School Diploma ,Unemployment,3.8
2016,"Some College, No Degree ",Unemployment,3.4
2016,Associate Degree,Unemployment,2.9
2016,Bachelor’s Degree or Higher,Unemployment,2.1
2021,Less than a High School Diploma,Unemployment,5.1
2021,High School Diploma ,Unemployment,4.5
2021,"Some College, No Degree ",Unemployment,4.2
2021,Associate Degree,Unemployment,3.6
2021,Bachelor’s Degree or Higher,Unemployment,2.5
2011,Less than a High School Diploma,Not_in_LF,37.8
2011,High School Diploma ,Not_in_LF,26
2011,"Some College, No Degree ",Not_in_LF,22.9
2011,Associate Degree,Not_in_LF,18.3
2011,Bachelor’s Degree or Higher,Not_in_LF,14.9
2016,Less than a High School Diploma,Not_in_LF,39.3
2016,High School Diploma ,Not_in_LF,27.9
2016,"Some College, No Degree ",Not_in_LF,23.9
2016,Associate Degree,Not_in_LF,19.6
2016,Bachelor’s Degree or Higher,Not_in_LF,15
2021,Less than a High School Diploma,Not_in_LF,40.2
2021,High School Diploma ,Not_in_LF,28.9
2021,"Some College, No Degree ",Not_in_LF,24.5
2021,Associate Degree,Not_in_LF,20.4
2021,Bachelor’s Degree or Higher,Not_in_LF,14.6

```

The plot I was looking for is something like the following one:

 ![aa](https://global.discourse-cdn.com/julialang/original/3X/6/5/65e111958c19a3191cefca68b1bc2f6d5ea3a5d3.png)

Despite accomplishing the figure I needed, I wouldn’t say I liked the entire process because my code was inefficient. For example, if I want to insert the direct labels into the plot, I have to insert them manually; or if I want to change the nature of the groups (from Years to Levels), I have a lot of work to do. This is because to produce the figure above, I had to generate three individual plots (one for 2011, another for 2016, and one for 2021), and then merge them into a 1 x 3 subplot grid. This leads to another major trouble: I do not know how to impose a single set of legends that operates on all three subplots in the final output.

The code I used to produce the individual plots is the following (e.g., for 2021), and the data set is wide in this case (I am using Pluto and PlotlyBase.jl):

```julia
begin
	y1c = [54.8, 66.6, 71.3, 75.9, 82.9] # to let direct labels
	y2c = [5.1, 4.5, 4.2, 3.6, 2.5] # to let direct labels
	y3c = [40.2, 28.9, 24.5, 20.4, 14.6] # to let direct labels
	
	fig24 = Plot([bar(filter(row -> row.Year == 2021, data), 
		x="Years", y=y, name=string(y)) for y in [:Employment, :Unemployment, :Not] ])
	relayout!(fig24, barmode="stack", title_text="2021", title_x=0.5, xaxis=attr(
        tickmode = "array",
        tickvals = [0, 1, 2, 3, 4],
        ticktext = ["HS-", "HS", "Col-", "Pro", "Col+"] 
		))
	restyle!(fig24, marker_color=["teelBlue", "darkblue", "Salmon"], text= [y1c, y2c, y3c], textposition="auto", showlegend=true)
	fig24
end

```

Thanks for your concerns.

---

<div class="post-metadata">

### Author: ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)
#### Post date: [August 12, 2023, 4:34am UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/6 "2023-08-12T04:34:37Z")

</div>

For the next 10 days I don’t have access to a computer. If it’s not too late I’ll try when I go back at home.

---

<div class="post-metadata">

### Author: ![VivMendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivmendes/32/16477_2.png) [@VivMendes](https://discourse.julialang.org/u/VivMendes)
#### Post date: [August 12, 2023, 8:56am UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/7 "2023-08-12T08:56:50Z")

</div>

@empet, no problem I am not in a hurry. Thanks.

---

<div class="post-metadata">

### Author: ![rgouveiamendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rgouveiamendes/32/218636_2.png) [@rgouveiamendes](https://discourse.julialang.org/u/rgouveiamendes)
#### Post date: [August 14, 2023, 6:21pm UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/8 "2023-08-14T18:21:42Z")

</div>

@VivMendes I think I can do it in a more efficient way.  
Notice that according to the documentation you have just mentioned, multi-category axis charts can be only achieved using raw arrays and not DataFrames.  
In fact, we cannot pass a vector of symbols to the `x` or the `y` kwargs inside the `Plot()` function to have two categories in one axis.  
But you can always work with the columns of the DataFrame as arrays.  
Here is my suggestion:

```julia
Plot(
	[bar(;
		x = [longdf.Year, longdf.Levels],
		y = filter(:Status => x -> x == "NotinLF",longdf).Percent,
		name = "Not in the Labor Force"),
	bar(;
		x = [longdf.Year, longdf.Levels],
		y = filter(:Status => x -> x == "Unemployment",longdf).Percent,
		name = "Unemployed"),
	bar(;
		x = [longdf.Year, longdf.Levels],
		y = filter(:Status => x -> x == "Employment",longdf).Percent,
		name = "Employed")],
    Layout(
		barmode="stack",
		height = 600
	)
)

```

Here is what I get:

 ![plot1](https://global.discourse-cdn.com/julialang/original/3X/1/a/1ac207695f5eaf9bb02951a31f959d8c0caa7d9c.png)

And if you want them horizontal:

```julia
Plot(
	[bar(;
		x = filter(:Status => x -> x == "NotinLF",longdf).Percent,
		y = [longdf.Year, longdf.Levels],
		name = "Not in the Labor Force",
		orientation = "h"),
	bar(;
		x = filter(:Status => x -> x == "Unemployment",longdf).Percent,
		y = [longdf.Year, longdf.Levels],
		name = "Unemployed",
		orientation = "h"),
	bar(;
		x = filter(:Status => x -> x == "Employment",longdf).Percent,
		y = [longdf.Year, longdf.Levels],
		name = "Employed",
		orientation = "h")],
    Layout(
		barmode="stack",
		height = 600
	)
)

```

 ![plot2](https://global.discourse-cdn.com/julialang/original/3X/4/2/4222cb110a588ece8e904586993db7d84e97fa0b.png)

I have converted the values in column `Year` to strings, to make sure Plotly does not mess-up with dates.  
Depending on your goal, it may also be wise to store in different variables the subsets of the DataFrame that you want to use later according to the `:Status`.

But let us wait for @empet, since she always has clever solutions. 🙂

---

<div class="post-metadata">

### Author: ![VivMendes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vivmendes/32/16477_2.png) [@VivMendes](https://discourse.julialang.org/u/VivMendes)
#### Post date: [August 14, 2023, 10:35pm UTC](https://discourse.julialang.org/t/plotlyjs-jl-grouped-stacked-bar-charts/102657/9 "2023-08-14T22:35:38Z")

</div>

@rgouveiamendes, thank you very much. This solves the problem. It seems easy after we see it done.
