作为我之前问题的后续(这里latex
),这里有一个可能比更复杂的问题gnuplot
。使用 gnuplot 和 pgfplots 生成拟合曲线后,有没有一种简单的方法可以latex
自动从图例或标题中的拟合中报告拟合参数(在本例中为:Ymax、EC50、nH)gnuplot
?
这是一个有效的例子:
\documentclass[11pt]{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\usepackage{xcolor}
\begin{filecontents}{drc1.dat}
2 17
5 55
10 96
20 125
50 144
100 147
200 147
500 146
\end{filecontents}
\begin{document}
\begin{figure}[h!t]
\centering
\begin{tikzpicture}
\begin{axis}[
legend pos=north west,
xmode=log,
ymode=linear,
axis x line*=bottom,
axis y line*=left,
tick label style={font=\small},
grid=both,
tick align=outside,
tickpos=left,
xlabel= {[ACh]} (nM),
ylabel=Response (mm),
%%% GRAPH RANGE %%%
xmin=0.1, xmax=1000,
ymin=0, ymax=160,
%%%%%%%%%%%%%%
width=0.6\textwidth,
height=0.4\textwidth,
]
\addplot[only marks, mark size=1.8, color=blue] file {drc1.dat};
% Now call gnuplot to fit this data
% The key is the raw gnuplot option
% which allows to write a gnuplot script file
\addlegendentry{{\tiny Experiment 1}}
\addplot+[raw gnuplot, draw=blue, mark=none, smooth] gnuplot {
set log x;
f(x)=Ymax/(1+(EC50/x)^nH);
% let gnuplot fit, using column 1 and 2 of the data file
% using the following initial guesses
Ymax=150;
nH=1;
EC50=50;
fit f(x) 'drc1.dat' using 1:2 via Ymax,EC50,nH;
% Next, plot the function and specify plot range
% The range should be approx. the same as the test.dat x range
plot [x=0.1:1000] f(x);
};
\end{axis}
\end{tikzpicture}
\end{figure}
\end{document}
TexShop 控制台报告拟合结果,即
Final set of parameters Asymptotic Standard Error
======================= ==========================
Ymax = 146.818 +/- 3.228 (2.199%)
EC50 = 18.5506 +/- 0.9328 (5.028%)
nH = 3.1713 +/- 0.5152 (16.25%)
这些也包含在生成的文件中fit.log
。但是这些可以被 Latex 访问吗?
答案1
您可以使用 gnuplot 命令set print "<filename"
打开一个新文件,然后使用 将参数写入该文件print Ymax,EC50,nH
。如果您使用set fit errorvariables;
,标准错误将以 的形式提供Ymax_err
,EC50_err
等等。然后您可以使用\pgfplotstableread{<filename>}<table macro>
读取文件,并使用 访问各个条目\pgfplotstablegetelem{<row>}{<col>}\of<table macro>
,这会将条目保存到名为 的临时宏中\pgfplotsretval
。
以下是如何使用它的示例:
\documentclass[11pt]{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\begin{filecontents}{drc1.dat}
2 17
5 55
10 96
20 125
50 144
100 147
200 147
500 146
\end{filecontents}
\begin{document}
\begin{figure}[h!t]
\centering
\begin{tikzpicture}
\begin{axis}[
legend pos=north west,
xmode=log,
ymode=linear,
axis x line*=bottom,
axis y line*=left,
tick label style={font=\small},
grid=both,
tick align=outside,
tickpos=left,
xlabel= {[ACh]} (nM),
ylabel=Response (mm),
%%% GRAPH RANGE %%%
xmin=0.1, xmax=1000,
ymin=0, ymax=160,
%%%%%%%%%%%%%%
width=0.7\textwidth,
height=0.4\textwidth,
]
\addplot[only marks, mark size=1.8, black] file {drc1.dat};
% Now call gnuplot to fit this data
% The key is the raw gnuplot option
% which allows to write a gnuplot script file
\addlegendentry[anchor=mid,font=\tiny]{Experiment 1}
\addplot+[raw gnuplot, red, mark=none, smooth] gnuplot {
set log x;
f(x)=Ymax/(1+(EC50/x)^nH);
% let gnuplot fit, using column 1 and 2 of the data file
% using the following initial guesses
Ymax=150;
nH=1;
EC50=50;
set fit errorvariables;
fit f(x) 'drc1.dat' using 1:2 via Ymax,EC50,nH;
% Next, plot the function and specify plot range
% The range should be approx. the same as the test.dat x range
plot [x=0.1:1000] f(x);
set print "parameters.dat"; % Open a file to save the parameters into
print Ymax, Ymax_err; % Write the parameters to file
print nH, nH_err;
print EC50, EC50_err;
};
\addlegendentry[font=\tiny, text depth=2ex]{\pgfplotstableread{parameters.dat}\parameters % Open the file Gnuplot wrote
\pgfplotstablegetelem{0}{0}\of\parameters \pgfmathsetmacro\paramA{\pgfplotsretval} % Get first element, save into \paramA
\pgfplotstablegetelem{1}{0}\of\parameters \pgfmathsetmacro\paramB{\pgfplotsretval}
\pgfplotstablegetelem{2}{0}\of\parameters \pgfmathsetmacro\paramC{\pgfplotsretval}
$\frac{\pgfmathprintnumber{\paramA}}{\left(1+\frac{\pgfmathprintnumber{\paramB}}{[ACh]}\right)^{\pgfmathprintnumber{\paramC}}}$
}
\end{axis}
\end{tikzpicture}
\end{figure}
\pgfplotstabletypeset[
dec sep align,
fixed,
columns/0/.style={
column name=Parameter
},
columns/1/.style={
column name=Standard Error
}
]{parameters.dat}
\end{document}
这将产生
以下是我之前比较粗糙的方法:
我定义了一个宏\extractcoefficients
,它将系数的数量作为参数,然后首先计算中的行数fit.log
,然后解析文件末尾附近的相关行,将系数名称、值和标准误差保存到pgfplotstable
名为的中\coefficients
,并将值另外存储在pgfmath
名为的数组中\coefficient
。
然后,您可以使用 输出整个表格\pgfplotstabletypeset [coefficient table] \coefficients};
,或者使用 将系数值放置在所需的位置\coefficient{<number>}
。
\documentclass[11pt]{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\usepackage{pgfplotstable}
\begin{filecontents}{drc1.dat}
2 17
5 55
10 96
20 125
50 144
100 147
200 147
500 146
\end{filecontents}
\makeatletter
\newcommand\create[1]{%
\expandafter\newcommand\csname #1\endcsname{My name is #1}}
%% "Master" macro: Parse file and store table and coefficients
% Number of coefficients as argument
\newcommand{\extractcoefficients}[1]{
\linesinfile{fit.log} % Count number of lines
\addtocounter{linecount}{-9} % Coefficients start 9 lines from end
\edef\lastresultline{\arabic{linecount}}
\addtocounter{linecount}{-#1}
\stepcounter{linecount}
\edef\firstresultline{\arabic{linecount}}
\pgfplotstableread[ % Set up coefficient table
header=has colnames,
row sep=crcr
]{
Parameter Value SE\\
}\coefficients
\partialinput{\firstresultline}{\lastresultline}{fit.log}
\def\coefficientarray{2}
\pgfplotstableforeachcolumnelement{Value}\of{\coefficients}\as{\value}{
\edef\coefficientarray{\coefficientarray,\value}
}
\edef\coefficientarray{{\coefficientarray}}
}
%% Count number of lines in a file
\newread\lf
\newcounter{linecount}
\newcommand\linesinfile[1]{%
\setcounter{linecount}{0}
\openin\lf #1
\unless\ifeof\lf
\loop\unless\ifeof\lf
\readline\lf to\lfline
\stepcounter{linecount}
\repeat
\closein\lf
\fi
}
%% Go through a file, execute a command for each line within specified range
\makeatletter
\newcommand*\partialinput [3] {%
\IfFileExists{#3}{%
\openin\lf #3
\setcounter{linecount}{1}
\@whilenum\value{linecount}<#1 \do{%
\read\lf to\lfline
\stepcounter{linecount}%
}
\addtocounter{linecount}{-1}
\@whilenum\value{linecount}<#2 \do{%
\readline\lf to\lfline
\parsecoeff{\lfline}%
\stepcounter{linecount}%
}%
\closein\lf%
}{%
\errmessage{File `#3' doesn't exist!}%
}%
}
\makeatother
%% Store the whitespace-separated values of a line in a table
\newcommand\parsecoeff[1]{%
\pgfplotstableset{alias/.cd,
Parameter/.initial=0,
Value/.initial=2,
SE/.initial=4}
\edef\read{\noexpand\pgfplotstableread[
row sep=crcr,
header=false,
]{#1\noexpand\\}\noexpand\test}
\read%
\pgfplotstablevertcat{\coefficients}{\test}
}
%% Return the formatted coefficient
\newcommand{\coefficient}[1]{%
\pgfmathparse{\coefficientarray[#1]}%
\pgfmathprintnumber{\pgfmathresult}
}
%% PGFplotstable style for printing the coefficient table
\tikzset{
/pgfplots/table/coefficient table/.style={
columns={Parameter,Value, SE},
columns/Parameter/.style=string type,
columns/Value/.style={dec sep align},
columns/SE/.style={dec sep align, fixed, fixed zerofill, precision=3}
}
}
\begin{document}
\begin{figure}[h!t]
\centering
\begin{tikzpicture}
\begin{axis}[
legend pos=north west,
xmode=log,
ymode=linear,
axis x line*=bottom,
axis y line*=left,
tick label style={font=\small},
grid=both,
tick align=outside,
tickpos=left,
xlabel= {[ACh]} (nM),
ylabel=Response (mm),
%%% GRAPH RANGE %%%
xmin=0.1, xmax=1000,
ymin=0, ymax=180,
%%%%%%%%%%%%%%
width=0.7\textwidth,
height=0.45\textwidth,
]
\addplot[only marks, mark size=1.8, color=blue] file {drc1.dat};
% Now call gnuplot to fit this data
% The key is the raw gnuplot option
% which allows to write a gnuplot script file
\addlegendentry{{\tiny Experiment 1}}
\addplot+[raw gnuplot, draw=blue, mark=none, smooth] gnuplot {
set log x;
f(x)=Ymax/(1+(EC50/x)^nH);
% let gnuplot fit, using column 1 and 2 of the data file
% using the following initial guesses
Ymax=150;
nH=1;
EC50=50;
fit f(x) 'drc1.dat' using 1:2 via Ymax,EC50,nH;
% Next, plot the function and specify plot range
% The range should be approx. the same as the test.dat x range
plot [x=0.1:1000] f(x);
};
\extractcoefficients{3}
\addlegendentry[text depth=2ex]{%
\small{%
$\frac{\coefficient{1}}{\left(1+\frac{\coefficient{2}}{[ACh]}\right)^{\coefficient{3}}}$
}
}
\node at (rel axis cs:0.975,0.2) [
anchor=east,
font=\tiny,
fill=white,
fill opacity=0.75,
text opacity=1
] {
\pgfplotstabletypeset [coefficient table] \coefficients};
\end{axis}
\end{tikzpicture}
\end{figure}
\end{document}