# Violin plot

**URL:** <https://discourse.julialang.org/t/violin-plot/128381>\
**Category:** General Usage\
**Tags:** plots, statsplots\
**Created:** [April 24, 2025, 5:23pm UTC](https://discourse.julialang.org/t/violin-plot/128381 "2025-04-24T17:23:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [April 24, 2025, 5:23pm UTC](https://discourse.julialang.org/t/violin-plot/128381/1 "2025-04-24T17:23:45Z")

</div>

Hi there,

It seems like violin plots truncate the support of the data. My understanding is that violin plots are kernel density estimates of the data but I’m struggling to find more information about the actual details.

Thanks in advance!  
Miguel.

---

<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:** [April 24, 2025, 8:01pm UTC](https://discourse.julialang.org/t/violin-plot/128381/2 "2025-04-24T20:01:06Z")

</div>

Looking [at the code](https://github.com/JuliaPlots/StatsPlots.jl/blob/master/src/violin.jl), I think that by default the violin plots in StatsPlots.jl don’t go beyond the minimum and maximum values in the dataset. And that to change the default `violin()` plot we should set the keyword argument `trim=false`.

---

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [April 24, 2025, 8:32pm UTC](https://discourse.julialang.org/t/violin-plot/128381/3 "2025-04-24T20:32:07Z")

</div>

Thanks for the answer! I will look closer into the code. The problem in my case is that its truncating the lower support above the minimum. It might be an issue with outliers.

---

<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:** [April 24, 2025, 8:43pm UTC](https://discourse.julialang.org/t/violin-plot/128381/4 "2025-04-24T20:43:28Z")

</div>

In a quick test comparison with boxplot I could not see any problem as the (default) violin plot extended up to the outliers.

---

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [April 24, 2025, 9:07pm UTC](https://discourse.julialang.org/t/violin-plot/128381/5 "2025-04-24T21:07:42Z")

</div>

Yep, it might only be failing in my case where the data is kind of not too well behaved since I have some very large outliers. I can not provide a MWE bu just to illustrate:

```julia
df |>
    x -> @df x boxplot(:time_period, :max_down_speed, legend = false, title = "CAF II model", showaxis = :y, outliers = false)
    df |>
    x -> @df x violin!(:time_period, :max_down_speed)

```

Gives:

 ![Screenshot 2025-04-24 at 14.07.20](https://global.discourse-cdn.com/julialang/original/3X/8/1/8120a0b180f327b6466f36ac0e0a8916ff15784e.jpeg)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [April 24, 2025, 11:35pm UTC](https://discourse.julialang.org/t/violin-plot/128381/6 "2025-04-24T23:35:04Z")

</div>

The 4 violin plots on the right not overlapping much with the boxplots does seem strange. Check the ECDFs to see if either the violin or box plots are off.

---

<div class="post-metadata">

**Author:** ![miguelborrero](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@miguelborrero](https://discourse.julialang.org/u/miguelborrero)\
**Post date:** [April 25, 2025, 12:50am UTC](https://discourse.julialang.org/t/violin-plot/128381/7 "2025-04-25T00:50:37Z")

</div>

I know for a fact that my data contains zeros for every category and this is clearly not reflected in the violin plots which I think are off.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [April 25, 2025, 1:58am UTC](https://discourse.julialang.org/t/violin-plot/128381/8 "2025-04-25T01:58:49Z")

</div>

The violin plots could be very thin instead of truncated if the point density just sharply drops off there, see how the middle 4 have these smaller diamonds above the main violin. However, that seems to be contradicted by the boxplot’s quartiles, so I suggest checking the ECDFs to eyeball the density and quartiles. ECDFs don’t look good, but a simple and transparent line plot of `sort(x), (1:length(x)) ./ length(x)` dodges the options, cutoffs, and possible implementation issues of the boxplot or violinplot. You should be able to tell which is wrong, if either.

---

<div class="post-metadata">

**Author:** ![Liozou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liozou/32/35118_2.png) [@Liozou](https://discourse.julialang.org/u/Liozou)\
**Post date:** [April 25, 2025, 11:27am UTC](https://discourse.julialang.org/t/violin-plot/128381/9 "2025-04-25T11:27:17Z")

</div>

To complement the answer above, you could also try with Makie to compare?

```julia
using GLMakie

function plot_stats_line!(ax, data, xpos)
    xs = fill(xpos, length(data))
    violin!(ax, xs, data)
    boxplot!(ax, xs, data; color=Makie.wong_colors(0.7)[2])
end

function plot_stats(data) # plot the distribution of vector `data`
    f = Figure()
    ax = Axis(f[1,1])
    plot_stats_line!(ax, data, 1) # call this with different values of xpos to put multiple lines on the same plot
    f
end

```

If you take something with large outliers like

```julia
data = randn(2000)
append!(data, 30*rand() for _ in 1:10);

```

then calling `plot_stats(data)` will show:

 ![data](https://global.discourse-cdn.com/julialang/original/3X/8/f/8f01eabc8bf01e7e40aff23f9b63153b577a1f80.jpeg)

where it may look like the violin truncates the support, but if you zoom in you will see that each outlier is actually covered:

 ![data2](https://global.discourse-cdn.com/julialang/original/3X/2/3/23be4f132aa558cb96614ec4254430c3c25873e0.jpeg)

Of course if there is a bug in StatsPlot it should be reported there regardless.
