14

I am trying to plot the following data with a curve fitting via pgfplots.

It seems linear regression is not suitable for my case. So I would prefer to have exponential or polynomial curve fitting on these data. How can I implement it?

Below is the current code:

% arara: pdflatex: { shell: yes }

\documentclass[border=1mm, png]{standalone}
\usepackage{siunitx}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\begin{filecontents*}{myData.dat}
X     Y 
2   275.68
3   1175.26
4   1351.60
5   1485.57
6   1583.30
7   1861.28
8   2095.39
9   2574.54
10  2841.74
11  2914.16
12  3965.12
13  3787.68
14  5294.83
21  10504.49
\end{filecontents*}

\begin{document}
\begin{tikzpicture}
    \pgfplotsset{%
        ,width=10cm
        ,legend style={font=\footnotesize}
        }
    \begin{axis}[%
        ,xlabel=Numbers $N$ in \si{\gram\per\liter}
        ,ylabel=Ratio
        ,ymin=0
        ,xmin=0
        ,scaled y ticks=base 10:0
        ,legend cell align = left
        ,legend pos = north west
        ]
    \addplot[only marks] table {mydata.dat};
    \addlegendentry{Ratio of \emph{tfml} to \emph{gGN}}
    \addplot+[no markers,red] table [y={create col/linear regression={y=Y}}]{myData.dat};
    \addlegendentry{%
        Linear trend $(y=\pgfmathprintnumber{\pgfplotstableregressiona} \cdot x
        \pgfmathprintnumber[print sign]{\pgfplotstableregressionb})$} %
    \end{axis}
\end{tikzpicture}
\end{document}

Which yields:

enter image description here

LaRiFaRi
  • 43,807
  • 2
    Did you take a look on how to use gnuplot in pgfplots? I guess, this kind of calculation needs some higher tool. Personally, I would recommend to calculate the curve you need via sageTeX and to plot it afterwards. – LaRiFaRi Jun 26 '14 at 11:41
  • Thank you! Such curve fitting is easy to implement via MS Excel or any other mathematical tools. However, when data sets are changing, the fitted curves have to be changed manually accordingly. Since both exponential and polynomial curve fitting can be converted into linear regression, so I guess there should be some implementation via pgfplots automatically. – LCFactorization Jun 26 '14 at 11:47
  • 1
    Well, Excel is a powerful calculation tool... (not that I like it ;-) ). If there is something implemented here, you should be able to find it by the words "fitting", "regression", "approximation", "polynomial" or "Taylor" in the manuals of pgfplots and pgfplotstable. Please have a look! I didn't check. – LaRiFaRi Jun 26 '14 at 11:57
  • 1
    Off topic: 1. $-$ is a minus sign. Therefore I would not set the unit of your ratio in math-mode. (As units should not be set in square brackets (ISO & SI) and a "ratio" has the unit 1 by definition, I would leave it away completely.). 2. please make you code minimal. You just need siunitx, pgfplots, and pgfplotstable for this example. – LaRiFaRi Jun 26 '14 at 12:04
  • 1
    I tried to search in the manual but didnot find exactly the solution. And I am not very familiar with how to convert it into linear regression in pgfplots myself. thank you for suggestions. Are you interested in editing my post so that I can learn from you? – LCFactorization Jun 26 '14 at 12:14
  • 1
    One approach would be to transform the data so that a linear fit was appropriate - in this case you might take log(y), but then the value at x=2 looks like a big outlier. See here. – Thruston Jun 26 '14 at 12:30
  • 2
    @LCFactorization: You can do this from within PGFPlots by using gnuplot in the background. See Non-linear curve fitting with gnuplot (this may be a duplicate of that question). – Jake Jun 26 '14 at 12:35
  • @Jake since I am asking whether it is possible by using pgfplots only, so solution with gnuplot may be a good option but not exactly the answer. So it is not a duplicate this way. Thank you – LCFactorization Jun 26 '14 at 12:39
  • @Thruston, thank you , let me try. If it works and is not a duplicate, please also post an answer here. – LCFactorization Jun 26 '14 at 12:40
  • 2
    @LCFactorization: PGFPlots can only do linear regression. The question "how can I linearize a polynomial / exponential equation?" seems more appropriate for math.stackexchange.com. – Jake Jun 26 '14 at 12:43
  • @LaRiFaRi Thank you very much for editing it. I was also wondering how to simply use only one data table. You helped me with it. Thanks :) – LCFactorization Jun 26 '14 at 12:44
  • @Jake I also intend to post the TeX code into a paper preparing for arXiv.org. The TeXlive system in arXiv.org may not support gnuplot(but I am not very sure). – LCFactorization Jun 26 '14 at 12:47
  • @LaRiFaRi Don't know why, the code \pgfplotsset{compat=1.1} doesn't work for me; I have to set it as at least 1.3 - 1.5 or there will be compiling error. – LCFactorization Jun 26 '14 at 13:02
  • @Jake I now begin to agree with you that only gnuplot would solve my problem easily. thank you! – LCFactorization Jun 26 '14 at 13:19
  • 1
    @LCFactorization 1.10 is what I wrote. Maybe you have to update your packages. You can add \listfiles in your preamble in order to read your current version in the .log-file. Just set the compat-number to your version. However, 1.10 is the most recent: http://www.ctan.org/pkg/pgfplots – LaRiFaRi Jun 26 '14 at 13:20
  • I use the old-styled version partly because I want to keep my LaTeX source code compatible with the TeXLive of arXiv.org. Thank you. I now realized this is a version number; I checked and found that only 1.3, 1.4 and 1.5 work for me now. – LCFactorization Jun 26 '14 at 13:26

