Skip to content

Extra Functions

Cmap #

Class to create a colormap with a given name and range. The colormap can be called with a value between 0 and 1 to get the corresponding rgb value.

Source code in src/CompNeuroPy/extra_functions.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class Cmap:
    """
    Class to create a colormap with a given name and range. The colormap can be called
    with a value between 0 and 1 to get the corresponding rgb value.
    """

    def __init__(self, cmap_name, vmin, vmax):
        """
        Args:
            cmap_name (str):
                Name of the colormap
            vmin (float):
                Lower limit of the colormap
            vmax (float):
                Upper limit of the colormap
        """
        self.cmap_name = cmap_name
        self.cmap = plt.get_cmap(cmap_name)
        self.norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
        self.scalarMap = cm.ScalarMappable(norm=self.norm, cmap=self.cmap)

    def __call__(self, x, alpha=1):
        """
        Returns the rgba value of the colormap at the given value.

        Args:
            x (float):
                Value between 0 and 1
            alpha (float):
                Alpha value of the rgba value

        Returns:
            rgba (tuple):
                RGBA value of the colormap at the given value
        """
        vals = self.get_rgb(x)
        if isinstance(vals, tuple):
            vals = vals[:3] + (alpha,)
        else:
            vals[:, -1] = alpha
        return vals

    def get_rgb(self, val):
        """
        Returns the rgb value of the colormap at the given value.

        Args:
            val (float):
                Value between 0 and 1

        Returns:
            rgb (tuple):
                RGB value of the colormap at the given value
        """
        return self.scalarMap.to_rgba(val)

__init__(cmap_name, vmin, vmax) #

Parameters:

Name Type Description Default
cmap_name str

Name of the colormap

required
vmin float

Lower limit of the colormap

required
vmax float

Upper limit of the colormap

required
Source code in src/CompNeuroPy/extra_functions.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def __init__(self, cmap_name, vmin, vmax):
    """
    Args:
        cmap_name (str):
            Name of the colormap
        vmin (float):
            Lower limit of the colormap
        vmax (float):
            Upper limit of the colormap
    """
    self.cmap_name = cmap_name
    self.cmap = plt.get_cmap(cmap_name)
    self.norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
    self.scalarMap = cm.ScalarMappable(norm=self.norm, cmap=self.cmap)

__call__(x, alpha=1) #

Returns the rgba value of the colormap at the given value.

Parameters:

Name Type Description Default
x float

Value between 0 and 1

required
alpha float

Alpha value of the rgba value

1

Returns:

Name Type Description
rgba tuple

RGBA value of the colormap at the given value

Source code in src/CompNeuroPy/extra_functions.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def __call__(self, x, alpha=1):
    """
    Returns the rgba value of the colormap at the given value.

    Args:
        x (float):
            Value between 0 and 1
        alpha (float):
            Alpha value of the rgba value

    Returns:
        rgba (tuple):
            RGBA value of the colormap at the given value
    """
    vals = self.get_rgb(x)
    if isinstance(vals, tuple):
        vals = vals[:3] + (alpha,)
    else:
        vals[:, -1] = alpha
    return vals

get_rgb(val) #

Returns the rgb value of the colormap at the given value.

Parameters:

Name Type Description Default
val float

Value between 0 and 1

required

Returns:

Name Type Description
rgb tuple

RGB value of the colormap at the given value

Source code in src/CompNeuroPy/extra_functions.py
169
170
171
172
173
174
175
176
177
178
179
180
181
def get_rgb(self, val):
    """
    Returns the rgb value of the colormap at the given value.

    Args:
        val (float):
            Value between 0 and 1

    Returns:
        rgb (tuple):
            RGB value of the colormap at the given value
    """
    return self.scalarMap.to_rgba(val)

DecisionTree #

Class to create a decision tree.

