Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question

1 Answer 1

(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{%
        \advance\c@pgf@counta by\pgfplots@hist@count\relax  
        \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{%
            \advance\c@pgf@counta by\pgfplots@hist@count\relax
            \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{%
+       \advance\c@pgf@counta by\pgfplots@hist@count\relax  
+       \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{%
            \advance\c@pgf@counta by\pgfplots@hist@count\relax
            \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}%
share|improve this answer
    
+1 Just great! You wrote 'not too complicated' :). I am just using this feature. –  Manuel Kuehner Jun 1 at 15:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.