• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenCOMPES / sed / 6851839863

13 Nov 2023 03:07PM UTC coverage: 90.391% (-0.04%) from 90.428%
6851839863

Pull #261

github

web-flow
Update linting.yml
Pull Request #261: Make linting work for tests folder

4920 of 5443 relevant lines covered (90.39%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.93
/sed/binning/utils.py
1
"""This file contains helper functions for the sed.binning module
2

3
"""
4
from typing import cast
1✔
5
from typing import List
1✔
6
from typing import Sequence
1✔
7
from typing import Tuple
1✔
8
from typing import Union
1✔
9

10
import numpy as np
1✔
11

12

13
def _arraysum(array_a, array_b):
1✔
14
    """Calculate the sum of two arrays."""
15
    return array_a + array_b
×
16

17

18
def simplify_binning_arguments(
1✔
19
    bins: Union[
20
        int,
21
        dict,
22
        Sequence[int],
23
        Sequence[np.ndarray],
24
        Sequence[tuple],
25
    ],
26
    axes: Sequence[str] = None,
27
    ranges: Sequence[Tuple[float, float]] = None,
28
) -> Tuple[Union[List[int], List[np.ndarray]], List[str], List[Tuple[float, float]]]:
29
    """Convert the flexible input for defining bins into a
30
    simple "axes" "bins" "ranges" tuple.
31

32
    This allows to mimic the input used in numpy.histogramdd flexibility into the
33
    binning functions defined here.
34

35
    Args:
36
        bins (int, dict, Sequence[int], Sequence[np.ndarray], Sequence[tuple]):
37
            Definition of the bins. Can  be any of the following cases:
38

39
                - an integer describing the number of bins for all dimensions. This
40
                  requires "ranges" to be defined as well.
41
                - A sequence containing one entry of the following types for each
42
                  dimenstion:
43

44
                    - an integer describing the number of bins. This requires "ranges"
45
                      to be defined as well.
46
                    - a np.arrays defining the bin centers
47
                    - a tuple of 3 numbers describing start, end and step of the binning
48
                      range.
49

50
                - a dictionary made of the axes as keys and any of the above as
51
                  values.
52

53
            The last option takes priority over the axes and range arguments.
54
        axes (Sequence[str], optional): Sequence containing the names of
55
            the axes (columns) on which to calculate the histogram. The order will be
56
            the order of the dimensions in the resulting array. Only not required if
57
            bins are provided as dictionary containing the axis names.
58
            Defaults to None.
59
        ranges (Sequence[Tuple[float, float]], optional): Sequence of tuples containing
60
            the start and end point of the binning range. Required if bins given as
61
            int or Sequence[int]. Defaults to None.
62

63
    Raises:
64
        ValueError: Wrong shape of bins,
65
        TypeError: Wrong type of bins
66
        AttributeError: Axes not defined
67
        AttributeError: Shape mismatch
68

69
    Returns:
70
        Tuple[Union[List[int], List[np.ndarray]], List[Tuple[float, float]]]: Tuple
71
        containing lists of bin centers, axes, and ranges.
72
    """
73
    # if bins is a dictionary: unravel to axes and bins
74
    if isinstance(bins, dict):
1✔
75
        axes = []
1✔
76
        bins_ = []
1✔
77
        for k, v in bins.items():
1✔
78
            axes.append(k)
1✔
79
            bins_.append(v)
1✔
80
        bins = bins_
1✔
81

82
    # if bins provided as single int, apply to all dimensions
83
    if isinstance(bins, (int, np.int64)):
1✔
84
        bins = [bins] * len(axes)
1✔
85

86
    # Check that we have a sequence of bins now
87
    if not isinstance(bins, Sequence):
1✔
88
        raise TypeError(f"Cannot interpret bins of type {type(bins)}")
×
89

90
    # check that we have axes
91
    if axes is None:
1✔
92
        raise AttributeError("Must define on which axes to bin")
×
93

94
    # check that axes is a sequence
95
    if not isinstance(axes, Sequence):
1✔
96
        raise TypeError(f"Cannot interpret axes of type {type(axes)}")
×
97

98
    # check that all elements of axes are str
99
    if not all(isinstance(axis, str) for axis in axes):
1✔
100
        raise TypeError("Axes has to contain only strings!")
×
101

102
    # we got tuples as bins, expand to bins and ranges
103
    if all(isinstance(x, tuple) for x in bins):
1✔
104
        bins = cast(Sequence[tuple], bins)
1✔
105
        assert len(bins[0]) == 3, "Tuples as bins need to have format (start, end, num_bins)."
1✔
106
        ranges = []
1✔
107
        bins_ = []
1✔
108
        for tpl in bins:
1✔
109
            assert isinstance(tpl, tuple)
1✔
110
            ranges.append((tpl[0], tpl[1]))
1✔
111
            bins_.append(tpl[2])
1✔
112
        bins = bins_
1✔
113

114
    # if bins are provided as int, check that ranges are present
115
    if all(isinstance(x, (int, np.int64)) for x in bins):
1✔
116
        bins = cast(List[int], list(bins))
1✔
117
        if ranges is None:
1✔
118
            raise AttributeError(
×
119
                "Must provide a range if bins is an integer or list of integers",
120
            )
121
        if not isinstance(ranges, Sequence):
1✔
122
            raise AttributeError(
×
123
                f"Ranges must be a sequence, not {type(ranges)}.",
124
            )
125

126
    # otherwise, all bins should by np.ndarrays here
127
    elif all(isinstance(x, np.ndarray) for x in bins):
1✔
128
        bins = cast(List[np.ndarray], list(bins))
1✔
129
    else:
130
        raise TypeError(f"Could not interpret bins of type {type(bins)}")
×
131

132
    # check that number of bins and number of axes is the same.
133
    if len(axes) != len(bins):
1✔
134
        raise AttributeError(
×
135
            "axes and bins must have the same number of elements",
136
        )
137

138
    return bins, list(axes), list(ranges) if ranges else None
1✔
139

140

141
def bin_edges_to_bin_centers(bin_edges: np.ndarray) -> np.ndarray:
1✔
142
    """Converts a list of bin edges into corresponding bin centers
143

144
    Args:
145
        bin_edges: 1d array of bin edges
146

147
    Returns:
148
        bin_centers: 1d array of bin centers
149
    """
150
    bin_centers = (bin_edges[1:] + bin_edges[:-1]) / 2
1✔
151

152
    return bin_centers
1✔
153

154

155
def bin_centers_to_bin_edges(bin_centers: np.ndarray) -> np.ndarray:
1✔
156
    """Converts a list of bin centers into corresponding bin edges
157

158
    Args:
159
        bin_centers: 1d array of bin centers
160

161
    Returns:
162
        bin_edges: 1d array of bin edges
163
    """
164
    bin_edges = (bin_centers[1:] + bin_centers[:-1]) / 2
1✔
165

166
    bin_edges = np.insert(
1✔
167
        bin_edges,
168
        0,
169
        bin_centers[0] - (bin_centers[1] - bin_centers[0]) / 2,
170
    )
171
    bin_edges = np.append(
1✔
172
        bin_edges,
173
        bin_centers[len(bin_centers) - 1]
174
        + (bin_centers[len(bin_centers) - 1] - bin_centers[len(bin_centers) - 2]) / 2,
175
    )
176

177
    return bin_edges
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc