Skip to content

Commit 882ee6c

Browse files
committed
release 0.10.0
2 parents 38c7d7d + 3d8606e commit 882ee6c

46 files changed

Lines changed: 3404 additions & 298 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.git-blame-ignore-revs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# First black run
22
e87fcdc29cfcce7b9f45510fa19792c4235d3cc4
3-
3+
# Next concerted black run
4+
f11ad88212493f9e93f34106962b1bad7f383f27

.package_config.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package:
2+
name: 'aspecd'
3+
author: 'Till Biskup'
4+
author_email: 'till@till-biskup.de'
5+
year: '2018-24'
6+
description: 'Framework for handling spectroscopic data..'
7+
urls:
8+
main: 'https://www.aspecd.de/'
9+
documentation: 'https://docs.aspecd.de/'
10+
source: 'https://github.com/tillbiskup/aspecd'
11+
keywords: [
12+
'spectroscopy',
13+
'data processing and analysis',
14+
'reproducible science',
15+
'reproducible research',
16+
'good scientific practice',
17+
'recipe-driven data analysis',
18+
]
19+
install_requires: [
20+
'jinja2>=3.0',
21+
'matplotlib',
22+
'numpy',
23+
'scipy>=0.14',
24+
'oyaml',
25+
'asdf',
26+
'bibrecord',
27+
]
28+
license: BSD
29+
documentation:
30+
logo: 'aspecd-logo.png'
31+
favicon: 'favicon.ico'
32+
language: en
33+
options:
34+
logging: true
35+
git: true
36+
gui: false

.prospector.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
autodetect: false
55

6+
ignore-paths:
7+
- build
8+
69
inherits:
710
- strictness_high
811

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.9.2
1+
0.10.0

aspecd/analysis.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,6 @@
216216
217217
"""
218218

219-
220219
import copy
221220

222221
import numpy as np

aspecd/annotation.py

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,18 @@
8181
8282
Add horizontal line(s) to a plot(ter).
8383
84+
* :class:`aspecd.annotation.Text`
85+
86+
Add text(s) to a plot(ter).
87+
8488
8589
Module documentation
8690
====================
8791
8892
"""
8993

94+
import numpy as np
95+
9096
import aspecd.exceptions
9197
import aspecd.history
9298
import aspecd.plotting
@@ -832,3 +838,221 @@ def _perform_task(self):
832838
else:
833839
line = self.plotter.ax.axhline(y=position)
834840
self.drawings.append(line)
841+
842+
843+
class Text(PlotAnnotation):
844+
"""
845+
Text added to a plot.
846+
847+
One of the most versatile ways to annotate a plot is adding text labels
848+
at defined positions. Basically, this class is the ASpecD wrapper to
849+
:meth:`matplotlib.axes.Axes.text`. Basically, you provide coordinates
850+
(*x*, *y*) for the location and a text label. By default, coordinates
851+
are data coordinates and specify the bottom left corner of the text.
852+
853+
The properties of the texts can be controlled in quite some detail using
854+
the :attr:`properties` property. Note that all texts will share the same
855+
properties. If you need to add texts with different properties to the
856+
same plot, use several :class:`Text` objects and annotate separately.
857+
858+
859+
Attributes
860+
----------
861+
parameters : :class:`dict`
862+
All parameters necessary for the annotation, implicit and explicit
863+
864+
The following keys exist:
865+
866+
positions : :class:`list`
867+
List of the positions texts should appear at.
868+
869+
Note that each position is itself a list: [*x*, *y*]
870+
871+
Values are in axis (data) units.
872+
873+
xpositions : :class:`list`
874+
List of the *x* positions texts should appear at.
875+
876+
This allows to set *x* positions from the result of other tasks,
877+
*e.g.* a peak finding analysis step.
878+
879+
If ``xpositions`` is set, you need to set ``ypositions`` as well.
880+
However, you can set either a single element or even a scalar
881+
(not a list). In this case, the single *y* position is expanded
882+
to match the number of *x* positions, *i.e.*, all texts will
883+
appear with the same *y* position.
884+
885+
If you provide both, ``positions`` and
886+
``xpositions``/``ypositions``, the latter couple wins.
887+
888+
Values are in axis (data) units.
889+
890+
ypositions : :class:`list` or :class:`float`
891+
List of the *y* positions texts should appear at.
892+
893+
If ``xpositions`` is set, you need to set ``ypositions`` as well.
894+
However, you can set either a single element or even a scalar
895+
(not a list). In this case, the single *y* position is expanded
896+
to match the number of *x* positions, *i.e.*, all texts will
897+
appear with the same *y* position.
898+
899+
If you provide both, ``positions`` and
900+
``xpositions``/``ypositions``, the latter couple wins.
901+
902+
Values are in axis (data) units.
903+
904+
texts : :class:`list`
905+
Texts that should appear at the individual positions.
906+
907+
Each text is a :class:`str`, obviously.
908+
909+
properties : :class:`aspecd.plotting.TextProperties`
910+
Properties of the text(s) within a plot
911+
912+
For the properties that can be set this way, see the documentation
913+
of the :class:`aspecd.plotting.TextProperties` class.
914+
915+
Examples
916+
--------
917+
For convenience, a series of examples in recipe style (for details of
918+
the recipe-driven data analysis, see :mod:`aspecd.tasks`) is given below
919+
for how to make use of this class. The examples focus each on a single
920+
aspect.
921+
922+
Generally and for obvious reasons, you need to have both, a plot task
923+
and a plotannotation task. It does not really matter which task you
924+
define first, the plot or the plot annotation. There are only marginal
925+
differences, and both ways are shown below.
926+
927+
.. code-block:: yaml
928+
929+
- kind: singleplot
930+
type: SinglePlotter1D
931+
properties:
932+
filename: plot1D.pdf
933+
result: plot1D
934+
935+
- kind: plotannotation
936+
type: Text
937+
properties:
938+
parameters:
939+
positions:
940+
- [0.5, 0.5]
941+
- [1.0, 0.5]
942+
texts:
943+
- "Lorem ipsum"
944+
- "dolor sit amet"
945+
properties:
946+
color: green
947+
fontsize: large
948+
fontstyle: oblique
949+
rotation: 30
950+
plotter: plot1D
951+
952+
953+
In this case, the plotter is defined first, and the annotation second.
954+
To refer to the plotter from within the plotannotation task, you need to
955+
set the ``result`` attribute in the plotting task and refer to it within
956+
the ``plotter`` attribute of the plotannotation task. Although defining
957+
the plotter before the annotation, the user still expects the annotation
958+
to be included in the file containing the actual plot, despite the fact
959+
that the figure has been saved (for the first time) before the
960+
annotation has been added.
961+
962+
Sometimes, it might be convenient to go the other way round and first
963+
define an annotation and afterwards add it to a plot(ter). This can be
964+
done as well:
965+
966+
.. code-block:: yaml
967+
968+
- kind: plotannotation
969+
type: Text
970+
properties:
971+
parameters:
972+
positions:
973+
- [0.5, 0.5]
974+
- [1.0, 0.5]
975+
texts:
976+
- "Lorem ipsum"
977+
- "dolor sit amet"
978+
properties:
979+
color: green
980+
fontsize: large
981+
fontstyle: oblique
982+
rotation: 30
983+
result: text
984+
985+
- kind: singleplot
986+
type: SinglePlotter1D
987+
properties:
988+
filename: plot1D.pdf
989+
annotations:
990+
- text
991+
992+
993+
In this way, you can add the same annotation to several plots,
994+
and be sure that each annotation is handled as a separate object.
995+
996+
Suppose you have more than one plotter you want to apply an annotation
997+
to. In this case, the ``plotter`` property of the plotannotation task is
998+
a list rather than a string:
999+
1000+
.. code-block:: yaml
1001+
1002+
- kind: singleplot
1003+
type: SinglePlotter1D
1004+
result: plot1
1005+
1006+
- kind: singleplot
1007+
type: SinglePlotter1D
1008+
result: plot2
1009+
1010+
- kind: plotannotation
1011+
type: Text
1012+
properties:
1013+
parameters:
1014+
positions:
1015+
- [0.5, 0.5]
1016+
- [1.0, 0.5]
1017+
texts:
1018+
- "Lorem ipsum"
1019+
- "dolor sit amet"
1020+
plotter:
1021+
- plot1
1022+
- plot2
1023+
1024+
In this case, the annotation will be applied to both plots
1025+
independently. Note that the example has been reduced to the key
1026+
aspects. In a real situation, the two plotters will differ much more.
1027+
1028+
1029+
.. versionadded:: 0.10
1030+
1031+
"""
1032+
1033+
def __init__(self):
1034+
super().__init__()
1035+
self.parameters["positions"] = []
1036+
self.parameters["xpositions"] = []
1037+
self.parameters["ypositions"] = []
1038+
self.parameters["texts"] = []
1039+
self.properties = aspecd.plotting.TextProperties()
1040+
1041+
def _perform_task(self):
1042+
if self.parameters["xpositions"] and self.parameters["ypositions"]:
1043+
xpositions = self.parameters["xpositions"]
1044+
ypositions = self.parameters["ypositions"]
1045+
if np.isscalar(ypositions):
1046+
ypositions = [ypositions] * len(xpositions)
1047+
if len(ypositions) == 1:
1048+
ypositions = ypositions * len(xpositions)
1049+
positions = []
1050+
for idx, xposition in enumerate(xpositions):
1051+
positions.append([xposition, ypositions[idx]])
1052+
else:
1053+
positions = self.parameters["positions"]
1054+
for idx, position in enumerate(positions):
1055+
text = self.plotter.ax.text(
1056+
position[0], position[1], self.parameters["texts"][idx]
1057+
)
1058+
self.drawings.append(text)

aspecd/io.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ class may look like the following::
337337
====================
338338
339339
"""
340+
340341
import copy
341342
import io
342343
import logging

0 commit comments

Comments
 (0)