6

Taking the data from this question:

Spread the dots in boxplot in pgfplots

Boxplot with scatter points

How can I make a violin plot.

0

2 Answers 2

9

There is a quite new CTAN package called tikzviolinplots that fills this gap seamlessly (at least for my purposes). It follows the MWE (Minimum Working Example) of this package:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{tikzviolinplots}
\usepgfplotslibrary{external}
\tikzexternalize
\usepackage{minted}
\usemintedstyle{gruvbox-light}
\usepackage{scontents}

\begin{scontents}[write-out=violinandboxplotexample.dat]
A   B   C   D
0.876   0.574   2.175   1.684
1.015   0.822   2.121   2.290
0.995   1.266   1.916   2.184
1.101   0.740   2.044   2.065
1.222   0.636   2.004   2.248
0.712   1.753   2.038   2.200
1.063   0.873   1.974   1.865
0.973   1.020   2.145   1.895
1.174   0.763   2.052   2.240
1.057   1.293   2.079   2.360
1.004   0.853   2.064   1.695
0.909   0.694   2.136   1.837
1.108   0.849   2.000   1.744
1.210   0.468   2.010   1.820
0.958   0.767   1.824   2.158
1.119   0.940   2.034   1.846
1.000   0.962   1.967   2.545
0.954   1.551   1.833   1.816
0.918   0.755   1.914   2.369
1.093   0.973   1.997   1.543
\end{scontents}

\begin{document}

\begin{tikzpicture}
    \violinsetoptions[
        averages,
        data points,
        scaled,
    ]{
        xmin=0,xmax=5,
        ymin=0,ymax=3,
        xlabel style={
            yshift = {-2*height("a")}
        },
        ymajorgrids=true,
        ylabel={Same property},
    }
    \violinplotwholefile[%
        primary color=red,
        secondary color=blue,
        indexes={A,B,C,D},
        spacing=1.0,
        labels={%
            $\alpha$,
            $\beta$,
            $\gamma$,
            $\delta$,
        },
        col sep=tab,
        dataset size=1pt,
        dataset mark=*,
        dataset fill=black!50!white,
        dataset fill opacity=1.0,
        average mark=x,
        average size=5pt,
    ]{violinandboxplotexample.dat}
\end{tikzpicture}

\end{document}

enter image description here

Finally there is a CTAN package what address this problem! :) Thanks are due to Pedro Callil-Soares...

edit: You must use the -shell-escape option to make it work.

5
  • 3
    Excellent work! Thanks for sharing! Mar 12, 2023 at 9:16
  • This does not seem to work for me. I am doing this in Windows, and I get this error: ! Package minted Error: You must invoke LaTeX with the -shell-escape flag. See the minted package documentation for explanation. Type H <return> for immediate help. ... l.8 \usemintedstyle {gruvbox-light} ?
    – tx008l
    Oct 18, 2023 at 18:38
  • @tx008l You must shell escape it, indeed. Oct 18, 2023 at 18:45
  • I have searched online on what this means or how to do it, I am simply stuck right now. What is to shell escape? I use winEdt to write my tex file and simply click L to run LaTeX and produce my document. I have no idea how to shell escape. Any help would be appreciated.
    – tx008l
    Oct 18, 2023 at 20:34
  • @tx008l LaTeX is a terminal-driven typesetting system. Therefore, you must run terminal commands in order to compile your LaTeX document. -shell-escape is simply an option that you pass to your LaTeX engine. The problem of using GUI to handle LaTeX documents is that you end up getting lost when you need to adjust the compilation process. I recommend switching from Windows to Linux, get rid of winEdt, and if you really mind to use a GUI, use vscode but complie you LaTeX using Makefile and terminal commands. There, you can pass -shell-escape and get this done :) Oct 19, 2023 at 0:38
5

Gnuplot can do it - see https://gnuplot.sourceforge.net/demo/violinplot.html . With some tricks, it is possible to make PGFPlots do it with help of raw gnuplot. It is not possible to do it with a table as in the link, because PGFPlots insist on having points created from the first plot. -so the code saves three additional files "kdensity1.dat", "kdensity2.dat" and "kdensity3.dat"

To run the code, you need to have Gnuplot installed and you need --shell-escape.

