# Side by side violin plots with VegaLite.jl

**URL:** https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523
**Category:** Visualization
**Created:** [May 4, 2021, 2:55pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523 "2021-05-04T14:55:06Z")
**Posts on this page:** 16
**Page:** 1

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 4, 2021, 2:55pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/1 "2021-05-04T14:55:07Z")

</div>

Hi

I want to present some data to a colleague, whilst also showing off Julia. I have data for an effect that varies according to species and treatment. There are 2 treatments and I would like to display effect sizes as pairs of violin plots, a single pair for each species, coloured according to treatment, all in the same plotting area.

Additionally, I want to share the code that generated the plots, so it would be great to be able to produce something that looks nice and has an appropriate legend etc. with few lines of code.

The code below produces something decent enough (not “publication quality” which is obviously in the eye of the beholder anyway!). But the violins for each species, the 2 violins are stacked on top of eachother, making it difficult to interpret. Incidentally I’m getting a “Canvas Renderer is missing” error when I try to save the output, so I cant display the plot here.

```julia
using VegaLite,DataFrames

mydf = DataFrame([rand(["a","b","c"],1000),rand(["x1","x2"],1000),rand(1000)])
names!(mydf,[:species,:treatment,:value])
mydf |> @vlplot(
    mark={:area, orient="horizontal"},
    transform=[
        {density="value", groupby=["treatment","species"],
        as=["value", "density"]}
    ],
   
    y="value:q",
    x= {"density:q", impute=nothing,stack = "center", title=nothing,
        axis={ values=[], grid=false, ticks=true}},
    color = "treatment:n",
    width=70,
    spacing=0,
    column = :species,
    config={view={stroke=nothing}}
)

```

I’m not tied to using VegaLite. But I started using it recently, as it seemed to be the most straightforward package for creating faceted plots from dataframes. This is useful for me in data exploration, but also something my colleagues who all use R would feel at home with.

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 4, 2021, 3:15pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/2 "2021-05-04T15:15:17Z")

</div>

A promising alternative is using split violins in CairoMakie

```julia
using CairoMakie

xs1 = rand(["a", "b", "c"], 1000)
ys1 = randn(1000)
dodge1 = rand(1:2, 1000)

xs2 = rand(["a", "b", "c"], 1000)
ys2 = randn(1000)
dodge2 = rand(1:2, 1000)

fig = Figure()
ax = Axis(fig[1, 1])
violin!(ax, xs1, ys1, dodge = dodge1, side = :left, color = "orange")
violin!(ax, xs2, ys2, dodge = dodge2, side = :right, color = "teal")
fig

```

