Pgf-Plot make a line between node and function

I propose the following, based on nodes near coords and scatter/@pre marker code:

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

\begin{document}

\begin{tikzpicture}
\begin{axis}[
  declare function={f(\x) = 0.35*\x + 1;},
  axis lines=middle,
  xlabel={$x$}, ylabel={$y$},
  x label style={anchor=west, inner sep=2pt},  % <-- added
  y label style={anchor=east, inner xsep=2pt}, % <-- added
  hide obscured x ticks=false,      % added to show the x tick at 0
  hide obscured y ticks=false,      % added to show the y tick at 0
  xmin=0, xmax=9, ymin=0, ymax=4.9, % avoid clash with the y label
  xtick distance=2,                 % as suggested by Stefan Pinnow
  ytick distance=1,                 % ditto
  samples=2, thick,                 % 2 samples are enough for a line
  domain=0:8,
  legend pos=outer north east,
  legend style={font=\small},
  ]

\addplot+[no marks, blue] {f(x)};
\addlegendentry{$y = 0.35x + 1$}

\addplot[
  only marks, mark=*, mark size=1pt, mark options={draw=red, fill=red},
  % This is the important part:
  nodes near coords={},
  scatter/@pre marker code/.append code={
    \draw[help lines]
         (0,0)
      -- (0, {f(\pgfkeysvalueof{/data point/x})-\pgfkeysvalueof{/data point/y}});
  }]
  coordinates {
      (2,0.8)
      (3,2.4)
      (4,3.2)
      (5,1.8)
      (6,2.8)
      (7,4)
      (8,2.7)
  };
\addlegendentry{points}

\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

One can also do it with scatter/position=absolute, but it is a bit more convoluted:

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

\begin{document}

\begin{tikzpicture}
\begin{axis}[
  declare function={f(\x) = 0.35*\x + 1;},
  axis lines=middle,
  xlabel={$x$}, ylabel={$y$},
  x label style={anchor=west, inner sep=2pt},  % <-- added
  y label style={anchor=east, inner xsep=2pt}, % <-- added
  hide obscured x ticks=false,      % added to show the x tick at 0
  hide obscured y ticks=false,      % added to show the y tick at 0
  xmin=0, xmax=9, ymin=0, ymax=4.9, % avoid clash with the y label
  xtick distance=2,                 % as suggested by Stefan Pinnow
  ytick distance=1,                 % ditto
  samples=2, thick,                 % 2 samples are enough for a line
  domain=0:8,
  legend pos=outer north east,
  legend style={font=\small},
  ]

\addplot+[no marks, blue] {f(x)};
\addlegendentry{$y = 0.35x + 1$}

\addplot[
  only marks, forget plot,
  % This is the important part:
  nodes near coords={},
  scatter/position=absolute,
  scatter/@pre marker code/.append code={
    \draw[help lines]
         (\pgfkeysvalueof{/data point/x}, \pgfkeysvalueof{/data point/y})
      -- (\pgfkeysvalueof{/data point/x}, {f(\pgfkeysvalueof{/data point/x})});
    \path[red] plot[mark=*, mark size=1pt, only marks]
      coordinates {(\pgfkeysvalueof{/data point/x},
                    \pgfkeysvalueof{/data point/y})};
  }]
  coordinates {
      (2,0.8)
      (3,2.4)
      (4,3.2)
      (5,1.8)
      (6,2.8)
      (7,4)
      (8,2.7)
  };

\addlegendimage{
  legend image code/.code={
    \draw[red]
      plot[only marks, mark=*, mark size=1pt] coordinates { (0.3cm,0cm) };
  },
}
\addlegendentry{points}

\end{axis}
\end{tikzpicture}

\end{document}

Same output as above.


I think my try is a little bit to much of a cheat, but it get's the job done.

\documentclass[tikz]{standalone}
\usepackage{pgfplots}

\begin{document}    
\pgfdeclareplotmark{noMark}{}
\begin{tikzpicture}[
declare function={foo(\x) = 0.35 * \x + 1;}
]
\begin{axis}
[ 
xlabel={$x$}, ylabel={$y$}
,axis lines=middle
,xmin=0,xmax=9,ymin=0,ymax=5
,xtick={0,2,...,8}
,ytick={0,1,...,4}
,samples=41, thick
,domain=0:8
,legend pos=outer north east
]
\addplot[blue] {foo(x)};
\addlegendentry{$g$}
\addlegendimage{red,only marks,mark=*}
\addlegendentry{$gg$}
%
\addplot+ [
red,
only marks,
mark=noMark,
error bars/.cd,
y dir=both,
y explicit,
error mark=*,
] coordinates {
    (2,{foo(2)}) += (0,{0.8-foo(2)}) 
    (3,{foo(3)}) += (0,{2.4-foo(3)})
    (4,{foo(4)}) += (0,{3.2-foo(4)})
    (5,{foo(5)}) += (0,{1.8-foo(5)})
    (6,{foo(6)}) += (0,{2.8-foo(6)})
    (7,{foo(7)}) += (0,{4.0-foo(7)})
    (8,{foo(8)}) += (0,{2.7-foo(8)})
};
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here


This is an improved answer (which is too long for a comment) of the (also) awesome idea of Venez (+1) using a table instead of coordinates. This makes live much easier :)

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    % create an empty plot mark
    % (which is needed later)
    \pgfdeclareplotmark{noMark}{}
\begin{document}
\begin{tikzpicture}[
    declare function={foo(\x) = 0.35 * \x + 1;}
]
    \begin{axis}[
        xmin=0,xmax=9,ymin=0,ymax=5,
        % (replaced `[x|y]tick`s)
        xtick distance=2,
        ytick distance=1,
        xlabel={$x$},
        ylabel={$y$},
        axis lines=middle,
        hide obscured x ticks=false,
        hide obscured y ticks=false,
        samples=2,     % <-- (more than 2 samples are not needed for a straight line)
        domain=0:8,
        legend pos=outer north east,
        thick,
    ]
        \addplot[blue] {foo(x)};
        \addlegendentry{$g$}

        % add a custom legend entry to imitate a "normal" mark plot
        \addlegendimage{red,only marks,mark=*}
        \addlegendentry{$gg$}

        % since this is the last plot and no more `\addlegendentry` is given
        % it doesn't show up in the legend
        \addplot+ [
            red,
            only marks,
            % don't show the normal mark ...
            mark=noMark,
            error bars/.cd,
                y dir=both,
                y explicit,
                % ... show the mark at the error (position)
                error mark=*,
        % replaced `coordinates` by a table which allows to calculate the
        % appropriate error position easily
        ] table [
            x=x,
            y expr={foo(\thisrow{x})},
            y error plus expr={\thisrow{y} - foo(\thisrow{x})},
        ] {
            x   y
            2   0.8
            3   2.4
            4   3.2
            5   1.8
            6   2.8
            7   4.0
            8   2.7
        };
    \end{axis}
\end{tikzpicture}
\end{document}

image showing the result of above code