向 pgfplot 图例添加值

向 pgfplot 图例添加值

作为我之前问题的后续(这里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_errEC50_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}

相关内容