Plot annotations: FillBetween

Classes used:

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.

Listing 10 Concrete example of a recipe demonstrating some of the ways to add annotations to plot(ter)s, in this case shaded areas below and between curves.
  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.

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).

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:

../_images/plotting-annotation-fillbetween-no-annotation.png

Fig. 35 Plot showing the composite model consisting of two Lorentzians together with the individual components. This is a typical scenario where one would like to add a shading below the curves of the individual components.

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:

../_images/plotting-annotation-fillbetween.png

Fig. 36 Plot with shading of the individual components as annotation. Note that the individual components are plotted explicitly as well, using a aspecd.plotting.MultiPlotter1D.

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:

../_images/plotting-annotation-fillbetween-separate.png

Fig. 37 Plot with both components styled individually. Here, we applied a colour (note the difference between facecolor and edgecolor for this type of annotation) and some transparency.

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:

../_images/plotting-annotation-fillbetween-singleplot.png

Fig. 38 Plot showing only the line of the composite model, annotated with the shaded areas of the indivual components.

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:

../_images/plotting-annotation-fillbetween-baseline.png

Fig. 39 Data with a baseline added, together with the baseline. A bit of styling is applied here, to show that the baseline is just an addition, not the actual data of interest.

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:

../_images/plotting-annotation-fillbetween-with-baseline.png

Fig. 40 Data with baseline together with the individual components, but respecting the baseline as (in this case lower) boundary of the fill patch.