I have a list of data (two columns) and I want to plot in gnuplot only the value for which my second column has a local maximum.
To do so I would like to see if the
Comparing 3 consecutive data points is a simple way to look for maxima/peaks.
if y(i-1) < y(i) > y(i+1) then you have a maximum/peak at x(i).
However, if you have noisy curves (like experimental spectra typically are) you will get too many "peaks".
The following gnuplot code allows to set a threshold for what is considered as a peak. The code basically calculates a number for each peak which is a measure for the "independence" of a peak. (see https://en.wikipedia.org/wiki/Topographic_prominence). The code uses datablocks and therefore gnuplot >=5.2 is required. Comments and improvements are welcome.
Test data:
Spectrum.dat
# x y
6.02 153.33
9.59 154.03
9.59 154.03
9.59 154.03
9.83 153.66
10.58 153.22
10.62 153.85
11.32 152.33
11.53 153.67
11.88 153.27
13.28 153.97
13.42 154.35
14.56 152.99
14.75 153.50
15.23 153.91
15.59 153.58
16.56 153.85
16.70 154.49
16.97 153.98
17.23 154.49
17.37 153.73
17.90 154.24
17.93 154.91
18.80 154.23
18.83 154.64
20.37 153.59
20.48 153.99
21.70 153.19
22.29 154.36
22.41 153.38
23.34 155.04
23.41 155.38
24.38 154.71
24.58 154.96
25.40 155.13
25.41 154.70
26.20 154.21
26.36 154.84
26.55 154.11
26.79 154.73
27.02 154.13
27.54 154.51
27.55 155.17
28.08 155.42
28.33 154.97
28.61 155.17
29.06 155.10
29.12 154.26
29.61 153.61
30.03 154.84
30.58 155.30
30.68 154.72
31.21 155.82
31.99 155.83
32.58 156.56
33.03 156.23
33.51 156.79
33.73 158.88
34.00 157.85
34.17 159.82
34.32 161.24
34.55 160.78
34.85 162.58
35.14 163.84
35.50 168.07
35.85 168.40
36.55 180.70
36.75 179.27
37.16 178.78
38.15 168.93
38.29 170.52
38.83 164.96
39.63 161.39
40.17 158.67
40.48 159.22
40.88 159.75
40.95 158.77
41.45 160.86
41.58 160.33
41.84 161.12
42.51 162.83
43.33 165.09
43.43 164.20
43.63 164.56
44.22 164.76
44.92 162.58
45.71 159.40
45.98 159.84
47.03 157.01
47.53 157.15
47.95 155.48
48.08 156.21
48.56 154.51
48.64 155.11
49.14 153.69
49.31 154.27
49.86 154.71
50.14 154.13
50.33 155.83
50.37 155.36
51.00 154.60
51.37 154.75
52.00 154.91
52.01 154.34
54.28 153.83
54.46 154.33
54.83 153.19
55.58 155.30
55.86 154.95
55.92 156.48
56.40 155.89
56.59 155.16
57.56 155.96
57.64 155.21
58.31 155.36
58.38 156.08
58.92 155.84
59.00 155.28
59.57 155.96
59.94 155.37
61.31 156.07
61.32 156.78
61.96 157.34
62.37 156.89
63.14 159.45
63.54 159.51
63.80 161.03
63.93 161.56
64.17 161.12
64.84 162.38
65.14 166.28
65.64 168.07
66.22 169.06
66.42 167.70
66.56 168.40
67.10 167.20
67.24 168.00
67.77 166.82
68.04 165.80
68.15 166.88
68.43 164.98
68.86 166.28
69.33 166.55
70.43 179.11
70.93 198.16
71.62 208.09
72.01 216.42
72.43 223.37
72.79 226.74
72.84 231.24
73.07 229.85
73.15 222.04
73.32 224.49
73.58 211.26
73.71 215.36
73.98 201.60
73.98 208.75
74.25 202.93
74.53 189.70
74.90 184.01
75.18 184.80
76.67 173.29
77.05 173.82
77.15 170.94
77.27 177.13
77.52 175.20
77.70 179.76
78.17 179.96
78.36 183.33
78.73 187.05
78.86 184.67
79.03 189.90
79.38 189.70
79.59 190.62
79.88 189.17
80.59 186.52
80.60 183.61
81.26 177.53
81.67 173.69
82.07 173.69
82.90 165.37
83.94 164.04
84.25 164.42
85.01 161.26
85.22 162.18
85.77 161.19
85.89 159.97
86.46 160.72
86.56 161.78
87.06 160.56
87.19 161.53
87.74 159.60
87.89 160.64
88.30 158.74
88.56 159.27
88.98 158.08
89.25 158.70
90.12 159.15
90.14 158.34
90.99 159.59
91.06 158.86
91.72 159.01
91.74 158.48
92.43 157.68
92.48 158.34
93.15 157.68
93.54 158.34
93.72 157.61
94.20 158.00
94.39 158.64
94.82 157.83
95.00 158.40
95.43 156.77
95.66 157.39
95.81 155.44
95.84 156.25
96.53 157.70
96.55 156.70
97.22 159.14
97.47 158.13
97.53 156.75
98.57 157.83
98.85 157.40
98.92 158.45
99.35 158.25
99.40 157.77
100.04 158.33
100.14 157.91
101.00 158.30
101.04 157.80
101.94 157.48
102.02 158.20
102.53 156.56
102.58 157.84
103.23 157.75
103.38 156.82
103.39 158.93
103.75 158.60
104.05 159.26
104.30 158.14
104.55 158.56
104.85 157.15
105.17 160.09
105.21 158.41
105.52 161.78
105.80 160.00
105.92 160.86
106.11 159.54
106.31 159.93
106.86 160.99
107.20 160.88
107.42 162.05
107.62 160.33
107.80 161.16
108.39 159.90
108.79 162.25
109.08 161.85
109.46 163.77
109.73 163.42
109.96 165.16
111.02 170.08
111.30 173.56
111.69 173.56
112.35 180.08
112.61 189.04
112.89 193.53
113.28 193.67
113.81 210.73
113.94 206.63
114.20 213.11
114.46 219.60
115.00 230.44
115.12 236.95
115.27 234.68
115.78 238.78
116.11 239.57
116.40 238.51
116.43 239.90
117.90 230.31
118.18 221.32
118.42 222.51
118.70 217.48
118.83 211.13
119.25 210.34
119.37 204.51
119.65 205.18
120.08 200.28
120.12 198.96
120.84 204.18
120.95 201.87
121.24 206.49
121.50 203.01
121.64 204.44
121.73 201.74
121.84 202.53
122.14 203.72
122.19 202.40
122.44 203.59
122.45 204.91
122.64 201.61
122.76 203.17
123.08 200.79
123.10 200.15
123.34 199.51
123.39 200.81
123.88 200.28
124.25 196.58
124.26 194.06
124.53 193.67
125.18 188.77
125.81 182.16
126.10 182.55
127.32 171.71
127.70 171.18
127.96 168.27
128.22 168.66
128.62 165.71
128.89 166.24
129.30 163.94
129.56 164.47
129.96 162.22
130.21 162.72
130.53 160.83
130.93 160.61
131.15 161.24
131.84 160.06
131.93 161.12
132.71 159.87
133.06 163.17
133.38 162.73
134.17 166.97
134.31 172.37
134.85 180.83
135.38 193.01
135.62 190.09
135.64 200.81
135.75 204.05
136.16 206.10
136.80 200.22
137.21 199.36
138.29 175.41
138.56 176.73
139.98 163.09
140.03 161.92
140.32 164.53
140.55 163.80
140.85 166.25
141.24 165.81
141.45 167.92
141.59 166.51
141.99 170.65
142.25 170.19
142.76 177.79
142.91 174.95
143.72 187.66
143.79 185.37
144.65 179.11
144.91 180.32
145.71 175.74
145.84 174.80
146.54 177.73
146.74 180.57
147.30 181.11
147.42 180.30
148.33 181.23
148.38 180.68
148.93 181.19
149.09 181.74
149.24 178.43
149.49 179.03
149.96 174.55
150.69 173.48
151.83 168.06
151.89 169.39
152.41 168.27
152.96 169.45
153.02 168.53
153.47 169.42
153.71 168.78
153.91 169.44
154.08 167.74
154.54 168.92
154.65 168.20
155.61 168.79
156.78 165.75
157.06 166.08
157.54 162.68
157.84 163.40
158.51 162.73
158.57 161.85
159.45 161.27
159.57 160.33
160.11 158.81
160.24 159.81
160.90 159.27
160.90 158.08
161.17 158.48
161.43 158.10
161.59 158.72
161.83 157.91
162.44 158.48
162.61 157.94
163.41 158.75
163.43 158.19
163.94 158.99
163.96 158.33
164.60 158.23
164.87 158.74
165.81 158.50
166.10 158.08
166.74 158.91
167.02 158.48
167.67 159.68
167.96 159.28
168.90 159.81
168.96 160.34
169.57 159.77
169.76 161.28
170.00 160.75
171.01 163.77
171.12 163.13
171.79 163.71
172.83 169.14
173.19 169.13
173.52 171.06
173.73 170.38
173.87 171.65
174.27 171.90
174.41 175.94
174.94 177.39
175.20 183.48
175.71 185.07
175.84 190.49
176.48 193.27
176.51 196.84
177.34 201.47
177.62 207.30
177.69 205.18
177.87 203.26
178.08 204.46
178.45 199.43
178.76 199.62
179.02 193.53
179.43 192.08
179.96 178.98
180.21 176.40
180.56 176.57
180.57 176.20
181.14 176.43
181.24 175.51
181.68 174.93
181.74 177.13
181.97 178.85
182.05 176.93
182.14 179.78
182.30 177.53
182.59 178.72
182.72 176.93
183.04 177.67
183.21 178.76
183.33 177.92
183.75 179.99
184.06 179.78
184.28 182.07
184.71 182.49
185.40 187.78
185.61 184.01
186.02 183.86
186.20 180.07
186.79 178.72
186.97 175.44
187.34 175.15
188.45 167.65
188.84 166.25
189.08 166.77
189.50 164.08
189.90 163.69
189.92 161.67
190.37 162.04
190.41 162.90
190.90 161.40
190.93 162.58
192.29 159.27
192.33 158.79
193.23 160.21
193.34 159.73
193.78 161.15
194.07 160.20
194.54 160.43
194.93 159.64
195.39 159.82
195.98 160.86
196.08 160.05
196.45 161.78
197.00 158.90
197.03 159.95
197.70 157.15
198.07 160.13
198.10 158.48
198.83 159.67
198.85 160.46
199.27 159.80
199.46 159.46
200.46 161.78
200.73 161.38
201.38 162.37
201.92 159.72
202.06 160.52
203.14 157.67
203.52 157.95
203.93 157.02
204.13 157.55
204.39 156.66
204.63 157.15
206.35 155.53
206.57 156.00
207.21 156.57
207.33 155.76
208.23 157.93
208.52 157.68
208.92 157.15
209.21 157.56
209.41 156.62
209.88 156.89
211.48 154.50
211.70 155.00
212.39 155.37
212.51 154.53
212.84 154.31
212.92 155.17
213.26 154.38
213.44 155.24
213.70 154.57
214.15 154.97
214.24 155.71
215.55 155.20
215.65 156.01
216.28 156.16
216.55 156.87
216.73 155.56
216.95 156.23
217.25 156.03
217.47 155.46
217.93 155.50
218.26 155.83
218.56 155.04
219.31 154.73
219.97 154.72
220.10 155.61
220.79 154.23
220.87 154.94
221.87 154.64
222.07 154.12
222.58 154.47
222.69 155.02
223.21 154.51
223.24 155.22
223.86 154.54
223.90 155.22
224.48 154.29
224.54 155.04
225.22 154.73
225.28 153.86
225.54 154.13
225.76 154.72
225.84 153.93
226.52 154.23
226.60 154.94
226.98 154.02
227.78 153.89
228.29 154.67
228.62 154.29
229.12 154.90
229.46 154.16
229.83 154.48
230.28 153.54
230.50 154.06
230.91 153.03
231.18 153.63
231.79 153.99
231.97 153.45
232.70 154.86
Code:
### a simple gnuplot peak-finder
# requires gnuplot >=5.2
reset session
FILE = "Spectrum.dat"
set table $Data
plot FILE u 1:2 with table
unset table
ColX=1
ColY=2
# extract all peaks
y2=y1=NaN
set print $Peaks
do for [i=2:|$Data|-1] {
if ( word($Data[i-1],ColY)<word($Data[i],ColY) && word($Data[i+1],ColY)<word($Data[i],ColY) ) \
{ print sprintf("%d %s %s", i, word($Data[i],ColX), word($Data[i],ColY)) }
}
set print
# determine prominence
set print $PeakInfo
do for [i=1:|$Peaks|] {
PeakIndex = int(word($Peaks[i],1))
PeakX = real(word($Data[PeakIndex],ColX))
PeakY = real(word($Data[PeakIndex],ColY))
MinY1 = PeakY
do for [j=PeakIndex+1:|$Data|] { # search for higher peak to the right
if ( word($Data[j],ColY) > PeakY ) { break }
else { MinY1 = word($Data[j],ColY) < MinY1 ? word($Data[j],ColY) : MinY1 }
}
MinY2 = PeakY
do for [j=PeakIndex-1:1:-1] { # search for higher peak to the left
if ( word($Data[j],ColY) > PeakY ) { break }
else { MinY2 = word($Data[j],ColY) < MinY2 ? word($Data[j],ColY) : MinY2 }
}
Prominence = MinY1 > MinY2 ? PeakY-MinY1 : PeakY-MinY2
NormalizedProminence = 100.*Prominence/PeakY
print sprintf("%2 d %6 .1f %6 .1f %6 .2f", i, PeakX, PeakY, NormalizedProminence )
}
set print
# print $PeakInfo
set yrange[150:250]
Threshold = 2.4
set label 1 at graph 0.05, 0.9 sprintf("Threshold: %g",Threshold)
plot $Data u 1:2 w lp pt 7 ps 0.5 lc rgb "red" not, \
$PeakInfo u ($4>Threshold?$2:NaN):3 w p pt 7 lc rgb "blue" not, \
$PeakInfo u ($4>Threshold?$2:NaN):3:2 w labels offset 0,0.8 not, \
$PeakInfo u ($4>Threshold?$2:NaN):3 w impulses lc rgb "black" not
### end of code
Results: (for different thresholds)
It can be done and I was bored enough to do it. I generated the following set of random data:
5191
29375
23222
32118
3185
32355
17173
8734
28850
20811
5956
6950
28560
25770
4630
28272
10035
7209
19428
26187
30784
20326
12865
23288
20924
Plotting the values against their position in the list looks like this:
You can spot the local maxima right away from the graph above. Now I can process the data points storing the two previous values (both x and y coordinates) in temporary variables, when I identify a maximum, I plot the data point:
# Select the columns of your data file that contain x and y data
# (usually 1 and 2 respectively)
xcolumn=0
ycolumn=1
plot "data" u (column(xcolumn)):(column(ycolumn)) w l, \
"data" u (column(0)==0 ? (last2y=column(ycolumn), \
last2x=column(xcolumn), 1/0) : column(0)==1 ? (lasty=column(ycolumn), \
lastx=column(xcolumn), 1/0) : lastx) \
: \
( column(0) < 2 ? 1/0 : (last2y < lasty && \
column(ycolumn) < lasty) ? (value=lasty, last2y=lasty, last2x=lastx, \
lasty=column(ycolumn), lastx=column(xcolumn), value) : (last2y=lasty, \
last2x=lastx, lasty=column(ycolumn), lastx=column(xcolumn), 1/0)) pt 7