Plot annotations: FillBetween
Classes used:
Models:
Processing:
Plotting:
Annotations:
Graphical representation of data and results is one of the most important aspects of presenting scientific results. A good figure is a figure allowing the reader to immediately catch the important aspects, not relying on reading the (nevertheless always important) caption with more description.
To this end, there is the frequent need to annotate figures, i.e. add additional lines, areas, or even text. This is what can be done with the concrete subclasses of aspecd.annotation.PlotAnnotation
.
Here, we focus on filling areas below or between curves that can be used, e.g., to highlight individual components. Suppose you have fitted a spectral line with a series of Lorentzians, and you would like to show the individual components as shaded areas. That’s exactly what aspecd.annotation.FillBetween
is designed for.
Recipe
Shown below is the entire recipe. As this is quite lengthy, separate parts will be detailed below in the “Results” section.
1format:
2 type: ASpecD recipe
3 version: '0.3'
4
5settings:
6 autosave_plots: False
7
8tasks:
9 - kind: model
10 type: Zeros
11 properties:
12 parameters:
13 shape: 1001
14 range: [0, 20]
15 result: dummy
16
17 - kind: model
18 type: Lorentzian
19 from_dataset: dummy
20 properties:
21 parameters:
22 position: 5
23 width: 0.8
24 result: lorentzian1
25
26 - kind: model
27 type: Lorentzian
28 from_dataset: dummy
29 properties:
30 parameters:
31 position: 8
32 width: 2
33 result: lorentzian2
34
35 - kind: model
36 type: CompositeModel
37 from_dataset: dummy
38 properties:
39 models:
40 - Lorentzian
41 - Lorentzian
42 parameters:
43 - position: 5
44 width: 0.8
45 - position: 8
46 width: 2
47 result: model_data
48
49 - kind: multiplot
50 type: MultiPlotter1D
51 properties:
52 properties:
53 axes:
54 xlabel: "$position$ / a.u."
55 xlim: [0, 20]
56 ylim: [0, 1.45]
57 drawings:
58 - linewidth: 1.5
59 color: black
60 - linewidth: 1
61 color: gray
62 - linewidth: 1
63 color: gray
64 parameters:
65 tight_layout: True
66 filename: plotting-annotation-fillbetween-no-annotation.pdf
67 apply_to:
68 - model_data
69 - lorentzian1
70 - lorentzian2
71 comment: >
72 Plotter showing just the model.
73
74 - kind: multiplot
75 type: MultiPlotter1D
76 properties:
77 properties:
78 axes:
79 xlabel: "$position$ / a.u."
80 xlim: [0, 20]
81 ylim: [0, 1.45]
82 parameters:
83 tight_layout: True
84 filename: plotting-annotation-fillbetween.pdf
85 apply_to:
86 - model_data
87 - lorentzian1
88 - lorentzian2
89 result: plot-with-fillbetween
90 comment: >
91 Plotter showing the model and the two coloured surfaces.
92
93 - kind: plotannotation
94 type: FillBetween
95 properties:
96 parameters:
97 data:
98 - lorentzian1
99 - lorentzian2
100 plotter: plot-with-fillbetween
101 comment: >
102 Coloured surfaces of the Lorentzians with default properties.
103
104 - kind: multiplot
105 type: MultiPlotter1D
106 properties:
107 properties:
108 axes:
109 xlabel: "$position$ / a.u."
110 xlim: [0, 20]
111 ylim: [0, 1.45]
112 parameters:
113 tight_layout: True
114 filename: plotting-annotation-fillbetween-separate.pdf
115 apply_to:
116 - model_data
117 - lorentzian1
118 - lorentzian2
119 result: plot-with-fillbetween-separate
120 comment: >
121 Plotter showing the model and the two coloured surfaces separately styled.
122
123 - kind: plotannotation
124 type: FillBetween
125 properties:
126 parameters:
127 data:
128 - lorentzian1
129 properties:
130 facecolor: orange
131 alpha: 0.3
132 plotter: plot-with-fillbetween-separate
133 result: fillbetween-lorentzian1
134 comment: >
135 Coloured surfaces of the first Lorentzian.
136
137 - kind: plotannotation
138 type: FillBetween
139 properties:
140 parameters:
141 data:
142 - lorentzian2
143 properties:
144 facecolor: green
145 alpha: 0.3
146 plotter: plot-with-fillbetween-separate
147 result: fillbetween-lorentzian2
148 comment: >
149 Coloured surfaces of the second Lorentzian.
150
151 - kind: singleplot
152 type: SinglePlotter1D
153 properties:
154 properties:
155 axes:
156 xlabel: "$position$ / a.u."
157 xlim: [0, 20]
158 ylim: [0, 1.45]
159 parameters:
160 tight_layout: True
161 filename: plotting-annotation-fillbetween-singleplot.pdf
162 apply_to:
163 - model_data
164 annotations:
165 - fillbetween-lorentzian1
166 - fillbetween-lorentzian2
167 comment: >
168 Plotter showing the model and the two coloured surfaces marking the components.
169
170 - kind: model
171 type: Polynomial
172 from_dataset: dummy
173 properties:
174 parameters:
175 coefficients: [0.1, 0.01]
176 result: baseline
177
178 - kind: processing
179 type: DatasetAlgebra
180 properties:
181 parameters:
182 kind: add
183 dataset: baseline
184 apply_to: model_data
185 result: model_data_with_baseline
186
187 - kind: processing
188 type: DatasetAlgebra
189 properties:
190 parameters:
191 kind: add
192 dataset: baseline
193 apply_to: lorentzian1
194 result: lorentzian1_with_baseline
195
196 - kind: processing
197 type: DatasetAlgebra
198 properties:
199 parameters:
200 kind: add
201 dataset: baseline
202 apply_to: lorentzian2
203 result: lorentzian2_with_baseline
204
205 - kind: multiplot
206 type: MultiPlotter1D
207 properties:
208 properties:
209 axes:
210 xlabel: "$position$ / a.u."
211 xlim: [0, 20]
212 drawings:
213 - color: black
214 linewidth: 1.5
215 - color: gray
216 linewidth: 1
217 parameters:
218 tight_layout: True
219 filename: plotting-annotation-fillbetween-baseline.pdf
220 apply_to:
221 - model_data_with_baseline
222 - baseline
223
224 - kind: plotannotation
225 type: FillBetween
226 properties:
227 parameters:
228 data:
229 - lorentzian1_with_baseline
230 second:
231 - baseline
232 properties:
233 facecolor: orange
234 alpha: 0.3
235 result: fillbetween-lorentzian1_with_baseline
236 comment: >
237 Coloured surfaces of the first Lorentzian.
238
239 - kind: plotannotation
240 type: FillBetween
241 properties:
242 parameters:
243 data:
244 - lorentzian2_with_baseline
245 second:
246 - baseline
247 properties:
248 facecolor: green
249 alpha: 0.3
250 result: fillbetween-lorentzian2_with_baseline
251 comment: >
252 Coloured surfaces of the second Lorentzian.
253
254 - kind: singleplot
255 type: SinglePlotter1D
256 properties:
257 properties:
258 axes:
259 xlabel: "$position$ / a.u."
260 xlim: [0, 20]
261 parameters:
262 tight_layout: True
263 filename: plotting-annotation-fillbetween-with-baseline.pdf
264 apply_to:
265 - model_data_with_baseline
266 annotations:
267 - fillbetween-lorentzian1_with_baseline
268 - fillbetween-lorentzian2_with_baseline
269 comment: >
270 Plotter showing the model and the two coloured surfaces
271 marking the components, but limited by the baseline.
Results
Examples for the figures created in the recipe are given below. While in the recipe, the output format has been set to PDF, for rendering them here they have been converted to PNG.
As this is a rather lengthy recipe demonstrating different scenarios, the individual cases are shown separately, each with the corresponding section of the recipe.
Setting the scene
The scenario: We have a curve comprising of two overlapping Lorentzians and want to highlight the individual components. Here, we just plot the data and the individual components.
49 - kind: multiplot
50 type: MultiPlotter1D
51 properties:
52 properties:
53 axes:
54 xlabel: "$position$ / a.u."
55 xlim: [0, 20]
56 ylim: [0, 1.45]
57 drawings:
58 - linewidth: 1.5
59 color: black
60 - linewidth: 1
61 color: gray
62 - linewidth: 1
63 color: gray
64 parameters:
65 tight_layout: True
66 filename: plotting-annotation-fillbetween-no-annotation.pdf
67 apply_to:
68 - model_data
69 - lorentzian1
70 - lorentzian2
71 comment: >
72 Plotter showing just the model.
The resulting figure is shown below:
FillBetween with default settings
The scenario is as described above: We have a curve comprising of two overlapping Lorentzians and want to highlight the individual components. To fill the area below the curves of the individual components, we can use a aspecd.annotation.FillBetween
annotation.
74 - kind: multiplot
75 type: MultiPlotter1D
76 properties:
77 properties:
78 axes:
79 xlabel: "$position$ / a.u."
80 xlim: [0, 20]
81 ylim: [0, 1.45]
82 parameters:
83 tight_layout: True
84 filename: plotting-annotation-fillbetween.pdf
85 apply_to:
86 - model_data
87 - lorentzian1
88 - lorentzian2
89 result: plot-with-fillbetween
90 comment: >
91 Plotter showing the model and the two coloured surfaces.
92
93 - kind: plotannotation
94 type: FillBetween
95 properties:
96 parameters:
97 data:
98 - lorentzian1
99 - lorentzian2
100 plotter: plot-with-fillbetween
101 comment: >
102 Coloured surfaces of the Lorentzians with default properties.
The resulting figure is shown below:
The default settings are most probably not exactly what we usually want to have. First of all, individual components should often been marked with different colours, and adding a bit of transparency may help as well. Off we go.
Individual annotations with styling
In the example above, we have shown the default styling of the aspecd.annotation.FillBetween
annotation. As this is not quite what we usually would like to see, here, we apply some styling. For details of the parameters you can set, have a look at aspecd.plotting.PatchProperties
.
104 - kind: multiplot
105 type: MultiPlotter1D
106 properties:
107 properties:
108 axes:
109 xlabel: "$position$ / a.u."
110 xlim: [0, 20]
111 ylim: [0, 1.45]
112 parameters:
113 tight_layout: True
114 filename: plotting-annotation-fillbetween-separate.pdf
115 apply_to:
116 - model_data
117 - lorentzian1
118 - lorentzian2
119 result: plot-with-fillbetween-separate
120 comment: >
121 Plotter showing the model and the two coloured surfaces separately styled.
122
123 - kind: plotannotation
124 type: FillBetween
125 properties:
126 parameters:
127 data:
128 - lorentzian1
129 properties:
130 facecolor: orange
131 alpha: 0.3
132 plotter: plot-with-fillbetween-separate
133 result: fillbetween-lorentzian1
134 comment: >
135 Coloured surfaces of the first Lorentzian.
136
137 - kind: plotannotation
138 type: FillBetween
139 properties:
140 parameters:
141 data:
142 - lorentzian2
143 properties:
144 facecolor: green
145 alpha: 0.3
146 plotter: plot-with-fillbetween-separate
147 result: fillbetween-lorentzian2
148 comment: >
149 Coloured surfaces of the second Lorentzian.
The resulting figure is shown below:
Individual annotations in a SinglePlotter
Quite similar to the situation above, we need not use a aspecd.plotting.MultiPlotter
to show the individual components, as the annotation would be sufficient. Note that we stored the annotations for the individual lines declared above using the result
key, so that we can reuse them here.
151 - kind: singleplot
152 type: SinglePlotter1D
153 properties:
154 properties:
155 axes:
156 xlabel: "$position$ / a.u."
157 xlim: [0, 20]
158 ylim: [0, 1.45]
159 parameters:
160 tight_layout: True
161 filename: plotting-annotation-fillbetween-singleplot.pdf
162 apply_to:
163 - model_data
164 annotations:
165 - fillbetween-lorentzian1
166 - fillbetween-lorentzian2
167 comment: >
168 Plotter showing the model and the two coloured surfaces marking the components.
The resulting figure is shown below:
Data with baseline
By default, and if not providing a second line, the patch extends from zero to the data points given by the actual data of the curve. While you could set a scalar value different from zero, more often you will encounter baselines, at least in spectroscopy and in real life. Here, we first (re)create the same data as above, but this time with a baseline added. To add the baseline to both, the model data and the individual components, we use the aspecd.processing.DatasetAlgebra
processing step. Afterwards, the data with baseline are plotted together with the baseline.
170 - kind: model
171 type: Polynomial
172 from_dataset: dummy
173 properties:
174 parameters:
175 coefficients: [0.1, 0.01]
176 result: baseline
177
178 - kind: processing
179 type: DatasetAlgebra
180 properties:
181 parameters:
182 kind: add
183 dataset: baseline
184 apply_to: model_data
185 result: model_data_with_baseline
186
187 - kind: processing
188 type: DatasetAlgebra
189 properties:
190 parameters:
191 kind: add
192 dataset: baseline
193 apply_to: lorentzian1
194 result: lorentzian1_with_baseline
195
196 - kind: processing
197 type: DatasetAlgebra
198 properties:
199 parameters:
200 kind: add
201 dataset: baseline
202 apply_to: lorentzian2
203 result: lorentzian2_with_baseline
204
205 - kind: multiplot
206 type: MultiPlotter1D
207 properties:
208 properties:
209 axes:
210 xlabel: "$position$ / a.u."
211 xlim: [0, 20]
212 drawings:
213 - color: black
214 linewidth: 1.5
215 - color: gray
216 linewidth: 1
217 parameters:
218 tight_layout: True
219 filename: plotting-annotation-fillbetween-baseline.pdf
220 apply_to:
221 - model_data_with_baseline
222 - baseline
The resulting figure is shown below:
Filling between two curves
Having data with a baseline, this is finally a sensible real-world situation where you may want to provide a second dataset as boundary for the patch. Of course, other typical scenarios are marking the confidence interval of a fit, where you have the lower and upper boundaries as dataset.
224 - kind: plotannotation
225 type: FillBetween
226 properties:
227 parameters:
228 data:
229 - lorentzian1_with_baseline
230 second:
231 - baseline
232 properties:
233 facecolor: orange
234 alpha: 0.3
235 result: fillbetween-lorentzian1_with_baseline
236 comment: >
237 Coloured surfaces of the first Lorentzian.
238
239 - kind: plotannotation
240 type: FillBetween
241 properties:
242 parameters:
243 data:
244 - lorentzian2_with_baseline
245 second:
246 - baseline
247 properties:
248 facecolor: green
249 alpha: 0.3
250 result: fillbetween-lorentzian2_with_baseline
251 comment: >
252 Coloured surfaces of the second Lorentzian.
253
254 - kind: singleplot
255 type: SinglePlotter1D
256 properties:
257 properties:
258 axes:
259 xlabel: "$position$ / a.u."
260 xlim: [0, 20]
261 parameters:
262 tight_layout: True
263 filename: plotting-annotation-fillbetween-with-baseline.pdf
264 apply_to:
265 - model_data_with_baseline
266 annotations:
267 - fillbetween-lorentzian1_with_baseline
268 - fillbetween-lorentzian2_with_baseline
269 comment: >
270 Plotter showing the model and the two coloured surfaces
271 marking the components, but limited by the baseline.
The resulting figure is shown below:
Comments
As usual, a model dataset is created at the beginning, to have something to show. Here, a CompositeModel comprising of two Lorentizans is used to get two peaks that can be labelled.
Furthermore, the individual Lorentzians are created as well.
For simplicity, generic plotters are used, to focus on the annotations.
The sequence of defining plot and annotation(s) does not matter. You only need to provide the
result
key with a unique name for whichever task you define first, to refer to it in the later task(s).