11

I want to add a bunch of evenly spaced vertical lines to a plot using \foreach.

I can do it like this:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

\begin{document}

\begin{tikzpicture}

    \begin{axis}[
        axis lines=left,
        scaled ticks=false,
        xtick=\empty,
        ytick=\empty,
        ymin=0,
    ]

    \addplot[samples=100,domain=0:10] {(x-5)^2 + 20};

    \addplot coordinates {\foreach \x in {1,...,9}  (\x,0) (\x,40)};

    \end{axis}

\end{tikzpicture}

\end{document}  

And I get the following plot:

enter image description here

However, I want all of the lines to be part of the same plot; something like this:

\addplot coordinates {\foreach \x in {1,...,9}  (\x,0) (\x,40)};

or this:

\addplot {\foreach \x in {1,...,9} coordinates (\x,0) (\x,40)};

But neither of these compiles. Is it possible to use \foreach inside \addplot, and if so, what's the correct syntax?

Edit: I want the plot to be something like this:

enter image description here

which I generated with the following snippet:

\addplot coordinates {
    (1,0) (1,40)

    (2,0) (2,40)

    (3,0) (3,40)

    (4,0) (4,40)
};

But I want to do it using a for-type loop.

By the way, the reason I'm doing this is to be able to drop lines from the curve to the x-axis and label them. I plan to make the vertical lines invisible, then find the intersections of the curve the vertical lines, and then use the intersection points as coordinates for visible lines that start at the curve. If there's a more efficient way to do that (which seems like a pretty common thing to do), I'm all ears. Edit: I'm reading the function from a file, not generating it using a formula.

2
  • 2
    Not sure to understand it, but if you know the plotted function, a coordinate on it is just (x, f(x)). Why do you need to find an intersection point? Take a look at "Accessing Axis Coordinates in Graphical Elements" in pgfplots documentation
    – Ignasi
    Sep 1, 2015 at 13:34
  • I'm actually reading the function from a file -- see my comment below. Sep 1, 2015 at 16:41

3 Answers 3

12

To avoids expansion issues with \foreach, pgfplots offers \pgfplotsinvokeforeach which can be used without problems; also, you can easily draw your lines from the curve to the axis using the function (no need to find intersections points); declaring the function from the beginning also simplifies the code:

enter image description here

The code:

\documentclass[border=5]{standalone}
\usepackage{pgfplots}
%\pgfplotsset{compat=1.12}

\pgfmathdeclarefunction{myfunct}{1}{%
  \pgfmathparse{(#1-5)^2 + 20}%
}

\begin{document}    
\begin{tikzpicture} 
    \begin{axis}[%
        ,axis lines=left
        ,xtick=\empty
        ,ytick=\empty
        ]
        \addplot[samples=100,domain=0:10] {myfunct(x)};
        \pgfplotsinvokeforeach{1,...,9}{
            \addplot coordinates { (#1,0) (#1,40) };}
    \end{axis}  
\end{tikzpicture}\qquad
\begin{tikzpicture} 
    \begin{axis}[%
        ,axis lines=left
        ,xtick=\empty
        ,ytick=\empty
        ]
        \addplot[samples=100,domain=0:10] {myfunct(x)};
        \pgfplotsinvokeforeach{1,...,9}{
            \addplot coordinates { (#1,0) (#1,{myfunct(#1)}) };
            \node[above=5pt] at (axis cs:#1,{myfunct(#1)}) {\pgfmathprint{myfunct(#1)}};
            }
    \end{axis}  
\end{tikzpicture}   

\end{document} 

Update

Using the same idea, name the path for the curve and inside \pgfplotsinvokeforeach draw the lines and name them; find the intersection points and draw the desired lines with the required labels:

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{fillbetween}
\pgfplotsset{compat=1.10}

\usepackage{filecontents}
\begin{filecontents*}{mydata.dat}
-6 36
-5 25
-4 16
-3 9
-2 4
-1 1
0 0
1 1
2 4
3 9
4 16
5 25
6 36
\end{filecontents*}


\begin{document}

\begin{tikzpicture}

\begin{axis}[
  axis lines=left,
  scaled ticks=false,
  xtick=\empty,
  ytick=\empty,
  ymin=0,
]
\addplot[no marks,smooth,name path=curve] table {mydata.dat};
\pgfplotsinvokeforeach{-6,...,6}{
  \addplot[draw=none,name path={line#1}] coordinates  { (#1,0) (#1,40) };
  \path[name intersections={of=curve and line#1,by={point#1}}];
  \draw[red]
    (axis cs:#1,0) -- (point#1) node[above,black] {#1};
}
\end{axis}

\end{tikzpicture}

\end{document} 

enter image description here

8
  • Actually I want the foreach inside the addplot because I want all the vertical lines to be part of the same plot (to make indexing easier later on). Also, let me clarify: I don't actually know the function, I'm reading data from a file. I only used x^2 here to build a compilable MWE. So, if I am reading the function points from a file, is there a way to do something like your second example? Sep 1, 2015 at 16:37
  • @grendelsdad Sounds like a new question to me. Feel free to open it, providing there a little complete document and a simple data file showing your relevant settings. Sep 1, 2015 at 16:38
  • Sorry, @GonzaloMedina, I edited my response to your answer -- see above. Sep 1, 2015 at 16:55
  • @grendelsdad I suggested a new question, not editing this one. Now my answer seems partly useless. Please, in the future, state your actual settings and intent from the beginning. Sep 1, 2015 at 16:58
  • @grendelsdad Now your question is confusing. You have some data in a file and are plotting those data and what do you want to do? At least, add to your question some simple data file showing us what you are really doing! Sep 1, 2015 at 17:06
3

The correct syntax (or at least a syntax which works) can be seen below:

% arara: pdflatex

\documentclass[border=5]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}

\begin{document}    
\begin{tikzpicture} 
    \begin{axis}[%
        ,axis lines=left
        ,xtick=\empty
        ,ytick=\empty
        ]
        \addplot[samples=100,domain=0:10] {(x-5)^2 + 20};
        \foreach \x in {1,...,9}
        {\edef\temp{\noexpand\addplot coordinates { (\x,0) (\x,40)};}\temp}
    \end{axis}  
\end{tikzpicture}   
\end{document} 

enter image description here

1
  • 1
    beat me by 23 secs
    – JPi
    Sep 1, 2015 at 13:25
1

From last paragraph on your question, I understand you want something like this:

\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

\begin{document}

\begin{tikzpicture}

    \begin{axis}[
        axis lines=left,
        scaled ticks=false,
        xtick=\empty,
        ytick=\empty,
        ymin=0,
        declare function={myfunction(\t)=(\t-5)^2+20;}
    ]

    \addplot[samples=100,domain=0:10] {myfunction(x)};

    \foreach \x in {1,...,9}
        {\edef\temp{\noexpand\addplot coordinates { (\x,{myfunction(\x)})};}\temp}

     \draw (axis cs:3,{myfunction(3)})--++(90:2cm);
     \draw[red] (axis cs:2,{myfunction(2)})--(axis cs:7,{myfunction(7)});
    \end{axis}

\end{tikzpicture}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .