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}
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}
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}