# Stacked bar graphs

**URL:** <https://discourse.julialang.org/t/stacked-bar-graphs/18550>\
**Category:** Visualization\
**Tags:** statsplots, vegalite\
**Created:** [December 11, 2018, 9:08am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550 "2018-12-11T09:08:29Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 11, 2018, 9:08am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/1 "2018-12-11T09:08:29Z")

</div>

Hello all, I’m quite new to Julia and was a bit lost on how to create Stacked Bar graphs. I’d like to have ideally 8 bars, grouped in pairs. Each of these bars would have 5 stacks that add up to a 100%- this is basically plotting a variance decomposition. So it would look like 4 sets of 2 bars each, each grouped pair of bars would have the same repeating label of “Conditional” and “Unconditional Variance”, and the stacks would represent shocks/errors that have their own titles. Each pair would represent testing a certain model, i.e. 4 models being tested in total.

I’d appreciate any and all help, thank you!

---

<div class="post-metadata">

**Author:** ![Mattriks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mattriks/32/351_2.png) [@Mattriks](https://discourse.julialang.org/u/Mattriks)\
**Post date:** [December 11, 2018, 10:06am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/2 "2018-12-11T10:06:03Z")

</div>

In `Gadfly`:

```plaintext
import Cairo
using DataFrames, Gadfly, RDatasets
D = dataset("datasets","HairEyeColor")
palette = ["brown","blue","tan","green"]

p = plot(D, x=:Sex, y=:Freq, color=:Eye, xgroup=:Hair,
    Geom.subplot_grid(Geom.bar(position=:stack)),
    Scale.color_discrete_manual(palette...), 
    Guide.xlabel("Hair color"))

# draw(PNG("haireyecolor.png", 6.6inch, 4inch), p)
draw(PNG(6.6inch, 4inch), p)

```

![haireyecolor](https://global.discourse-cdn.com/julialang/original/3X/9/1/918e0b4d571df70cf5f37f059f16cbd99bbad854.png)

For more Gadfly, see the [plot gallery](http://gadflyjl.org/stable/gallery/geometries/).

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [December 11, 2018, 10:09am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/3 "2018-12-11T10:09:16Z")

</div>

An alternative is to use StatPlots: [https://github.com/JuliaPlots/StatPlots.jl#grouped-bar-plots](https://github.com/JuliaPlots/StatPlots.jl#grouped-bar-plots)

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 11, 2018, 1:03pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/4 "2018-12-11T13:03:38Z")

</div>

I’ve seen this and attempted it with StatPlots, but I’m not sure where to input the values (manually) for the stacks? And to group them in pairs?

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 11, 2018, 1:03pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/5 "2018-12-11T13:03:39Z")

</div>

great, thank you! If I wanted to input the values manually, how would this be arranged? I.e. in what order?

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 11, 2018, 1:03pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/6 "2018-12-11T13:03:40Z")

</div>

I was looking at attempting what you did in this: [https://discourse.julialang.org/t/plots-bars-side-by-side](https://discourse.julialang.org/t/plots-bars-side-by-side) but with manually adding stacks and putting in these values for each bar having 5 stacks.

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [December 11, 2018, 1:36pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/7 "2018-12-11T13:36:20Z")

</div>

Interestingly enough I think StatPlots and StatsMakie are both a bit ill-equipped to _both_ stack and dodge bars at the same time. It should be possible to add this feature to StatsMakie with the new grouping API though.

---

<div class="post-metadata">

**Author:** ![Mattriks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mattriks/32/351_2.png) [@Mattriks](https://discourse.julialang.org/u/Mattriks)\
**Post date:** [December 11, 2018, 4:45pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/8 "2018-12-11T16:45:15Z")

</div>

@svpillai The easiest way to enter data is to make a `DataFrame`. e.g.

```julia
# Set up the DataFrame
D = [[x model prop] for x in ["Conditional", "Unconditional"], 
        model in "Model".*["1","2","3","4"], prop in 1:5]
 D = DataFrame(vcat(D...), [:Variance, :Model, :Prop])

# Now enter the corresponding values in a new column like this:
D[:values] = [20, 40,]

```

For more DataFrames, see the [DataFrames docs](http://juliadata.github.io/DataFrames.jl/stable/).

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [December 11, 2018, 9:15pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/9 "2018-12-11T21:15:52Z")

</div>

Yes, but you can do it manually by defining the matrix values for groupedbars and passing the x positions to x. In this case I find the gadfly way nicer, though.

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [December 13, 2018, 2:06am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/10 "2018-12-13T02:06:56Z")

</div>

Here is the [VegaLite.jl](https://github.com/fredo-dedup/VegaLite.jl) way:

```julia
using VegaLite, RDatasets

df = dataset("datasets", "HairEyeColor")

df |> @vlplot(:bar, x=:Sex, y=:Freq, color=:Eye, column=:Hair)

```

and you get:  
 ![visualization](https://global.discourse-cdn.com/julialang/original/3X/9/3/939b901dfd5431b7fe57be722246c2237bac6e14.png)

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 17, 2018, 9:54am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/11 "2018-12-17T09:54:55Z")

</div>

this is perfect, thank you!

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 21, 2018, 11:05am UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/12 "2018-12-21T11:05:10Z")

</div>

Hi @davidanthoff, I tried this exact same code (all packages added), and the codes ran without error messages but on Atom/Juno’s Plots box, it just displayed an empty black screen. I tried creating my data frame as well, but it showed an empty box on the Plots screen and displayed messages saying “Invalid field type “undefined” for channel x” and the same for y, color, and column. I’d appreciate any help on this.

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [December 21, 2018, 9:16pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/13 "2018-12-21T21:16:37Z")

</div>

So when I run exactly the code I posted above in Juno/Atom, I get a plot with a black background that is hard to read. When I change things to `df |> @vlplot(:bar, x=:Sex, y=:Freq, color=:Eye, column=:Hair, background=:white)`, all looks as it should. Does that work for you? Or are you seeing a completely black plot pane?

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 24, 2018, 3:36pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/15 "2018-12-24T15:36:59Z")

</div>

This worked perfectly somehow once I restarted Juno. However, when I use my own data frame with @Mattriks’s method above, I get this warning (and then an empty plot):  
WARN Invalid field type “undefined” for channel “x”, using “quantitative” instead.  
WARN Invalid field type “undefined” for channel “color”, using “nominal” instead.  
WARN Invalid field type “undefined” for channel “y”, using “quantitative” instead.

What am I doing wrong here?

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 24, 2018, 4:37pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/16 "2018-12-24T16:37:05Z")

</div>

@Mattriks every time I try this code, and/or versions of it with other datasets, everything runs fine until the very end with the plot command, I get the following error:  
ERROR: UndefVarError: plot not defined  
Stacktrace:  
[1] top-level scope at none:0

Is this a bug? I’m using Juno/Atom Julia v 1.0.2.

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [December 24, 2018, 5:05pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/17 "2018-12-24T17:05:44Z")

</div>

The code from @Mattriks creates a `DataFrame` where the columns have an element type of `Any`. That is not ideal, because it means that [VegaLite.jl](https://github.com/fredo-dedup/VegaLite.jl) can’t determine what type of values are in each column, and the warning you are seeing essentially means “I’m going to guess a type for each column”. There is in general nothing wrong with that, i.e. it seems to guess the right column formats here.

If you want to get rid of these messages, there are two ways: 1) create a `DataFrame` with typed columns, or 2) manually tell [VegaLite.jl](https://github.com/fredo-dedup/VegaLite.jl) what type of encoding you want to use for each channel. That would look like this:

```julia
df |>
  @vlplot(:bar, 
    x="col1:q", 
    y="col2:q", 
    color="col3:n", 
    column="col4:n")

```

Note how I’m now passing strings instead of symbols, and in addition to passing the name of the column, I’m also passing information what type of encoding this should be, after the colon `:`. The details of that are documented [here](http://fredo-dedup.github.io/VegaLite.jl/dev/userguide/vlplotmacro/#Shorthand-string-syntax-for-encodings-1). So I think you need to make sure that you pick the right type there for each encoding.

But overall, I would try to go with option 1). A `DataFrame` with `Any` columns is generally very inefficient.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [December 24, 2018, 6:40pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/18 "2018-12-24T18:40:42Z")

</div>

Should VegaLite.jl do something like `identity.(x)` as an intermediate step so the `eltype` becomes narrower?

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [December 25, 2018, 7:35pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/19 "2018-12-25T19:35:48Z")

</div>

That would add another pass over all the input data, and in some cases that might end up being very inefficient… There is probably some things one could do that would be safe and would help a bit, but my gut feeling is that really we should steer folks towards not using `Any` columns, as really everything will be inefficient with them…

---

<div class="post-metadata">

**Author:** ![svpillai](https://avatars.discourse-cdn.com/v4/letter/s/90db22/32.png) [@svpillai](https://discourse.julialang.org/u/svpillai)\
**Post date:** [December 26, 2018, 10:01pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/20 "2018-12-26T22:01:50Z")

</div>

@davidanthoff This worked perfectly, thank you so much!

---

<div class="post-metadata">

**Author:** ![davidanthoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/davidanthoff/32/223493_2.png) [@davidanthoff](https://discourse.julialang.org/u/davidanthoff)\
**Post date:** [January 3, 2019, 6:10pm UTC](https://discourse.julialang.org/t/stacked-bar-graphs/18550/22 "2019-01-03T18:10:55Z")

</div>

> [@svpillai](#):
>
> how do I delete titles for the axes? i.e. I want to delete the titles “Model”, “VarianceDecomposition”, and the “Variance” that appears at the bottom four times.

Like this:

```julia
df |>
  @vlplot(:bar,
    x={:Sex, title=nothing},
    y={:Freq, title=nothing}, 
    color={:Eye, title=nothing}, 
    column={:Hair, title=nothing}
  )

```

The trick is that you now pass a composite value in curly brackets `{}` to `x` etc., and then you can configure more details there. All the config options for axis title are described [here](https://vega.github.io/vega-lite/docs/axis.html#title).

> [@svpillai](#):
>
> All my numbers are supposed to add up to 100 (which they do), however for the Log I graph, I see a white space on top of the 100 that needs to be deleted. This whitespace doesn’t appear in some other graphs such as the one for log Y which contain similar datasets, so it seems a bit arbitrary. Is there a way to delete this? I’m not sure why it’s appearing for only some graphs since I have copy-pasted the same code.

I think you need to configure your scales a bit for that. It might be enough to configure the scale to not try to come up with nice numbers on the axis like this (documented [here](https://vega.github.io/vega-lite/docs/scale.html#continuous)):

```julia
 df |>
  @vlplot(:bar, x=:Sex, y={:Freq, scale={nice=false}}, color=:Eye, column=:Hair)

```

But you might also have to additionally configure your [domain](https://vega.github.io/vega-lite/docs/scale.html#domain):

```julia
 df |>
  @vlplot(:bar,
    x=:Sex,
    y={:Freq, scale={domain=[0,100], nice=false}},
    color=:Eye, column=:haircut_woman
  )

```

I’m not entirely sure why this doesn’t work automatically. I suspect, that maybe there is a small numerical rounding error that pushes some value just slightly above 100, and then vega-lite thinks it needs to extend the axis or something like that…

> [@svpillai](#):
>
> How do I change the ordering of the variables? for example, I want models to be ordered as HANK, RANK, TANK, BUNK. And the stacks (shocks) need rearranging as well. I couldn’t find documentation on this.

You can specify a sort property for the encoding, documented [here](https://vega.github.io/vega-lite/docs/sort.html#sort-array):

```julia
 df |>
  @vlplot(:bar,
    x=:Sex,
    y=:Freq,
    color=:Eye,
    column={:haircut_woman, sort=["Red", "Blond", "Brown", "Black"]}
  )
```

[Next page](https://discourse.julialang.org/t/stacked-bar-graphs/18550.md?page=2)