Source code in src/CompNeuroPy/extra_functions.py
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
class DecisionTree:
    """
    Class to create a decision tree.
    """

    def __init__(self):
        """
        Create a new empty decision tree.
        """
        ### node list is a list of lists
        ### first idx = level of tree
        ### second idx = all nodes in the level
        self.node_list = [[]]

    def node(self, parent=None, prob=0, name=None):
        """
        Create a new node in the decision tree.

        Args:
            parent (node object):
                Parent node of the new node
            prob (float):
                Probability of the new node
            name (str):
                Name of the new node

        Returns:
            new_node (node object):
                The new node
        """

        ### create new node
        new_node = DecisionTreeNode(tree=self, parent=parent, prob=prob, name=name)
        ### add it to node_list
        if len(self.node_list) == new_node.level:
            self.node_list.append([])
        self.node_list[new_node.level].append(new_node)
        ### return the node object
        return new_node

    def get_path_prod(self, name):
        """
        Get the path and path product of a node with a given name.

        Args:
            name (str):
                Name of the node

        Returns:
            path (str):
                Path to the node
            path_prod (float):
                Path product of the node
        """

        ### search for all nodes with name
        ### start from behind
        search_node_list = []
        path_list = []
        path_prod_list = []
        for level in range(len(self.node_list) - 1, -1, -1):
            for node in self.node_list[level]:
                if node.name == name:
                    search_node_list.append(node)
        ### get the paths and path products for the found nodes
        for node in search_node_list:
            path, path_prod = self._get_path_prod_rec(node)
            path_list.append(path)
            path_prod_list.append(path_prod)
        ### return the paths and path products
        return [
            [path_list[idx], path_prod_list[idx]]
            for idx in range(len(search_node_list))
        ]

    def _get_path_prod_rec(self, node):
        """
        Recursive function to get the path and path product of a node.

        Args:
            node (node object):
                Node to get the path and path product of

        Returns:
            path_str (str):
                Path to the node
            prob (float):
                Path product of the node
        """
        node: DecisionTreeNode = node

        if node.parent == None:
            return ["/" + node.name, node.prob]
        else:
            path_str, prob = self._get_path_prod_rec(node.parent)
            return [path_str + "/" + node.name, prob * node.prob]

__init__() #

Create a new empty decision tree.

Source code in src/CompNeuroPy/extra_functions.py
355
356
357
358
359
360
361
362
def __init__(self):
    """
    Create a new empty decision tree.
    """
    ### node list is a list of lists
    ### first idx = level of tree
    ### second idx = all nodes in the level
    self.node_list = [[]]

node(parent=None, prob=0, name=None) #

Create a new node in the decision tree.

Parameters:

Name Type Description Default
parent node object

Parent node of the new node

None
prob float

Probability of the new node

0
name str

Name of the new node

None

Returns:

Name Type Description
new_node node object

The new node

Source code in src/CompNeuroPy/extra_functions.py
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
def node(self, parent=None, prob=0, name=None):
    """
    Create a new node in the decision tree.

    Args:
        parent (node object):
            Parent node of the new node
        prob (float):
            Probability of the new node
        name (str):
            Name of the new node

    Returns:
        new_node (node object):
            The new node
    """

    ### create new node
    new_node = DecisionTreeNode(tree=self, parent=parent, prob=prob, name=name)
    ### add it to node_list
    if len(self.node_list) == new_node.level:
        self.node_list.append([])
    self.node_list[new_node.level].append(new_node)
    ### return the node object
    return new_node

get_path_prod(name) #

Get the path and path product of a node with a given name.

Parameters:

Name Type Description Default
name str

Name of the node

required

Returns:

Name Type Description
path str

Path to the node

path_prod float

Path product of the node

Source code in src/CompNeuroPy/extra_functions.py
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
def get_path_prod(self, name):
    """
    Get the path and path product of a node with a given name.

    Args:
        name (str):
            Name of the node

    Returns:
        path (str):
            Path to the node
        path_prod (float):
            Path product of the node
    """

    ### search for all nodes with name
    ### start from behind
    search_node_list = []
    path_list = []
    path_prod_list = []
    for level in range(len(self.node_list) - 1, -1, -1):
        for node in self.node_list[level]:
            if node.name == name:
                search_node_list.append(node)
    ### get the paths and path products for the found nodes
    for node in search_node_list:
        path, path_prod = self._get_path_prod_rec(node)
        path_list.append(path)
        path_prod_list.append(path_prod)
    ### return the paths and path products
    return [
        [path_list[idx], path_prod_list[idx]]
        for idx in range(len(search_node_list))
    ]

DecisionTreeNode #

Class to create a node in a decision tree.