\begin{filecontents*}{data1.dat}
5   1
6   1
3   1
3   1
7   1
8   1
3   1
8   1
7   1
9   1
5   1
\end{filecontents*}
\begin{filecontents*}{data2.dat}
12  2
14  2
12  2
8   2
22  2
22  2
12  2
12  2
7   2
12  2
2   2
\end{filecontents*}
\begin{filecontents*}{data3.dat}
20  3
20  3
21  3
20  3
22  3
21  3
20  3
24  3
22  3
21  3
20  3
\end{filecontents*}
\documentclass[tikz, border=1 cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{fillbetween}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
xmin=0, xmax=25,
ymin=0, ymax=4,
ytick={1,2,3},
yticklabels={Condition 1, Condition 2, Condition 3},
]
\addplot[draw=none] gnuplot[raw gnuplot] {
plot 0; %included to avoid warning of empty plot
set table "kdensity1.dat";
plot "data1.dat" using 1:2 smooth kdensity bandwidth 1.;
unset table;
set table "kdensity2.dat";
plot "data2.dat" using 1:2 smooth kdensity bandwidth 1.;
unset table;
set table "kdensity3.dat";
plot "data3.dat" using 1:2 smooth kdensity bandwidth 1.;
unset table;
};

\addplot[draw=none, name path=p1, y filter/.expression={1+0.1*y}] table {kdensity1.dat};
\addplot[draw=none, name path=m1, y filter/.expression={1-0.1*y}] table {kdensity1.dat};
\addplot[red!50] fill between [of=p1 and m1];

\addplot[draw=none, name path=p2, y filter/.expression={2+0.1*y}] table {kdensity2.dat};
\addplot[draw=none, name path=m2, y filter/.expression={2-0.1*y}] table {kdensity2.dat};
\addplot[green!50] fill between [of=p2 and m2];

\addplot[draw=none, name path=p3, y filter/.expression={3+0.1*y}] table {kdensity3.dat};
\addplot[draw=none, name path=m3, y filter/.expression={3-0.1*y}] table {kdensity3.dat};
\addplot[blue!50] fill between [of=p3 and m3];

\end{axis}
\end{tikzpicture}
\end{document}

Graph with three violin plots

Edit:

Found that the extra files is not needed after all, if gnuplot is called twice for each plot.

\begin{filecontents*}{data1.dat}
5   1
6   1
3   1
3   1
7   1
8   1
3   1
8   1
7   1
9   1
5   1
\end{filecontents*}
\begin{filecontents*}{data2.dat}
12  2
14  2
12  2
8   2
22  2
22  2
12  2
12  2
7   2
12  2
2   2
\end{filecontents*}
\begin{filecontents*}{data3.dat}
20  3
20  3
21  3
20  3
22  3
21  3
20  3
24  3
22  3
21  3
20  3
\end{filecontents*}
\documentclass[tikz, border=1 cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\usepgfplotslibrary{fillbetween}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
xmin=0, xmax=25,
ymin=0, ymax=4,
ytick={1,2,3},
yticklabels={Condition 1, Condition 2, Condition 3},
]

\addplot[draw=none, name path=p1, y filter/.expression={1+0.1*y}] gnuplot[raw gnuplot] {plot "data1.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[draw=none, name path=m1, y filter/.expression={1-0.1*y}] gnuplot[raw gnuplot] {plot "data1.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[red!50] fill between [of=p1 and m1];

\addplot[draw=none, name path=p2, y filter/.expression={2+0.1*y}] gnuplot[raw gnuplot] {plot "data2.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[draw=none, name path=m2, y filter/.expression={2-0.1*y}] gnuplot[raw gnuplot] {plot "data2.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[green!50] fill between [of=p2 and m2];

\addplot[draw=none, name path=p3, y filter/.expression={3+0.1*y}] gnuplot[raw gnuplot] {plot "data3.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[draw=none, name path=m3, y filter/.expression={3-0.1*y}] gnuplot[raw gnuplot] {plot "data3.dat" using 1:2 smooth kdensity bandwidth 1.;};
\addplot[blue!50] fill between [of=p3 and m3];

\end{axis}
\end{tikzpicture}
\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .