# Is it possible to “transform” a histogram into a density plot in pgfplots?

I just figured out that there is the pgfplots package with the hist feature, that allows to "draw" histograms based on an external data table. What I'm looking for is a possibility to transform a histogram into density plot, where instead of counts I have densities according to breaks. It is like the hist function in R (if anybody knows) with parameters freq = FALSE.

Or, is there any other way (package) to plot density from the data set in LaTeX?

(Update: This feature is now included in the unstable version of pgfplots and will become part of the next regular release). That feature is not available in pgfplots by default. It's not too complicated to add, however. I've written a patch that makes it possible to use hist=density and hist={cumulative,density} to create density histograms. This example uses a datafile containing a sample of 2000 points taken from a normal distribution with mean 2 and standard deviation 1.

\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\pgfplotsset{
small,
every axis plot post/.style={
fill=orange!75,
draw=orange!50!black
},
trim axis left
}
\begin{tikzpicture}
\begin{axis}[ymin=0,title=\texttt{hist}]
\addplot [hist] table [y index=0] {random.tsv};
\end{axis}
\end{tikzpicture}\hfill
\begin{tikzpicture}
\begin{axis}[ymin=0, title=\texttt{hist=density}]
\addplot [hist=density] table [y index=0] {random.tsv};
\end{axis}
\end{tikzpicture}\vspace{1cm}

\begin{tikzpicture}
\begin{axis}[ymin=0, title=\texttt{hist=cumulative}]
\addplot [hist=cumulative] table [y index=0] {random.tsv};
\end{axis}
\end{tikzpicture}\hfill
\begin{tikzpicture}
\begin{axis}[ymin=0, title=\texttt{hist=\{cumulative,density\}}]
\addplot [hist={cumulative,density}] table [y index=0] {random.tsv};
\end{axis}
\end{tikzpicture}
\end{document}


Here's an attempt to recreate the result of the R command random<-rnorm(2000,2,1); hist(random,freq=F). The code for the pgfplots graph is

\begin{axis}[width=8cm,height=4.5cm, axis lines*=left]
\addplot [hist={density,bins=15,data min=-1.5,data max=6}] table [y index=0] {random.tsv};
\end{axis}


If you just want to try out the feature, you can put the following code in your preamble:

\makeatletter
\newif\ifpgfplotsplothandlerhistogram@density
\pgfplotsset{
hist/density/.is if=pgfplotsplothandlerhistogram@density,
hist/density/.default=true,
hist/density=false
}
\def\pgfplotsplothandlersurveyend@hist@{%
\pgfmathfloatsubtract@{\pgfplotsplothandlerhistogram@datamax}{\pgfplotsplothandlerhistogram@datamin}%
\let\pgfplotsplothandlerhistogram@range=\pgfmathresult
\pgfmathfloatdivide@{\pgfplotsplothandlerhistogram@range}{\pgfplotsplothandlerhistogram@N}%
\let\pgfplotsplothandlerhistogram@h=\pgfmathresult
\pgfmathfloatreciprocal@{\pgfplotsplothandlerhistogram@h}%
\let\pgfplotsplothandlerhistogram@invh=\pgfmathresult
%
\pgfplotsarraynewempty{pgfp@hist}%
\pgfplotsarrayresize{pgfp@hist}{\pgfplotsplothandlerhistogram@Nfixed}%
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to{0}%
}%
%
\pgfplotsapplistXlet\pgfplots@hist@data=\pgfp@hist@@
\pgfplotsapplistXnewempty\pgfp@hist@@
\expandafter\pgfplotsplothandlersurveyend@hist@loop\pgfplots@hist@data\pgfplots@EOI
\let\pgfplots@hist@data=\relax
%

% Calculate total count
\c@pgf@counta=0
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
}%
\edef\pgfp@hist@totalcount{\the\c@pgf@counta}
\ifpgfplotsplothandlerhistogram@cumulative
\c@pgf@counta=0
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
\ifpgfplotsplothandlerhistogram@density
\pgfmathdivide{\the\c@pgf@counta}{\pgfp@hist@totalcount}%
\expandafter\pgfplots@loc@TMPa\expandafter{\pgfmathresult}%
\else
\expandafter\pgfplots@loc@TMPa\expandafter{\the\c@pgf@counta}%
\fi
}%
\fi%
%
%% Density histogram
% Divide count in each bin by (totalcount*range/bins)
\ifpgfplotsplothandlerhistogram@density
\ifpgfplotsplothandlerhistogram@cumulative
\else
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
\pgfmathdivide{\pgfplots@hist@count}{\pgfp@hist@totalcount}
\pgfmathdivide{\pgfmathresult}{\pgfplotsplothandlerhistogram@h}
\expandafter\pgfplots@loc@TMPa\expandafter{\pgfmathresult}%
}%
\fi
\fi
%
%% End density histogram
\pgfplots@curplot@threedimfalse
%
\pgfplotsset{/pgfplots/hist/handler}%
\pgfplotsresetplothandler
\tikz@plot@handler
%
\pgfplotsplothandlersurveystart
%
\let\pgfplots@current@point@z=\pgfutil@empty
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\pgfplotsplothandlerhistgetintervalstartfor\pgfplotsarrayforeachindex
\pgfplotsplothandlerhist@invtrafo
\let\pgfplots@current@point@x\pgfmathresult%
\let\pgfplots@current@point@y\pgfplots@hist@count%
%\message{Survey point (\pgfplots@current@point@x,\pgfplots@current@point@y)^^J}%
\pgfplotsplothandlersurveypoint
}%
\ifpgfplotsplothandlerhistogram@intervals
% replicate last count.
\let\pgfmathresult\pgfplotsplothandlerhistogram@datamax%
\pgfplotsplothandlerhist@invtrafo
\let\pgfplots@current@point@x\pgfmathresult%
\let\pgfplots@current@point@y\pgfplots@hist@count%
%\message{Survey point (\pgfplots@current@point@x,\pgfplots@current@point@y)^^J}%
\pgfplotsplothandlersurveypoint
\fi
%
\pgfplotsplothandlersurveyend
}
\makeatother


Here's the patch. If you save it to a file called density.patch, you can apply it by navigating to your pgfplots directory (on my machine, that's ~/.texlive2011/texmf-local/tex/generic/pgfplots) and calling patch < density.patch.

--- pgfplotsplothandlers.code.tex       2012-05-01 21:47:37.000000000 +0200
+++ pgfplotsplothandlerswithdensity.code.tex    2012-05-02 12:44:19.927248104 +0200
@@ -1380,6 +1380,7 @@

\newif\ifpgfplotsplothandlerhistogram@intervals
\newif\ifpgfplotsplothandlerhistogram@cumulative
+\newif\ifpgfplotsplothandlerhistogram@density
\pgfplotsset{
hist/.code={%
\let\tikz@plot@handler=\pgfplotsplothandlerhistogram
@@ -1398,6 +1399,9 @@
hist/intervals=true,
hist/cumulative/.is if=pgfplotsplothandlerhistogram@cumulative,
hist/cumulative/.default=true,
+   hist/density/.is if=pgfplotsplothandlerhistogram@density,
+   hist/density/.default=true,
+   hist/density=false,
hist/handler/.style={/tikz/ybar interval},
hist/symbolic coords/.style={%
/pgfplots/symbolic coords={hist/data}{A,B,C,D,E,F,G,H,I,J},
@@ -1521,15 +1525,43 @@
\expandafter\pgfplotsplothandlersurveyend@hist@loop\pgfplots@hist@data\pgfplots@EOI
\let\pgfplots@hist@data=\relax
%
+
+   % Calculate total count
+   \c@pgf@counta=0
+   \pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
+       \def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
+   }%
+   \edef\pgfp@hist@totalcount{\the\c@pgf@counta}
\ifpgfplotsplothandlerhistogram@cumulative
\c@pgf@counta=0
\pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
\def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
-           \expandafter\pgfplots@loc@TMPa\expandafter{\the\c@pgf@counta}%
+           \ifpgfplotsplothandlerhistogram@density
+               \pgfmathdivide{\the\c@pgf@counta}{\pgfp@hist@totalcount}%
+               \expandafter\pgfplots@loc@TMPa\expandafter{\pgfmathresult}%
+           \else
+               \expandafter\pgfplots@loc@TMPa\expandafter{\the\c@pgf@counta}%
+           \fi
}%
+   \fi%
+   %
+   %% Density histogram
+   % Divide count in each bin by (totalcount*range/bins)
+   \ifpgfplotsplothandlerhistogram@density
+       \ifpgfplotsplothandlerhistogram@cumulative
+       \else
+           \pgfplotsarrayforeachungrouped{pgfp@hist}\as\pgfplots@hist@count{%
+               \def\pgfplots@loc@TMPa{\pgfplotsarrayset{\pgfplotsarrayforeachindex}\of{pgfp@hist}\to}%
+               \pgfmathdivide{\pgfplots@hist@count}{\pgfp@hist@totalcount}
+               \pgfmathdivide{\pgfmathresult}{\pgfplotsplothandlerhistogram@h}
+               \expandafter\pgfplots@loc@TMPa\expandafter{\pgfmathresult}%
+           }%
+       \fi
\fi
%
+   %% End density histogram
\pgfplots@curplot@threedimfalse
%
\pgfplotsset{/pgfplots/hist/handler}%

• +1 Just great! You wrote 'not too complicated' :). I am just using this feature. – Dr. Manuel Kuehner Jun 1 '14 at 15:37