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 am trying to have TikZ automatically mark a local maximum in a fourth-degree polynomial I built using a curve-fitting tool. I am new to LaTeX and TikZ, and am a bit overwhelmed - there seem to be a dozen ways of accomplishing this.

The code Jake provided in his answer to this question does not seem to work for me; it works for the functions in the example, but not for mine.

Here is my minimal working example:

\documentclass[preview=false,tikz=true]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}

\pgfplotsset{
    /tikz/max node/.style={
        anchor=south
    },
    /tikz/min node/.style={
        anchor=north
    },
    mark min/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
            \ifdim\pgfplotspointmetatransformed pt=0pt
                \def\markopts{}%
                \node [min node] {
                    \pgfmathprintnumber[fixed]{\xvalue},%
                    \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
                };
            \else
                \def\markopts{mark=none}
            \fi
            \expandafter\scope\expandafter[\markopts,every node near coord/.style=green]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter,
    },
    mark max/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
            \ifdim\pgfplotspointmetatransformed pt>1000pt
                \def\markopts{}%
                \node [max node] {
                    \pgfmathprintnumber[fixed]{\xvalue},%
                    \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
                };
            \else
                \def\markopts{mark=none}
            \fi
            \expandafter\scope\expandafter[\markopts]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter
    }
}


\begin{document}

\begin{tikzpicture}
    \begin{axis}[
    xtick={0,...,7},
    domain=0:7,
    axis lines*=middle
    ]       
    \addplot +[mark max] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[
    xtick={0,...,7},
    domain=0:7,
    axis lines*=middle
    ]       
    \addplot +[mark min] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}
    \addplot +[mark max] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}
    \addplot +[mark min] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\end{document}

This results in the following plots:

enter image description here

The first plot is the one I want to highlight a maximum for. The second plot shows that it works for the minimum; the third plot is without a domain set -- you can see that it doesn't find a maximum there, either, although again it works for the minimum.

Now, while I was setting up the example, I tweaked some values.

If I change the threshold to 500 pt:

\documentclass[preview=false,tikz=true]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}

\pgfplotsset{
    /tikz/max node/.style={
        anchor=south
    },
    /tikz/min node/.style={
        anchor=north
    },
    mark min/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
            \ifdim\pgfplotspointmetatransformed pt=0pt
                \def\markopts{}%
                \node [min node] {
                    \pgfmathprintnumber[fixed]{\xvalue},%
                    \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
                };
            \else
                \def\markopts{mark=none}
            \fi
            \expandafter\scope\expandafter[\markopts,every node near coord/.style=green]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter,
    },
    mark max/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
%            \ifdim\pgfplotspointmetatransformed pt>1000pt
            \ifdim\pgfplotspointmetatransformed pt>500pt
                \def\markopts{}%
                \node [max node] {
                    \pgfmathprintnumber[fixed]{\xvalue},%
                    \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
                };
            \else
                \def\markopts{mark=none}
            \fi
            \expandafter\scope\expandafter[\markopts]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter
    }
}


\begin{document}

\begin{tikzpicture}
    \begin{axis}[
    xtick={0,...,7},
    domain=0:7,
    axis lines*=middle
    ]       
    \addplot +[mark max] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\end{document}

then I get:

threshold 500pt

(I would be interested in knowing why this happens.)

A bit of further playing around reveals that setting it to 999pt gives the desired result:

threshold 999pt

I have to admit at this point that I don't understand the code, and have no idea if this solution is the right one or whether it will give consistent results. Perhaps someone could explain what is happening? I don't understand what the "meta value" is supposed to mean here, or even what scatter does.

How would one draw a highlighted vertical line from the horizontal axis to the maximum using this method?

share|improve this question
add comment

1 Answer

up vote 12 down vote accepted

There are some numerical inaccuracies involved here: The range of \pgfplotspointmetatransformed should be from 0 to 1000, where 0 is the point with the lowest meta value (by default, the meta value is the same as the y coordinate), and 1000 is the maximum value. However, it seems that the maximum value is sometimes something along the lines of 999.9876 or 1000.0422.

I took another look at the code, and found that there's actually a better way to determine the extreme values: They're already stored in the macros \pgfplots@metamin and \pgfplots@metamax. So we can simply use \ifx\pgfplots@metamax\pgfplotspointmeta to check whether we have the maximum value.

To be able to use the maximum to draw a vertical line, we can place a \coordinate node. This can only be accessed after the axis is finished, so you'll need to put your drawing command into the after end axis/.code={...} option. Setting

after end axis/.code={
        \draw [thick, dashed, gray] (maximum) --({axis cs:0,0}-|maximum);
}

will draw a vertical line from the maximum to the 0 line. For boxed plots, you should use rel axis cs:0,0 instead of axis cs:0,0, so the line goes all the way to the edge of the plot area.

\documentclass[preview=false,tikz=true]{standalone}
\usepackage{pgfplots}
\makeatletter
\pgfplotsset{
    /tikz/max node/.style={
        anchor=south,
    },
    /tikz/min node/.style={
        anchor=north,
        name=minimum
    },
    mark min/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
            \ifx\pgfplotspointmeta\pgfplots@metamin
                \def\markopts{}%
                \coordinate (minimum);
                \node [min node] {
                    \pgfmathprintnumber[fixed]{\xvalue},%
                    \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
                };
            \else
                \def\markopts{mark=none}
            \fi
            \expandafter\scope\expandafter[\markopts,every node near coord/.style=green]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter,
    },
    mark max/.style={
        point meta rel=per plot,
        visualization depends on={x \as \xvalue},
        scatter/@pre marker code/.code={%
        \ifx\pgfplotspointmeta\pgfplots@metamax
            \def\markopts{}%
            \coordinate (maximum);
            \node [max node] {
                \pgfmathprintnumber[fixed]{\xvalue},%
                \pgfmathprintnumber[fixed]{\pgfplotspointmeta}
            };
        \else
            \def\markopts{mark=none}
        \fi
            \expandafter\scope\expandafter[\markopts]
        },%
        scatter/@post marker code/.code={%
            \endscope
        },
        scatter
    }
}
\makeatother

\begin{document}

\begin{tikzpicture}
    \begin{axis}[
    xtick={0,...,7},
    domain=0:7,
    axis lines*=middle,after end axis/.code={
        \draw [thick, dashed, gray] (maximum) --({axis cs:0,0}-|maximum);
    }
    ]       
    \addplot +[mark max] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[
    xtick={0,...,7},
    domain=0:7,
    axis lines*=middle
    ]       
    \addplot +[mark min] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}[
        after end axis/.code={
            \draw [thick, dashed, gray] (maximum) --({rel axis cs:0,0}-|maximum);
        }
    ]
    \addplot +[mark max] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}
    \begin{axis}
    \addplot +[mark min] plot {0.001826*x^4-0.02873*x^3+0.1066*x^2+0.03454*x+0.003613};
    \end{axis}
\end{tikzpicture}



\end{document}
share|improve this answer
2  
Yay! Too late again :) –  percusse May 11 '12 at 9:36
add comment

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.