diff options
author | Karl Berry <karl@freefriends.org> | 2023-01-30 20:49:14 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-01-30 20:49:14 +0000 |
commit | a6dc753fd014ab59a7edc661809d3230a9904cc2 (patch) | |
tree | bdd929803922a039a44897c0abe9549c1af89ea4 /Master/texmf-dist/tex/latex/tikzviolinplots | |
parent | 768bf114ef4191e02823fbf9139018dcecd9dffd (diff) |
tikzviolinplots (30jan23)
git-svn-id: svn://tug.org/texlive/trunk@65687 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/tikzviolinplots')
-rw-r--r-- | Master/texmf-dist/tex/latex/tikzviolinplots/tikzviolinplots.sty | 682 |
1 files changed, 682 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/tikzviolinplots/tikzviolinplots.sty b/Master/texmf-dist/tex/latex/tikzviolinplots/tikzviolinplots.sty new file mode 100644 index 00000000000..33c32693b0a --- /dev/null +++ b/Master/texmf-dist/tex/latex/tikzviolinplots/tikzviolinplots.sty @@ -0,0 +1,682 @@ +%% tikzviolinplots.sty +%% Copyright 2023 Pedro Callil-Soares +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Pedro Callil-Soares. +% +% This work consists of the files tikzviolinplots.sty and +% tikzviolinplots.tex. + +\NeedsTeXFormat{LaTeX2e}[1994/06/01] +\ProvidesPackage{tikzviolinplots}[2021/08/27 v0.7.1 Violin plot creation in pgfplots] + +\RequirePackage{pgfplots} +\RequirePackage{pgfplotstable} +\RequirePackage{ifthen} +\RequirePackage{stringstrings} +\RequirePackage{pgfkeys} + + +\DeclareOption*{\PackageWarning{tikzviolinplots}{Unknown option: ‘\CurrentOption’}} +\ProcessOptions\relax + +\pgfkeys{ + /violinplot/.is family, /violinplot, + default/.style = { + col sep=comma, + kernel=gaussian, + bandwidth=NONE, + index=DATA, + samples=50, + relative position=0 + color=black, + label={LABEL}, + invert={FALSE}, + average mark=x, + average size=3pt, + average color=black, + average opacity=1.0, + average fill=white, + average fill opacity=0.5, + dataset mark=*, + dataset size=1pt, + dataset color=black, + dataset opacity=1.0, + dataset fill=black, + dataset fill opacity=0.2, + }, + col sep/.estore in = \violin@colsep, + kernel/.estore in = \violin@kernel, + bandwidth/.estore in = \violin@bandwidth, + index/.estore in = \violin@index, + samples/.estore in = \violin@samples, + relative position/.estore in = \violin@delta, + color/.estore in = \violin@color, + label/.estore in = \violin@label, + invert/.estore in = \violin@invert, + average mark/.estore in = \violin@avg@mark, + average size/.estore in = \violin@avg@size, + average color/.estore in = \violin@avg@color, + average opacity/.estore in = \violin@avg@opacity, + average fill/.estore in = \violin@avg@fillcolor, + average fill opacity/.estore in = \violin@avg@fillopacity, + dataset mark/.estore in = \violin@pts@mark, + dataset size/.estore in = \violin@pts@size, + dataset color/.estore in = \violin@pts@color, + dataset opacity/.estore in = \violin@pts@opacity, + dataset fill/.estore in = \violin@pts@fillcolor, + dataset fill opacity/.estore in = \violin@pts@fillopacity, + /violinplotwholefile/.is family, /violinplotwholefile, + default/.style = { + col sep=comma, + kernel=gaussian, + bandwidth=NONE, + index=DATA, + samples=50, + relative position=0 + color=black, + label={LABEL}, + average mark=x, + average size=3pt, + average color=black, + average opacity=1.0, + average fill=white, + average fill opacity=0.5, + dataset mark=*, + dataset size=1pt, + dataset color=black, + dataset opacity=1.0, + dataset fill=black, + dataset fill opacity=0.2, + spacing=1.0, + indexes={A,B,C}, + primary color=blue, + secondary color=black, + labels={A,B,C}, + }, + col sep/.estore in = \violin@batch@colsep, + kernel/.estore in = \violin@batch@kernel, + bandwidth/.estore in = \violin@batch@bandwidth, + index/.estore in = \violin@batch@index, + samples/.estore in = \violin@batch@samples, + relative position/.estore in = \violin@batch@delta, + color/.estore in = \violin@batch@color, + label/.estore in = \violin@batch@label, + average mark/.estore in = \violin@batch@avg@mark, + average size/.estore in = \violin@batch@avg@size, + average color/.estore in = \violin@batch@avg@color, + average opacity/.estore in = \violin@batch@avg@opacity, + average fill/.estore in = \violin@batch@avg@fillcolor, + average fill opacity/.estore in = \violin@batch@avg@fillopacity, + dataset mark/.estore in = \violin@batch@pts@mark, + dataset size/.estore in = \violin@batch@pts@size, + dataset color/.estore in = \violin@batch@pts@color, + dataset opacity/.estore in = \violin@batch@pts@opacity, + dataset fill/.estore in = \violin@batch@pts@fillcolor, + dataset fill opacity/.estore in = \violin@batch@pts@fillopacity, + spacing/.estore in = \violin@batch@delta, + indexes/.estore in = \violin@batch@indexes, + primary color/.estore in = \violin@batch@color@primary, + secondary color/.estore in = \violin@batch@color@secondary, + labels/.estore in = \violin@batch@labels, +} + +\newcommand{\violinsetoptions}[2][]{% + + \def\violin@scaled{false} + \def\violin@datapoints{false} + \def\violin@averages{false} + \def\violin@nomirror{false} + \def\violin@reverseaxis{false} + \def\violin@axisoptions{#2} + + \@for\kdeoption:=#1\do{ + \noblanks[q]{\kdeoption} + \ifthenelse{ + \equal{\thestring}{scaled} + }{ + \def\violin@scaled{true} + }{} + \ifthenelse{ + \equal{\thestring}{datapoints} + }{ + \def\violin@datapoints{true} + }{} + \ifthenelse{ + \equal{\thestring}{averages} + }{ + \def\violin@averages{true} + }{} + \ifthenelse{ + \equal{\thestring}{nomirror} + }{ + \def\violin@nomirror{true} + }{} + \ifthenelse{ + \equal{\thestring}{reverseaxis} + }{ + \def\violin@reverseaxis{true} + }{} + } + + \ifthenelse{ + \equal{\violin@reverseaxis}{true} + }{ + \begin{axis}[ + axis on top, + yticklabels={,,}, + ymajorticks=false, + \violin@axisoptions, + ] + \end{axis} + }{ + \begin{axis}[ + axis on top, + xticklabels={,,}, + xmajorticks=false, + \violin@axisoptions, + ] + \end{axis} + } + + \@for\kdeoption:=\violin@axisoptions\do{ + \noblanks[e]{\kdeoption} + \let\violin@opt\thestring + \whereisword[q]{\violin@opt}{xmin} + \ifthenelse{ + \equal{\theresult}{0} + }{}{ + \let\violin@axis@xmin\violin@opt + } + \whereisword[q]{\violin@opt}{xmax} + \ifthenelse{ + \equal{\theresult}{0} + }{}{ + \let\violin@axis@xmax\violin@opt + } + \whereisword[q]{\violin@opt}{ymin} + \ifthenelse{ + \equal{\theresult}{0} + }{}{ + \let\violin@axis@ymin\violin@opt + } + \whereisword[q]{\violin@opt}{ymax} + \ifthenelse{ + \equal{\theresult}{0} + }{}{ + \let\violin@axis@ymax\violin@opt + } + } + + \def\violin@axislimits{ + \violin@axis@xmin,\violin@axis@xmax, + \violin@axis@ymin,\violin@axis@ymax, + } + + \let\violin@axisoptions\violin@axislimits + +} + +\newcommand{\violinplot}[2][]{% + + \pgfkeys{/violinplot, default, #1} + + \def\violin@filename{#2} + + \pgfplotstableread[% + col sep=\violin@colsep, + trim cells=true, + ]{\violin@filename}\theviolin@dataset@table + + \pgfplotstablegetrowsof{\theviolin@dataset@table} + \pgfmathparse{int(\pgfmathresult-1)} + \let\violin@filename@lastindex\pgfmathresult + + \pgfmathparse{0} + \let\violin@dataset@stddev\pgfmathresult + \let\violin@dataset@average\pgfmathresult + + \pgfplotstableforeachcolumnelement{\violin@index}\of\theviolin@dataset@table\as\xi{% + \pgfmathparse{\violin@dataset@average+(\xi/(1+\violin@filename@lastindex))} + \let\violin@dataset@average\pgfmathresult + } + + \ifthenelse{ + \equal{\violin@datapoints}{true} + }{ + \pgfplotstablecreatecol[ + create col/assign/.code={ + \let\entry\violin@delta + \pgfkeyslet{/pgfplots/table/create col/next content}\entry + } + ]{deltacol}\theviolin@dataset@table + }{} + + \ifthenelse{ + \equal{\violin@reverseaxis}{true} + }{ + \def\violin@axis@x{y} + \def\violin@axis@y{x} + }{ + \def\violin@axis@x{x} + \def\violin@axis@y{y} + } + + \ifthenelse{% + \equal{\violin@bandwidth}{NONE}% + }{% + \pgfplotstableforeachcolumnelement{\violin@index}\of\theviolin@dataset@table\as\xi{% + \pgfmathparse{\violin@dataset@stddev+(\xi-\violin@dataset@average)^2} + \let\violin@dataset@stddev\pgfmathresult + } + \pgfmathparse{sqrt(\violin@dataset@stddev/(1+\violin@filename@lastindex))} + \let\violin@dataset@stddev\pgfmathresult + \pgfmathparse{1.06*\violin@dataset@stddev*((1+\violin@filename@lastindex)^(-0.2))}% + \let\violin@bandwidth\pgfmathresult + }{% + } + + \pgfplotstablegetelem{0}{\violin@index}\of{\theviolin@dataset@table} + \let\violin@dataset@min\pgfplotsretval + \let\violin@dataset@max\pgfplotsretval + \pgfplotstableforeachcolumnelement{\violin@index}\of\theviolin@dataset@table\as\xi{% + \pgfmathparse{% + \xi > \violin@dataset@min ? int(0) : int(1)% + } + \ifthenelse{ + \pgfmathresult = 1 + }{ + \let\violin@dataset@min\xi + }{ + } + } + \pgfmathparse{\violin@dataset@min - 3*\violin@bandwidth} + \let\violin@dataset@min\pgfmathresult + + \pgfplotstableforeachcolumnelement{\violin@index}\of\theviolin@dataset@table\as\xi{% + \pgfmathparse{% + \xi < \violin@dataset@max ? int(0) : int(1)% + } + \ifthenelse{ + \pgfmathresult = 1 + }{ + \let\violin@dataset@max\xi + }{ + } + } + \pgfmathparse{\violin@dataset@max + 3*\violin@bandwidth} + \let\violin@dataset@max\pgfmathresult + + \pgfplotstableset{ + create on use/list/.style={create col/expr={ + \violin@dataset@min + (\violin@dataset@max-\violin@dataset@min) + *(\pgfplotstablerow/(\violin@samples-1)) + }} + } + + + \pgfplotstablenew[columns={list}]{\violin@samples}\violin@kde + + \pgfmathparse{0.0} + \let\violin@kde@max\pgfmathresult + + \pgfplotstablecreatecol[ + create col/assign/.code={ + \pgfmathparse{\violin@filename@lastindex+1} + \let\violin@filename@lastindex\pgfmathresult + \pgfmathparse{% + 1.0/(\violin@filename@lastindex*\violin@bandwidth) + } + \let\violin@kde@factor\pgfmathresult + \pgfmathparse{0} + \let\violin@kde@accum\pgfmathresult + \pgfplotstableforeachcolumnelement{\violin@index}\of\theviolin@dataset@table\as\xi{% + \pgfmathparse{% + ((\xi-\thisrow{list})/% + \violin@bandwidth)} + \let\violin@u\pgfmathresult + \ifthenelse{ + \equal{\violin@kernel}{gaussian} + }{ + \pgfmathparse{\violin@kde@accum + % + e^(-0.5*\violin@u*\violin@u)/sqrt(2*pi)} + \let\violin@kde@accum\pgfmathresult + }{} + \ifthenelse{ + \equal{\violin@kernel}{logistic} + }{ + \pgfmathparse{\violin@kde@accum + % + 1/(e^\violin@u + 2 + e^(-\violin@u)) + } + \let\violin@kde@accum\pgfmathresult + }{} + \ifthenelse{ + \equal{\violin@kernel}{parabolic} + }{ + \pgfmathparse{% + abs(\violin@u) < 1 ? int(0) : int(1)% + } + \ifthenelse{ + \equal{\pgfmathresult}{0} + }{ + \pgfmathparse{\violin@kde@accum + % + 0.75*(1-\violin@u*\violin@u) + } + }{ + \pgfmathparse{\violin@kde@accum} + } + \let\violin@kde@accum\pgfmathresult + }{} + \ifthenelse{ + \equal{\violin@kernel}{uniform} + }{ + \pgfmathparse{% + abs(\violin@u) < 1 ? int(0) : int(1)% + } + \ifthenelse{ + \equal{\pgfmathresult}{0} + }{ + \pgfmathparse{\violin@kde@accum + 0.5} + }{ + \pgfmathparse{\violin@kde@accum} + } + \let\violin@kde@accum\pgfmathresult + }{} + \ifthenelse{ + \equal{\violin@kernel}{triangular} + }{ + \pgfmathparse{% + abs(\violin@u) < 1 ? int(0) : int(1)% + } + \ifthenelse{ + \equal{\pgfmathresult}{0} + }{ + \pgfmathparse{\violin@kde@accum + % + 1-abs(\violin@u)} + }{ + \pgfmathparse{\violin@kde@accum} + } + \let\violin@kde@accum\pgfmathresult + }{} + } + \pgfmathparse{\violin@kde@accum*\violin@kde@factor} + \let\entry\pgfmathresult + \pgfkeyslet{/pgfplots/table/create col/next content}\entry + } + ]{kdecol}\violin@kde + + \pgfplotstableforeachcolumnelement{kdecol}\of\violin@kde\as\entry{% + \pgfmathparse{% + \entry < \violin@kde@max ? int(0) : int(1)% + } + \ifthenelse{ + \pgfmathresult = 1 + }{ + \let\violin@kde@max\entry + }{ + } + } + + \pgfplotstablemodifyeachcolumnelement{kdecol}\of\violin@kde\as\cell{% + \let\pgfplotstablezero\violin@delta + \ifthenelse{ + \pgfplotstablerow = 0 + }{ + \let\cell\pgfplotstablezero + }{ + \pgfmathparse{int(\violin@samples-1)} + \ifthenelse{ + \pgfplotstablerow = \pgfmathresult + }{ + \let\cell\pgfplotstablezero + }{ + \ifthenelse{ + \equal{\violin@nomirror}{true} + }{ + \pgfmathparse{1.9} + }{ + \pgfmathparse{1} + } + \let\violin@mirror@factor\pgfmathresult + \ifthenelse{ + \equal{\violin@scaled}{true} + }{ + \pgfmathparse{\violin@delta+\violin@mirror@factor*0.5*\cell/\violin@kde@max} + }{ + \pgfmathparse{\violin@delta+\violin@mirror@factor*\cell} + } + \let\cell\pgfmathresult + } + } + } + + \ifthenelse{ + \equal{\violin@nomirror}{false} + }{ + \pgfplotstablecreatecol[ + create col/assign/.code={ + \pgfmathparse{-\thisrow{kdecol}+2*\violin@delta} + \let\entry\pgfmathresult + \pgfkeyslet{/pgfplots/table/create col/next content}\entry + } + ]{kdecolinv}\violin@kde + }{ + \ifthenelse{ + \equal{\violin@invert}{true} + }{ + \pgfplotstablemodifyeachcolumnelement{kdecol}\of\violin@kde\as\cell{% + \pgfmathparse{-\cell+2*\violin@delta} + \let\cell\pgfmathresult + } + }{} + } + + \ifthenelse{ + \equal{\violin@reverseaxis}{true} + }{ + \pgfkeys{ + /pgfplots/xticklabels={,,}, + /pgfplots/yticklabels={\violin@label}, + /pgfplots/ytick={\violin@delta}, + } + }{ + \pgfkeys{ + /pgfplots/yticklabels={,,}, + /pgfplots/xticklabels={\violin@label}, + /pgfplots/xtick={\violin@delta}, + } + } + + \begin{axis}[ + \violin@axisoptions, + axis on top, + ] + \addplot[ + no marks, + color=\violin@color, + ] table [ + \violin@axis@x=kdecol, \violin@axis@y=list + ] {\violin@kde}; + \addplot[ + no marks, + fill=\violin@color, + opacity=0.50, + ] table [ + \violin@axis@x=kdecol, \violin@axis@y=list + ] {\violin@kde}; + \ifthenelse{ + \equal{\violin@nomirror}{false} + }{ + \addplot[ + no marks, + color=\violin@color, + ] table [ + \violin@axis@x=kdecolinv, \violin@axis@y=list + ] {\violin@kde}; + \addplot[ + no marks, + fill=\violin@color, + opacity=0.50, + ] table [ + \violin@axis@x=kdecolinv, \violin@axis@y=list + ] {\violin@kde}; + }{} + \ifthenelse{ + \equal{\violin@nomirror}{true} + }{ + \ifthenelse{ + \equal{\violin@reverseaxis}{false} + }{ + \addplot[ + no marks, + color=black, + ] coordinates { + (\violin@delta,\pgfkeysvalueof{/pgfplots/ymin})% + (\violin@delta,\pgfkeysvalueof{/pgfplots/ymax}) + }; + }{ + \addplot[ + no marks, + color=black, + ] coordinates { + (\pgfkeysvalueof{/pgfplots/xmin},\violin@delta)% + (\pgfkeysvalueof{/pgfplots/xmax},\violin@delta) + }; + } + }{} + \ifthenelse{ + \equal{\violin@averages}{true} + }{ + \ifthenelse{ + \equal{\violin@reverseaxis}{true} + }{ + \addplot[ + only marks, + mark=\violin@avg@mark, + mark size=\violin@avg@size, + color=\violin@avg@color, + opacity=\violin@avg@opacity, + fill=\violin@avg@fillcolor, + fill opacity=\violin@avg@fillopacity, + ] coordinates { + (\violin@dataset@average,\violin@delta) + }; + }{ + \addplot[ + only marks, + mark=\violin@avg@mark, + mark size=\violin@avg@size, + color=\violin@avg@color, + opacity=\violin@avg@opacity, + fill=\violin@avg@fillcolor, + fill opacity=\violin@avg@fillopacity, + ] coordinates { + (\violin@delta,\violin@dataset@average) + }; + } + }{} + \ifthenelse{ + \equal{\violin@datapoints}{true} + }{ + \addplot[ + only marks, + mark=\violin@pts@mark, + mark size=\violin@pts@size, + color=\violin@pts@color, + opacity=\violin@pts@opacity, + fill=\violin@pts@fillcolor, + fill opacity=\violin@pts@fillopacity, + ] table [ + \violin@axis@x=deltacol, + \violin@axis@y=\violin@index, + ] {\theviolin@dataset@table}; + }{} + \end{axis} + +} + +\newcommand{\violin@getnth}[2]{% + \pgfmathparse{int(0)} + \let\violin@getnth@counter\pgfmathresult + \let\violin@nthelem\pgfmathresult + \@for\violin@listelem:=#1\do{ + \ifthenelse{ + \equal{#2}{\violin@getnth@counter} + }{ + \let\violin@nthelem\violin@listelem + \pgfmathparse{int(\violin@getnth@counter+1)} + \let\violin@getnth@counter\pgfmathresult + }{ + \pgfmathparse{int(\violin@getnth@counter+1)} + \let\violin@getnth@counter\pgfmathresult + } + } +} + +\newcommand{\violinplotwholefile}[2][]{% + + \pgfkeys{/violinplotwholefile, default, #1} + \def\violin@batch@filename{#2} + + \pgfmathparse{0} + \let\violin@batch@numofplots\pgfmathresult + \@for\index:=\violin@batch@indexes\do{ + \pgfmathparse{int(\violin@batch@numofplots+1)} + \let\violin@batch@numofplots\pgfmathresult + } + + \pgfmathparse{0} + \let\violin@batch@color@deg\pgfmathresult + \let\violin@batch@counter\pgfmathresult + \let\violin@batch@relativepos\pgfmathresult + + \@for\violin@batch@index:=\violin@batch@indexes\do{ + \pgfmathparse{int(\violin@batch@counter*% + (100/(\violin@batch@numofplots-1)))} + \let\violin@batch@color@deg\pgfmathresult + \edef\violin@batch@color{\violin@batch@color@primary!\violin@batch@color@deg!\violin@batch@color@secondary} + + \violin@getnth{\violin@batch@labels}{\violin@batch@counter} + \let\violin@batch@label\violin@nthelem + + \pgfmathparse{1+\violin@batch@counter*\violin@batch@delta} + \let\violin@batch@relativepos\pgfmathresult + + \violinplot[% + col sep = \violin@batch@colsep, + bandwidth=\violin@batch@bandwidth, + kernel = \violin@batch@kernel, + index=\violin@batch@index, + relative position=\violin@batch@relativepos, + samples = \violin@batch@samples, + color=\violin@batch@color, + label={\violin@batch@label}, + average mark = \violin@batch@avg@mark, + average size = \violin@batch@avg@size, + average color = \violin@batch@avg@color, + average opacity = \violin@batch@avg@opacity, + average fill = \violin@batch@avg@fillcolor, + average fill opacity = \violin@batch@avg@fillopacity, + dataset mark = \violin@batch@pts@mark, + dataset size = \violin@batch@pts@size, + dataset color = \violin@batch@pts@color, + dataset opacity = \violin@batch@pts@opacity, + dataset fill = \violin@batch@pts@fillcolor, + dataset fill opacity = \violin@batch@pts@fillopacity, + ]{\violin@batch@filename} + + \pgfmathparse{int(\violin@batch@counter+1)} + \let\violin@batch@counter\pgfmathresult + } + +} + |