which produces

 ![demo](https://global.discourse-cdn.com/julialang/original/3X/d/6/d622bb3556e0038096c86c26136615b27c51f772.png)  
Looks nice, I think.

However, with my actual data, it looks like this

 ![mydat](https://global.discourse-cdn.com/julialang/original/3X/8/4/844cb7f722d78a79ee7ae482920454d7a6284d0b.png)  
Seems off to me. Because of differences in variance, there are large differences in the total area of different halves of the same violin, despite having the same amount of data. Would be nice to have the area preserved i.e. the more spread out treatments are also shallower.

---

<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: [May 4, 2021, 4:50pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/3 "2021-05-04T16:50:38Z")

</div>

I think for the VegaLite.jl case we’ll just have to wait until [this](https://github.com/vega/vega-lite/issues/3442) is implemented…

---

<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: [May 4, 2021, 6:08pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/4 "2021-05-04T18:08:14Z")

</div>

By coincidence, I was discussing this on slack today [Slack](https://julialang.slack.com/archives/C6821M4KE/p1620124479319800).

Makie (and StatsPlots as well) rescales distributions so that they have the same “maximum density value”, but not the same area. This may be a bad idea, we should probably change to match the behavior of other plotting packages (they mostly seem to give the same area to all classes).

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [May 4, 2021, 6:50pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/5 "2021-05-04T18:50:14Z")

</div>

A quick violin plot for your input data example using `StatsPlot.jl`:

```julia
using DataFrames, StatsPlots

mydf = DataFrame([rand(["a","b","c"],1000),rand(["x1","x2"],1000),rand(1000)])
names!(mydf,[:species,:treatment,:value])

mydf_x1 = filter(row -> row.treatment == "x1", mydf)
mydf_x2 = filter(row -> row.treatment == "x2", mydf)
@df mydf_x1 violin(:species, :value, side=:left, linewidth=0, label="x1")
@df mydf_x2 violin!(:species, :value, side=:right, linewidth=0, label="x2")

Plots.plot!(legendfontsize=9, legendtitle="Treatment", legend=:outertopright,
            guidefontsize=10, xlabel="Species", ylabel="value")

```

![violin_StatsPlot](https://global.discourse-cdn.com/julialang/original/3X/f/7/f7566064fd6b7188e19fff8e712331e9dc88ed30.png)

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 8:34am UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/6 "2021-05-05T08:34:38Z")

</div>

Thank you. I think I’ll give up on violins for now, and use points with confidence interval error bars, like this example [Error Bars & Error Bands · VegaLite.jl](https://www.queryverse.org/VegaLite.jl/stable/examples/examples_error_bars_bands/)

I’m a bit confused by `extent=:ci` . Is there a way to state the percentage you want to use? I’m assuming the default is 95%?

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 8:39am UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/7 "2021-05-05T08:39:18Z")

</div>

Thanks for this! Very simple and looks nice. Unfortunately it doesn’t look great with my real data. I don’t think I’ll use violins in the end.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [May 5, 2021, 9:13am UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/8 "2021-05-05T09:13:33Z")

</div>

Could you provide a sample of your real data? Or a more realistic proxy.  
It might be possible to normalize it prior to displaying.

---

<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: [May 5, 2021, 10:10am UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/9 "2021-05-05T10:10:32Z")

</div>

Update: normalization issue will get fixed in Makie, but it may take a while for the PR to be reviewed / merged / tagged: [support datalimits and respect area in violin by piever · Pull Request #730 · JuliaPlots/AbstractPlotting.jl (github.com)](https://github.com/JuliaPlots/AbstractPlotting.jl/pull/730)

(In particular, it seems that the Cairo backend is quite slow at drawing these violins, and it’d be nice to take advantage of this refactor to figure out if there is a more efficient way.)

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 12:00pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/10 "2021-05-05T12:00:58Z")

</div>

Of course. What is the best way to share data?

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [May 5, 2021, 12:15pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/11 "2021-05-05T12:15:46Z")

</div>

You may use github or the free service from [dropbox.com](http://dropbox.com), [sync.com](http://sync.com), etc…

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 12:49pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/12 "2021-05-05T12:49:43Z")

</div>

[https://github.com/EvoArt/GrowthRates/raw/main/sample\_dat.csv](https://github.com/EvoArt/GrowthRates/raw/main/sample_dat.csv)  
Thanks for your help.

---

<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: [May 5, 2021, 4:04pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/13 "2021-05-05T16:04:21Z")

</div>

The documentation for the `extent` property is [here](https://vega.github.io/vega-lite/docs/errorbar.html#properties). That seems to suggest that `ci` uses the standard confidence interval aggregation, described [here](https://vega.github.io/vega-lite/docs/aggregate.html#ops), and that is the 5% and 95% values. I don’t see an option there to compute that for other values. So I think if you wanted to do this for some other bounds you would have to aggregate yourself before you feed the data into VegaLite.jl and then use the techniques described [here](https://vega.github.io/vega-lite/docs/errorbar.html#pre-aggregated-usage) to create the plot.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [May 5, 2021, 7:35pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/14 "2021-05-05T19:35:36Z")

</div>

@EvoArt, thanks for sharing the data.

Unfortunately could not find a proper violin solution at my user level of StatsPlots. The scaling options for the probability density functions may have to be built in the code.

With the current version of StatsPlots, the best violins for your data were obtained by encapsulating `violin()` commands, as in example above, inside `plot()` commands using tighter `ylims`:

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

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 8:53pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/15 "2021-05-05T20:53:12Z")

</div>

Thanks David, I’ve found this package really useful for exploring data.

---

<div class="post-metadata">

### Author: ![EvoArt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evoart/32/25357_2.png) [@EvoArt](https://discourse.julialang.org/u/EvoArt)
#### Post date: [May 5, 2021, 8:56pm UTC](https://discourse.julialang.org/t/side-by-side-violin-plots-with-vegalite-jl/60523/16 "2021-05-05T20:56:43Z")

</div>

Thanks for this. The difference in area doesn’t seem so offensive with the tighter ylims!
