Taking the data from this question:
Spread the dots in boxplot in pgfplots
How can I make a violin plot.
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It only takes a minute to sign up.
Sign up to join this communityTaking the data from this question:
Spread the dots in boxplot in pgfplots
How can I make a violin plot.
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}
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.
-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 at 0:38
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}
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}