22

I know that one can get smooth point connections with option smooth to \addplot that takes the previous and the next point into account, but this still connects all the points.

How can I draw a smooth curve through the points using pgfplots that are not necessarily connected? I'm not fully sure if this is correct, but I think I'm looking for "bezier curves" (correct me if wrong). To be clear: I do not want curve-fitting like one can do with gnuplot, just some "sloppy-smooth" connecting of points.

Example picture (not from my data!):

enter image description here

Here is my real data, they don't follow a known, analytical, mathematical function:

43  3.22
44  3.26
45  3.28
46  3.40
47  3.60
48  3.53
49  3.50
50  3.60
51  3.59
52  3.54
53  3.55
54  3.51
55  3.35
56  3.45
57  3.42
58  3.43
59  3.42
60  3.42
61  3.43
62  3.47
63  3.45
64  3.40
65  3.20
66  3.21
67  3.17
68  3.20
69  3.22
70  3.36
71  3.37
72  3.37
73  3.30
74  3.33
75  3.39
76  3.41
77  3.34
78  3.45
79  3.42
80  3.38
81  3.33
82  3.15
83  3.35
84  3.33
85  3.20
86  3.24
87  3.20
Foo Bar
  • 13,247
  • 4
    You are asking for the hobby package that Andrew Stacey created for TikZ. – percusse Apr 18 '13 at 17:35
  • @percusse: I agree, although hobby curves do go through all the specified points – Jake Apr 18 '13 at 17:36
  • @Jake oops, nice catch! It might still smoothen out though. – percusse Apr 18 '13 at 17:41
  • 1
    @FooBar: Could you edit your question to include an example of the data you want to smooth? – Jake Apr 18 '13 at 17:44
  • @Jake done. It does not follow any known mathematical function, however. Just some "random" points. – Foo Bar Apr 18 '13 at 17:49
  • @percusse, can hobby be integrated directly in pgfplots? – alfC Apr 18 '13 at 18:53
  • Yes you can use TikZ commands inside the axis environments. But it might require a few modifications. I didn't test it. – percusse Apr 18 '13 at 18:54
  • @percusse, yes, it looks like (page 6), but it may not have the desired effect out of the box as the resulting curve is not a "function". – alfC Apr 18 '13 at 18:56
  • @alfC You don't \addplot it but rather \draw a TikZ path inside the axis environment. Jake's comment still holds though. – percusse Apr 18 '13 at 19:06
  • @Jake Since the last update, hobby can be used with \addplot. However, I don't recommend it as it can double back on itself as alfC mentions. (I added it because it was requested.) – Andrew Stacey Apr 18 '13 at 19:10

3 Answers3

14

Using the gnuplot backend, put your points in a file.dat, and compile twice with -shell-escape

enter image description here

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\begin{document}
\begin{tikzpicture}
  \begin{axis}
    \addplot +[no markers, raw gnuplot] gnuplot {
        plot 'file.dat' smooth sbezier;
    };
    \addplot +[only marks, raw gnuplot] gnuplot {
        plot 'file.dat' with points;
    };
  \end{axis}
\end{tikzpicture}
\end{document}
alfC
  • 14,350
  • Thanks to everyone, but I like this solution most, since I'm using gnuplot already. But I upvoted all solutions, since they are all very good. – Foo Bar Apr 18 '13 at 18:56
10

One thing you could do is to calculate a LOESS smooth of the data. I don't know of a way to do this in LaTeX directly, but you could preprocess your data in R (which is free and useful to know, at any rate).

The following code reads the data from a file called data.dat and smoothes it using a span of 0.3 (i.e. it takes 30% of the data around each point into account for calculating a polynomial), and then writes it to a file called smooth.dat:

datapoints = read.delim('data.dat', header=F)
smooth=loess(datapoints$V2 ~ datapoints$V1, span=0.3)
write.table(data.frame(smooth$x,smooth$fitted), 'smooth.dat',sep='\t', quote=F, col.names=F, row.names=F)

Which you can then plot using:

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}
\addplot [only marks] table {../data.dat};
\addplot [red, smooth] table {../smooth.dat};
\end{axis}

\end{tikzpicture}
\end{document}
Jake
  • 232,450
  • Your neat answer made me want to ask you a question about curve fitting with pgfplots and gnuplot. In my question here, is it possible to use gnuplot with pgfplot to get a fitting function through certain points then draw it? – Diaa Nov 25 '16 at 17:01
7

here is your data with a Bezier curve:

\documentclass{article}% run with xelatex
%\usepackage[pdf]{pstricks}% for pdflatex --shell-escape
\usepackage{pst-plot}
\begin{document}
\psset{xunit=0.2,yunit=5}
\begin{pspicture}(0,0)(50,1)
\pstScalePoints(1,1){40 sub}{3 sub}
\psaxes[ticksize=0 5pt,Dy=0.2,Dx=10,Ox=40,Oy=3]{->}(0,0)(50,1)
\readdata\data{data0.dat}
\listplot[linecolor=red,linewidth=1.5pt,plotstyle=bezier]{43 3.22 \data}
\listplot[plotstyle=dots]{43 3.22 \data}
\end{pspicture}

\end{document}

enter image description here