9

I ploted the data from the table below (first vs. fourth column),

3000              1.2970e+00    0.198956 0.258046
3100              8.6050e-01    0.18747 0.161318
3200              5.7970e-01    0.172414 0.0999484
3300              3.9770e-01    0.147098 0.0585009
3400              2.7720e-01    0.128355 0.03558
3500              1.9700e-01    0.139395 0.0274608
3600              1.4310e-01    0.0867237 0.0124102
3700              1.0600e-01    0.0865613 0.0091755
3800              7.9990e-02    0.0509629 0.00407652
3900              6.1560e-02    0.0501454 0.00308695
4000              4.8010e-02    0.0249455 0.00119763

and in a previous post cjorssen helped me to correct the format (which is included below).

QUESTION(s):

  • How to fit a non-linear data for this columns (they have no name, just index)?

I found the post here (very helpful by the way), but this has no extra columns in the data file...

My code

Without any fitting is,

\documentclass{report}
\usepackage{amsmath,siunitx,xcolor}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\begin{document}
\begin{tikzpicture}
  \pgfkeys{%
    /pgf/number format/set thousands separator = {}}
  \begin{axis}[
    axis background/.style = {%
      shade,
      top color = gray,
      bottom color = white},
    legend style = {%
      fill = white},
    xlabel = Mass $\Omega$,
    ylabel = $\sigma*\mathcal{A}(\si{\pico\barn})$,
    ]
    \addplot+[only marks] table[x index=0,y index=3,header=false] {%
     3000              1.2970e+00    0.198956 0.258046
     3100              8.6050e-01    0.18747 0.161318
     3200              5.7970e-01    0.172414 0.0999484
     3300              3.9770e-01    0.147098 0.0585009
     3400              2.7720e-01    0.128355 0.03558
     3500              1.9700e-01    0.139395 0.0274608
     3600              1.4310e-01    0.0867237 0.0124102
     3700              1.0600e-01    0.0865613 0.0091755
     3800              7.9990e-02    0.0509629 0.00407652
     3900              6.1560e-02    0.0501454 0.00308695
     4000              4.8010e-02    0.0249455 0.00119763
   };
    \legend{$\sigma_{\text{MC}}$}
  \end{axis}
\end{tikzpicture}
\end{document}

And the result

Resulting plot from the code

Cheers.

13

PGFPlots can only fit linear functions, and it works best if the scales of the dependent and independent variables are similar. So you could either linearise and normalise your data to do the curve fitting using PGFPlots, or you could use gnuplot as a backend to do the fitting.

I'd go with the second option, because I find it to be a little more straightforward. Note that this requires you to compile the document with shell-escape enabled, and gnuplot has to be installed on your system.

\documentclass{report}
\usepackage{siunitx}
\usepackage{pgfplots}
\usepackage{filecontents}

\begin{filecontents}{data.csv}
     3000              1.2970e+00    0.198956 0.258046
     3100              8.6050e-01    0.18747 0.161318
     3200              5.7970e-01    0.172414 0.0999484
     3300              3.9770e-01    0.147098 0.0585009
     3400              2.7720e-01    0.128355 0.03558
     3500              1.9700e-01    0.139395 0.0274608
     3600              1.4310e-01    0.0867237 0.0124102
     3700              1.0600e-01    0.0865613 0.0091755
     3800              7.9990e-02    0.0509629 0.00407652
     3900              6.1560e-02    0.0501454 0.00308695
     4000              4.8010e-02    0.0249455 0.00119763
\end{filecontents}

\begin{document}
\begin{tikzpicture}
  \begin{axis}[
  /pgf/number format/set thousands separator = {},
    xlabel = Mass $\Omega$,
    ylabel = $\sigma*\mathcal{A}(\si{\pico\barn})$,
    ]
    \addplot [only marks, black] table[x index=0,y index=3,header=false] {data.csv};
    \addplot [no markers, red] gnuplot [raw gnuplot] { % "raw gnuplot" allows us to use arbitrary gnuplot commands
            f(x) = a*exp(b*x); % Define the function to fit
            a=1; b=-0.001; % Set reasonable starting values here
            fit f(x) 'data.csv' u 1:4 via a,b; % Select the file, the columns (indexing starts at 1) and the variables
            plot [x=3000:4000] f(x); % Specify the range to plot
    };
    \legend{$\sigma_{\text{MC}}$}
  \end{axis}
\end{tikzpicture}
\end{document}
| improve this answer | |
  • 1
    Thank you so much! very helpful and simple. The only things I'd point out are: (1) Compile using pdflatex -shell-escape file.tex, and (2) gnuplot should be installed in the OS (Am I right?). Cheers. – Dox Jun 20 '13 at 14:25
  • @Dox: Yes, you're right. I should have mentioned that, sorry. – Jake Jun 20 '13 at 14:33
2

Another option is to use embedded python code via the pythontex package. There is a 3-step process to compile the python code and have the results appear (see the documentation for the package):

pdflatex mytexfile.tex
pythontex mytexfile.tex
pdflatex mytexfile.tex

To do the fit you need to have python-numpy and python-scipy available to your python installation. Here is a MWE in which I took your data and fitted a 3rd order polynomial and an exponential decay (offset at Mass=3000):

\documentclass{article}
\usepackage{graphicx}% Include figure files
\usepackage{siunitx}
\sisetup{per-mode=symbol,inter-unit-product = \ensuremath { { } \cdot { } } }
\usepackage{filecontents} %This lets you create a file from within LaTeX
\usepackage{pythontex}

\begin{document}

\begin{filecontents*}{xyzfilecontent.csv}
     Mass mycol2 mycol3 sigma  
     3000 1.2970e+00 0.198956 0.258046  
     3100 8.6050e-01 0.18747 0.161318  
     3200 5.7970e-01 0.172414 0.0999484  
     3300 3.9770e-01 0.147098 0.0585009  
     3400 2.7720e-01 0.128355 0.03558  
     3500 1.9700e-01 0.139395 0.0274608  
     3600 1.4310e-01 0.0867237 0.0124102  
     3700 1.0600e-01 0.0865613 0.0091755  
     3800 7.9990e-02 0.0509629 0.00407652  
     3900 6.1560e-02 0.0501454 0.00308695  
     4000 4.8010e-02 0.0249455 0.00119763  
\end{filecontents*}

\begin{pycode}
import csv
import matplotlib.pyplot as plt
from numpy import *
import numpy.polynomial.polynomial  as poly
from scipy.optimize import curve_fit

csvfile=open('xyzfilecontent.csv','rb')
things=csv.DictReader(csvfile,delimiter=' ')
ystuff=[]
xstuff=[]

for this in things:
    xstuff.append(float(this['Mass']))
    ystuff.append(float(this['sigma']))

ser=poly.polyfit(xstuff,ystuff,3)
ffit=poly.polyval(xstuff,ser)
plt.plot(xstuff,ystuff,'k+',xstuff,ffit,'r-')
plt.xlabel('Mass ($\Omega$)')
plt.ylabel(r'$\sigma*\mathcal{A}(\mathrm{pb})$')
plt.legend(['Data',r'Fit=' + ' {:0.4g}+{:0.4g}'.format(ser[0],ser[1])+'$\cdot\mathrm{Mass}$' + '+{:0.4g}'.format(ser[2]) + '$\cdot\mathrm{Mass}^2$' + '+{:0.4g}'.format(ser[3]) + '$\cdot\mathrm{Mass}^3$ '],loc='upper left')
plt.title('sigma versus Mass')

plt.savefig('xandyfit.jpg')

#modify a general exponential to specify the starting x of fit
def expofit(x,a,b,c):
    yval=a*exp(b/1000.*(x-3000.))+c
    return(yval)

# for scipy routine need to cast the lists into a nparray type
xstuff=array(xstuff)
ystuff=array(ystuff)
guess=array([.3,-.01,0.])
popt, pcov = curve_fit(expofit, xstuff, ystuff,guess)
newsig=[]
#create a list for storing the fitted y values

for phi in xstuff:
    newsig.append(expofit(phi,*popt))
fig2=plt.figure()
#create another plot container

plt.plot(xstuff,ystuff,'k+')
plt.plot(xstuff, newsig, 'g-', label='fit')
plt.xlabel('Mass ($\Omega$)')
plt.ylabel(r'$\sigma*\mathcal{A}(\mathrm{pb})$')
plt.legend(['Data','Fit-$\\sigma = '+str(round(popt[0],5))+'*\\exp\\left('+str(round(popt[1],5))+'\\cdot \mathrm{(Mass-3000)}\\right) '+' +'+str(round(popt[2],5))+'$'],loc='upper left')
plt.title('Exponential sigma vs. Mass')

plt.savefig('xandyexp.jpg')
\end{pycode}

\includegraphics[scale=0.5]{xandyfit.jpg}

\includegraphics[scale=0.5]{xandyexp.jpg}
\end{document}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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