Source code in src/CompNeuroPy/extra_functions.py
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
class DecisionTreeNode:
    """
    Class to create a node in a decision tree.
    """

    id_counter = 0

    def __init__(self, tree: DecisionTree, parent=None, prob=0, name=""):
        """
        Create a new node in a decision tree.

        Args:
            tree (DecisionTree object):
                Decision tree the node belongs to
            parent (node object):
                Parent node of the new node
            prob (float):
                Probability of the new node
            name (str):
                Name of the new node
        """
        self.tree = tree
        parent: DecisionTreeNode = parent
        self.parent = parent
        self.prob = prob
        self.name = name
        self.id = int(self.id_counter)
        self.id_counter += 1
        if parent != None:
            self.level = int(parent.level + 1)
        else:
            self.level = int(0)

    def add(self, name, prob):
        """
        Add a child node to the node.

        Args:
            name (str):
                Name of the new node
            prob (float):
                Probability of the new node

        Returns:
            new_node (node object):
                The new node
        """

        return self.tree.node(parent=self, prob=prob, name=name)

    def get_path_prod(self):
        """
        Get the path and path product of the node.

        Returns:
            path (str):
                Path to the node
            path_prod (float):
                Path product of the node
        """
        return self.tree._get_path_prod_rec(self)

__init__(tree, parent=None, prob=0, name='') #

Create a new node in a decision tree.

Parameters:

Name Type Description Default
tree DecisionTree object

Decision tree the node belongs to

required
parent node object

Parent node of the new node

None
prob float

Probability of the new node

0
name str

Name of the new node

''
Source code in src/CompNeuroPy/extra_functions.py
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
def __init__(self, tree: DecisionTree, parent=None, prob=0, name=""):
    """
    Create a new node in a decision tree.

    Args:
        tree (DecisionTree object):
            Decision tree the node belongs to
        parent (node object):
            Parent node of the new node
        prob (float):
            Probability of the new node
        name (str):
            Name of the new node
    """
    self.tree = tree
    parent: DecisionTreeNode = parent
    self.parent = parent
    self.prob = prob
    self.name = name
    self.id = int(self.id_counter)
    self.id_counter += 1
    if parent != None:
        self.level = int(parent.level + 1)
    else:
        self.level = int(0)

add(name, prob) #

Add a child node to the node.

Parameters:

Name Type Description Default
name str

Name of the new node

required
prob float

Probability of the new node

required

Returns:

Name Type Description
new_node node object

The new node

Source code in src/CompNeuroPy/extra_functions.py
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
def add(self, name, prob):
    """
    Add a child node to the node.

    Args:
        name (str):
            Name of the new node
        prob (float):
            Probability of the new node

    Returns:
        new_node (node object):
            The new node
    """

    return self.tree.node(parent=self, prob=prob, name=name)

get_path_prod() #

Get the path and path product of the node.

Returns:

Name Type Description
path str

Path to the node

path_prod float

Path product of the node

Source code in src/CompNeuroPy/extra_functions.py
502
503
504
505
506
507
508
509
510
511
512
def get_path_prod(self):
    """
    Get the path and path product of the node.

    Returns:
        path (str):
            Path to the node
        path_prod (float):
            Path product of the node
    """
    return self.tree._get_path_prod_rec(self)

print_df(df) #

Prints the complete dataframe df

Parameters:

Name Type Description Default
df pandas dataframe

Dataframe to be printed

required
Source code in src/CompNeuroPy/extra_functions.py
14
15
16
17
18
19
20
21
22
23
24
25
def print_df(df):
    """
    Prints the complete dataframe df

    Args:
        df (pandas dataframe):
            Dataframe to be printed
    """
    with pd.option_context(
        "display.max_rows", None
    ):  # more options can be specified also
        print(df)

flatten_list(lst) #

Retuns flattened list

Parameters:

Name Type Description Default
lst list of lists or mixed

values and lists): List to be flattened

required

Returns:

Name Type Description
new_list list

Flattened list

Source code in src/CompNeuroPy/extra_functions.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def flatten_list(lst):
    """
    Retuns flattened list

    Args:
        lst (list of lists or mixed: values and lists):
            List to be flattened

    Returns:
        new_list (list):
            Flattened list
    """

    ### if lists in lst --> upack them and retunr flatten_list of new list
    new_lst = []
    list_in_lst = False
    for val in lst:
        if isinstance(val, list):
            list_in_lst = True
            for sub_val in val:
                new_lst.append(sub_val)
        else:
            new_lst.append(val)

    if list_in_lst:
        return flatten_list(new_lst)
    ### else return lst
    else:
        return lst

remove_key(d, key) #

Removes an element from a dict, returns the new dict

Parameters:

Name Type Description Default
d dict

Dict to be modified

required
key str

Key to be removed

required

Returns:

Name Type Description
r dict

Modified dict

Source code in src/CompNeuroPy/extra_functions.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def remove_key(d, key):
    """
    Removes an element from a dict, returns the new dict

    Args:
        d (dict):
            Dict to be modified
        key (str):
            Key to be removed

    Returns:
        r (dict):
            Modified dict
    """
    r = dict(d)
    del r[key]
    return r

suppress_stdout() #

Suppresses the print output of a function

Examples:

with suppress_stdout():
    print("this will not be printed")
Source code in src/CompNeuroPy/extra_functions.py
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@contextmanager
def suppress_stdout():
    """
    Suppresses the print output of a function

    Examples:
        ```python
        with suppress_stdout():
            print("this will not be printed")
        ```
    """
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:
            yield
        finally:
            sys.stdout = old_stdout

sci(nr) #

Rounds a number to a single decimal. If number is smaller than 0 it is converted to scientific notation with 1 decimal.

Parameters:

Name Type Description Default
nr float or int

Number to be converted

required

Returns:

Name Type Description
str str

String of the number in scientific notation

Examples:

>>> sci(0.0001)
'1.0e-4'
>>> sci(1.77)
'1.8'
>>> sci(1.77e-5)
'1.8e-5'
>>> sci(177.22)
'177.2'
Source code in src/CompNeuroPy/extra_functions.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def sci(nr):
    """
    Rounds a number to a single decimal.
    If number is smaller than 0 it is converted to scientific notation with 1 decimal.

    Args:
        nr (float or int):
            Number to be converted

    Returns:
        str (str):
            String of the number in scientific notation

    Examples:
        >>> sci(0.0001)
        '1.0e-4'
        >>> sci(1.77)
        '1.8'
        >>> sci(1.77e-5)
        '1.8e-5'
        >>> sci(177.22)
        '177.2'
    """
    if af.get_number_of_zero_decimals(nr) == 0:
        return str(round(nr, 1))
    else:
        return f"{nr*10**af.get_number_of_zero_decimals(nr):.1f}e-{af.get_number_of_zero_decimals(nr)}"

create_cm(colors, name='my_cmap', N=256, gamma=1.0, vmin=0, vmax=1) #

Create a LinearSegmentedColormap from a list of colors.

Parameters:

Name Type Description Default
colors array-like of colors or array-like of (value, color

If only colors are given, they are equidistantly mapped from the range :math:[0, 1]; i.e. 0 maps to colors[0] and 1 maps to colors[-1]. If (value, color) pairs are given, the mapping is from value to color. This can be used to divide the range unevenly.

required
name str

The name of the colormap, by default 'my_cmap'.

'my_cmap'
N int

The number of rgb quantization levels, by default 256.

256
gamma float

Gamma correction value, by default 1.0.

1.0
vmin float

The minimum value of the colormap, by default 0.

0
vmax float

The maximum value of the colormap, by default 1.

1

Returns:

Name Type Description
linear_colormap _LinearColormapClass

The colormap object

Source code in src/CompNeuroPy/extra_functions.py
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
def create_cm(colors, name="my_cmap", N=256, gamma=1.0, vmin=0, vmax=1):
    """
    Create a `LinearSegmentedColormap` from a list of colors.

    Args:
        colors (array-like of colors or array-like of (value, color)):
            If only colors are given, they are equidistantly mapped from the
            range :math:`[0, 1]`; i.e. 0 maps to ``colors[0]`` and 1 maps to
            ``colors[-1]``.
            If (value, color) pairs are given, the mapping is from *value*
            to *color*. This can be used to divide the range unevenly.
        name (str, optional):
            The name of the colormap, by default 'my_cmap'.
        N (int, optional):
            The number of rgb quantization levels, by default 256.
        gamma (float, optional):
            Gamma correction value, by default 1.0.
        vmin (float, optional):
            The minimum value of the colormap, by default 0.
        vmax (float, optional):
            The maximum value of the colormap, by default 1.

    Returns:
        linear_colormap (_LinearColormapClass):
            The colormap object
    """
    if not np.iterable(colors):
        raise ValueError("colors must be iterable")

    if (
        isinstance(colors[0], Sized)
        and len(colors[0]) == 2
        and not isinstance(colors[0], str)
    ):
        # List of value, color pairs
        vals, colors = zip(*colors)
        vals = np.array(vals).astype(float)
        colors = list(colors)
        ### insert values for 0 and 1 if not given
        ### they equal the colors of the borders of the given range
        if vals.min() != 0.0:
            colors = [colors[np.argmin(vals)]] + colors
            vals = np.insert(vals, 0, 0.0)
        if vals.max() != 1.0:
            colors = colors + [colors[np.argmax(vals)]]
            vals = np.insert(vals, len(vals), 1.0)
    else:
        vals = np.linspace(0, 1, len(colors))

    ### sort values and colors, they have to increase
    sort_idx = np.argsort(vals)
    vals = vals[sort_idx]
    colors = [colors[idx] for idx in sort_idx]

    r_g_b_a = np.zeros((len(colors), 4))
    for color_idx, color in enumerate(colors):
        if isinstance(color, str):
            ### color given by name
            r_g_b_a[color_idx] = to_rgba_array(color)
        else:
            ### color given by rgb(maybe a) value
            color = np.array(color).astype(float)
            ### check color size
            if len(color) != 3 and len(color) != 4:
                raise ValueError(
                    "colors must be names or consist of 3 (rgb) or 4 (rgba) numbers"
                )
            if color.max() > 1:
                ### assume that max value is 255
                color[:3] = color[:3] / 255
            if len(color) == 4:
                ### gamma already given
                r_g_b_a[color_idx] = color
            else:
                ### add gamma
                r_g_b_a[color_idx] = np.concatenate([color, np.array([gamma])])
    r = r_g_b_a[:, 0]
    g = r_g_b_a[:, 1]
    b = r_g_b_a[:, 2]
    a = r_g_b_a[:, 3]

    cdict = {
        "red": np.column_stack([vals, r, r]),
        "green": np.column_stack([vals, g, g]),
        "blue": np.column_stack([vals, b, b]),
        "alpha": np.column_stack([vals, a, a]),
    }

    return _LinearColormapClass(name, cdict, N, gamma, vmin, vmax)

evaluate_expression_with_dict(expression, value_dict) #

Evaluate a mathematical expression using values from a dictionary.

This function takes a mathematical expression as a string and a dictionary containing variable names as keys and corresponding values as numpy arrays. It replaces the variable names in the expression with their corresponding values from the dictionary and evaluates the expression.

Parameters:

Name Type Description Default
expression str

A mathematical expression to be evaluated. Variable names in the expression should match the keys in the value_dict.

required
value_dict dict

A dictionary containing variable names (strings) as keys and corresponding numpy arrays or numbers as values.

required

Returns:

Name Type Description
result value or array

The result of evaluating the expression using the provided values.

Examples:

>>> my_dict = {"a": np.ones(10), "b": np.arange(10)}
>>> my_string = "a*2-b+10"
>>> evaluate_expression_with_dict(my_string, my_dict)
array([12., 11., 10.,  9.,  8.,  7.,  6.,  5.,  4.,  3.])
Source code in src/CompNeuroPy/extra_functions.py
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
def evaluate_expression_with_dict(expression, value_dict):
    """
    Evaluate a mathematical expression using values from a dictionary.

    This function takes a mathematical expression as a string and a dictionary
    containing variable names as keys and corresponding values as numpy arrays.
    It replaces the variable names in the expression with their corresponding
    values from the dictionary and evaluates the expression.

    Args:
        expression (str):
            A mathematical expression to be evaluated. Variable
            names in the expression should match the keys in the value_dict.
        value_dict (dict):
            A dictionary containing variable names (strings) as
            keys and corresponding numpy arrays or numbers as values.

    Returns:
        result (value or array):
            The result of evaluating the expression using the provided values.

    Examples:
        >>> my_dict = {"a": np.ones(10), "b": np.arange(10)}
        >>> my_string = "a*2-b+10"
        >>> evaluate_expression_with_dict(my_string, my_dict)
        array([12., 11., 10.,  9.,  8.,  7.,  6.,  5.,  4.,  3.])
    """
    # Replace dictionary keys in the expression with their corresponding values
    ### replace names with dict entries
    expression = _replace_names_with_dict(
        expression=expression, name_of_dict="value_dict", dictionary=value_dict
    )

    ### evaluate the new expression
    try:
        result = eval(expression)
        return result
    except Exception as e:
        raise ValueError(f"Error while evaluating expression: {str(e)}")