1 Answers1

15

This is an attempt via polynomial fit and the use of gnuplot. Therefore this requires one to compile the code with shell-escape enabled, and gnuplot has to be installed on your system.

enter image description here

Edit: The OP finds how to find the actually parameters after curve fitting. The answer is here: show fitted values which needs two lines of code

set print "parameters.dat"; % Open a file to save the parameters into
print a, b;                 % Write the parameters to file

Code

\documentclass[border=10pt]{standalone}
\usepackage{pgf,tikz}
\usepackage{pstricks-add}
\usepackage{siunitx}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage{graphicx}
\usepackage{latexsym}
\usepackage{keyval}
\usepackage{ifthen}
\usepackage{moreverb}
\usepackage{gnuplottex}%[miktex]%[shell]
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.5}

\usepackage{filecontents}
\begin{document}

\begin{filecontents}{data.csv}
X     Y   
2   275.68
3   1175.26
4   1351.60
5   1485.57
6   1583.30
7   1861.28
8   2095.39
9   2574.54
10  2841.74
11  2914.16
12  3965.12
13  3787.68
14  5294.83
21  10504.49
    };
\end{filecontents}


\begin{tikzpicture}
    \pgfplotsset{width=10cm,
    legend style={font=\footnotesize}}
    \begin{axis}[
    xlabel={Numbers [N,\si{\gram\per\liter}]},
    ylabel={Ratio $[-]$},
    ymin =0,
    ytick = {200,2000,4000,6000,8000,10000},
        y tick label style={
        /pgf/number format/.cd,
        fixed,
        fixed zerofill,
        precision=0,
        /tikz/.cd
    },
    yticklabel=\pgfmathprintnumber{\tick},
    scaled y ticks=base 10:0,
    legend cell align = left,
    legend pos = north west]
    \addplot[only marks] table[x =X,y =Y]{data.csv};
    \addlegendentry{Ratio of {\em tfml} to {\em gGN}}
% linear curve fitting
    \addplot+[no markers,red] table[row sep=\\,
    y={create col/linear regression={y=Y}}] % compute a linear regression from the input table
    {data.csv};
    \addlegendentry{%
        linear trend $\left(y=\pgfmathprintnumber{\pgfplotstableregressiona} \cdot x
        \pgfmathprintnumber[print sign]{\pgfplotstableregressionb}\right)$} %
% polynomial fit 
    \addplot [no markers, blue] gnuplot [raw gnuplot] { % allows arbitrary gnuplot commands
            f(x) = a*x**2+b*x;     % Define the function to fit
            a=260;b=-270;          % Set reasonable starting values here
            fit f(x) 'data.csv' u 1:2 via a,b; % Select the file, starts at col 1 and two variables
            plot [x=2:21] f(x);    % Specify the range to plot
            set print "parameters.dat";  % Open a file to save the parameters
            print a, b;                  % Write the parameters to file
    };
   \addlegendentry{\pgfplotstableread{parameters.dat}\parameters % Open the file Gnuplot wrote
\pgfplotstablegetelem{0}{0}\of\parameters \pgfmathsetmacro\paramA{\pgfplotsretval} % Get first element, save into \paramA
\pgfplotstablegetelem{0}{1}\of\parameters \pgfmathsetmacro\paramB{\pgfplotsretval}
 polynomial fit: $y=\pgfmathprintnumber{\paramA} x^2 \pgfmathprintnumber[print sign]{\paramB} x $
}
\end{axis} 
\end{tikzpicture} 
\end{document}
Jesse
  • 29,686