morphgen-rates 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphgen-rates
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Compute bifurcation and annihilation rates from morphology data
5
5
  Author-email: Francesco Cavarretta <fcavarretta@ualr.edu>
6
6
  Requires-Python: >=3.9
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "morphgen-rates"
7
- version = "0.4.0"
7
+ version = "0.5.0"
8
8
  description = "Compute bifurcation and annihilation rates from morphology data"
9
9
  authors = [
10
10
  { name = "Francesco Cavarretta", email = "fcavarretta@ualr.edu" },
@@ -0,0 +1,145 @@
1
+ import pandas as pd
2
+ from pathlib import Path
3
+
4
+
5
+ def _local_data_path(filename='morph_data', ext="csv"):
6
+ """
7
+ Build a path like: <this_file_dir>/data/<filename>.<ext>
8
+
9
+ Parameters
10
+ ----------
11
+ filename : str
12
+ Base filename (without extension)
13
+ ext : str, default "csv"
14
+ File extension (without the dot)
15
+
16
+ Returns
17
+ -------
18
+ pathlib.Path
19
+ Full path to the data file
20
+ """
21
+ work_dir = Path(__file__).resolve().parent
22
+ return work_dir / f"{filename}.{ext}"
23
+
24
+
25
+ def get_data(area, neuron_type):
26
+ """
27
+ Retrieve summary morphology statistics for a given brain area and neuron class.
28
+
29
+ This function loads a local CSV dataset, filters rows matching the requested
30
+ `area` and `neuron_type`, and aggregates statistics by `section_type`. The
31
+ output is a nested dictionary keyed by section type (e.g., soma, apical, basal),
32
+ containing:
33
+
34
+ - Summary statistics for bifurcation counts and total length
35
+ - Estimated number of primary neurites at the soma (Count0)
36
+ - Sholl plot summary statistics (bin size, mean counts, standard deviation)
37
+
38
+ Parameters
39
+ ----------
40
+ area : str
41
+ Brain region identifier used in the dataset (must match values in the
42
+ 'area' column of the CSV)
43
+ neuron_type : str
44
+ Neuron class identifier used in the dataset (must match values in the
45
+ 'neuron_type' column of the CSV)
46
+
47
+ Returns
48
+ -------
49
+ dict
50
+ Nested dictionary structured as:
51
+
52
+ data = {
53
+ "<section_type>": {
54
+ "bifurcation_count": {"mean": ..., "std": ..., "min": ..., "max": ...},
55
+ "total_length": {"mean": ..., "std": ..., "min": ..., "max": ...},
56
+ "primary_count": {"mean": ..., "std": ..., "min": ..., "max": ...},
57
+ "sholl_plot": {
58
+ "bin_size": float,
59
+ "mean": list[float],
60
+ "std": list[float],
61
+ },
62
+ },
63
+ ...
64
+ }
65
+
66
+ Notes on fields:
67
+ - `primary_count` corresponds to the row group labeled 'Count0'
68
+ - Sholl values are collected from rows whose metric name starts with 'Count'
69
+ (including 'Count0'); users may want to interpret/plot them as a function
70
+ of radial bin index multiplied by `bin_size`
71
+
72
+ Raises
73
+ ------
74
+ AssertionError
75
+ If no rows match the requested `area` and `neuron_type`
76
+
77
+ Notes
78
+ -----
79
+ - The function expects the local CSV to include at least the following columns:
80
+ 'area', 'neuron_type', 'neuron_name', 'section_type', 'bin_size'
81
+ plus metric columns including:
82
+ - 'bifurcation_count'
83
+ - 'total_length'
84
+ - 'Count0', 'Count1', ... (Sholl counts per radial bin)
85
+ - Statistics are computed using `pandas.DataFrame.groupby(...).describe()`.
86
+ Only the summary columns 'mean', 'std', 'min', 'max' are retained.
87
+
88
+ Examples
89
+ --------
90
+ >>> data = get_data("CTX", "pyr")
91
+ >>> data["apical"]["bifurcation_count"]["mean"]
92
+ 42.0
93
+ >>> data["apical"]["sholl_plot"]["bin_size"]
94
+ 50.0
95
+ >>> len(data["apical"]["sholl_plot"]["mean"])
96
+ 20
97
+ """
98
+
99
+ data = {}
100
+
101
+ area, neuron_type = parts
102
+
103
+ # load data
104
+ df = pd.read_csv(_local_data_path(), index_col=0)
105
+
106
+ # select specific area and neuron type
107
+ df = df[(df['area'] == area) & (df['neuron_type'] == neuron_type)]
108
+
109
+ # ensure that there are area and neuron_type in the df
110
+ assert df.shape[0] > 0, "The area {area} or neuron class {neuron_type} are not known"
111
+
112
+ # neuron name unnecessary
113
+ df.drop(['area', 'neuron_type', 'neuron_name'], axis=1, inplace=True)
114
+
115
+ # statistics
116
+ df = df.groupby('section_type').describe()
117
+
118
+ # select only a subset of columns
119
+ df = df.loc[:, df.columns.get_level_values(1).isin(['mean', 'std', 'min', 'max'])]
120
+
121
+ # get subsections
122
+ for section_type, row in df.iterrows():
123
+ data[section_type] = {}
124
+
125
+ # get statistics
126
+ for data_type in ['bifurcation_count', 'total_length']:
127
+ tmp = row.loc[row.index.get_level_values(0) == data_type, :]
128
+ tmp.index = tmp.index.droplevel(0)
129
+ data[section_type][data_type] = tmp.to_dict()
130
+
131
+ # count neurites at the soma
132
+ tmp = row.loc[row.index.get_level_values(0) == 'Count0', :]
133
+ tmp.index = tmp.index.droplevel(0)
134
+ data[section_type]['primary_count'] = tmp.to_dict()
135
+
136
+ # sholl plots
137
+ tmp = row.loc[row.index.get_level_values(0).str.startswith('Count'), :]
138
+ data[section_type]['sholl_plot'] = {
139
+ 'bin_size':row[('bin_size', 'mean')].tolist(),
140
+ 'mean':tmp.loc[tmp.index.get_level_values(1) == 'mean', :].tolist(),
141
+ 'std':tmp.loc[tmp.index.get_level_values(1) == 'std', :].tolist()
142
+ }
143
+
144
+ return data
145
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphgen-rates
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Compute bifurcation and annihilation rates from morphology data
5
5
  Author-email: Francesco Cavarretta <fcavarretta@ualr.edu>
6
6
  Requires-Python: >=3.9
@@ -10,4 +10,5 @@ src/morphgen_rates.egg-info/SOURCES.txt
10
10
  src/morphgen_rates.egg-info/dependency_links.txt
11
11
  src/morphgen_rates.egg-info/requires.txt
12
12
  src/morphgen_rates.egg-info/top_level.txt
13
- tests/test.py
13
+ tests/test_primary_count.py
14
+ tests/test_rates.py
@@ -0,0 +1,38 @@
1
+ """
2
+ Minimal test example: empirical distribution of primary dendrites.
3
+
4
+ This script loads summary statistics for aPC pyramidal neurons (apical dendrite),
5
+ extracts the primary dendrite stats (Count0), and converts them into a discrete
6
+ probability distribution using `compute_init_number_probs`.
7
+
8
+ `probs[i]` is the probability of generating i primary dendrites.
9
+ """
10
+
11
+ from morphgen_rates import get_data, compute_init_number_probs
12
+
13
+ if __name__ == "__main__":
14
+ # Load summary statistics and select the apical dendrite section
15
+ data = get_data("aPC", "PYR")["apical_dendrite"]
16
+
17
+ # Primary dendrite stats (derived from Count0)
18
+ stats = data["primary_count"]
19
+
20
+ mean_primary = float(stats["mean"])
21
+ sd_primary = float(stats["std"])
22
+ min_primary = int(stats["min"])
23
+ max_primary = int(stats["max"])
24
+
25
+ probs = compute_init_number_probs(
26
+ mean_primary_dendrites=mean_primary,
27
+ sd_primary_dendrites=sd_primary,
28
+ min_primary_dendrites=min_primary,
29
+ max_primary_dendrites=max_primary,
30
+ )
31
+
32
+ print("Primary dendrite stats:")
33
+ print(f" mean={mean_primary}, std={sd_primary}, min={min_primary}, max={max_primary}")
34
+
35
+ print("\nP(# primary dendrites = i):")
36
+ for i, p in enumerate(probs):
37
+ if p > 0:
38
+ print(f" i={i}: {p:.6f}")
@@ -0,0 +1,23 @@
1
+ """
2
+ Minimal test example: compute bifurcation and annihilation rates from packaged data.
3
+ """
4
+
5
+ from morphgen_rates import compute_rates, get_data
6
+
7
+ if __name__ == "__main__":
8
+ # Load summary statistics for aPC pyramidal neurons and select the apical dendrite section
9
+ data = get_data("aPC", "PYR")["apical_dendrite"]
10
+
11
+ # (Optional) inspect the input dictionary used by the estimator
12
+ print("Input data keys:", list(data.keys()))
13
+ print("Sholl bin size:", data["sholl"]["bin_size"])
14
+
15
+ # Maximum advancement (distance from soma) allowed for one elongation step
16
+ max_step_size = 5.0
17
+
18
+ # Estimate rates
19
+ rates = compute_rates(data, max_step_size=max_step_size)
20
+
21
+ print("Bifurcation rate:", rates.get("bifurcation_rate"))
22
+ print("Annihilation rate:", rates.get("annihilation_rate"))
23
+
@@ -1,147 +0,0 @@
1
- import pandas as pd
2
- from pathlib import Path
3
-
4
-
5
- def _local_data_path(filename='morph_data', ext="csv"):
6
- """
7
- Build a path like: <this_file_dir>/data/<filename>.<ext>
8
-
9
- Parameters
10
- ----------
11
- filename : str
12
- Base filename (without extension)
13
- ext : str, default "csv"
14
- File extension (without the dot)
15
-
16
- Returns
17
- -------
18
- pathlib.Path
19
- Full path to the data file
20
- """
21
- work_dir = Path(__file__).resolve().parent
22
- return work_dir / f"{filename}.{ext}"
23
-
24
-
25
- def get_data(key):
26
- """
27
- Retrieve a dataset entry using a key-path of the form
28
- "<brain region>/<neuron class>/<subcellular section>".
29
-
30
- The argument `data_path` is interpreted as a slash-separated path of keys used
31
- to traverse a nested dataset dictionary. The selected dataset is expected to
32
- contain both Sholl-plot statistics and bifurcation statistics; when both are
33
- available, this function returns a standardized dictionary compatible with
34
- `compute_rates`.
35
-
36
- Parameters
37
- ----------
38
- key : str
39
- Dataset identifier expressed as a key path:
40
-
41
- "<brain region>/<neuron class>/<subcellular section>"
42
-
43
- Examples:
44
- - "CTX/pyr/apical"
45
- - "HPC/pyr/basal"
46
-
47
- Each component is used as a successive key lookup into the nested dataset
48
- container.
49
-
50
- Returns
51
- -------
52
- dict
53
- If both Sholl and bifurcation information are present for the selected dataset,
54
- returns:
55
-
56
- data = {
57
- "sholl": {
58
- "bin_size": float,
59
- "mean": numpy.ndarray, # shape (K,)
60
- "var": numpy.ndarray, # shape (K,)
61
- },
62
- "bifurcations": {
63
- "mean": float,
64
- "var": float,
65
- },
66
- }
67
-
68
- Where:
69
- - `data["sholl"]["bin_size"]` is the spatial bin size used to define Sholl shells
70
- - `data["sholl"]["mean"]` is the mean Sholl intersection count per radial bin
71
- - `data["sholl"]["var"]` is the variance of the Sholl intersection count per bin
72
- - `data["bifurcations"]["mean"]` is the mean bifurcation count
73
- - `data["bifurcations"]["var"]` is the variance of the bifurcation count
74
-
75
- Raises
76
- ------
77
- KeyError
78
- If any key along `data_path` is missing (brain region, neuron class, or section)
79
- ValueError
80
- If the selected dataset does not contain both Sholl and bifurcation data, or
81
- if the provided arrays have incompatible shapes
82
-
83
- Notes
84
- -----
85
- - `data_path` is a *key path*, not a filesystem path
86
- - The function assumes the dataset entry referenced by `data_path` includes:
87
- - Sholl bin size, mean array, variance array
88
- - Bifurcation mean and variance
89
-
90
- Examples
91
- --------
92
- >>> data = get("CTX/pyr/apical")
93
- >>> data["sholl"]["bin_size"]
94
- 50.0
95
- >>> data["bifurcations"]["mean"]
96
- 12.3
97
- """
98
- data = {}
99
-
100
- # split the key
101
- parts = tuple(p.strip() for p in key.split("/") if p.strip())
102
- if len(parts) != 2:
103
- raise ValueError(f"Expected key like 'area/neuron_type', got: {key!r}")
104
- area, neuron_type = parts
105
-
106
- # load data
107
- df = pd.read_csv(_local_data_path(), index_col=0)
108
-
109
- # select specific area and neuron type
110
- df = df[(df['area'] == area) & (df['neuron_type'] == neuron_type)]
111
-
112
- # neuron name unnecessary
113
- df.drop(['area', 'neuron_type', 'neuron_name'], axis=1, inplace=True)
114
-
115
- # statistics
116
- df = df.groupby('section_type').describe()
117
-
118
- # select only a subset of columns
119
- df = df.loc[:, df.columns.get_level_values(1).isin(['mean', 'std', 'min', 'max'])]
120
-
121
- # get subsections
122
- for section_type, row in df.iterrows():
123
- data[section_type] = {}
124
-
125
- print()
126
-
127
- # get statistics
128
- for data_type in ['bifurcation_count', 'total_length']:
129
- tmp = row.loc[row.index.get_level_values(0) == data_type, :]
130
- tmp.index = tmp.index.droplevel(0)
131
- data[section_type][data_type] = tmp.to_dict()
132
-
133
- # count neurites at the soma
134
- tmp = row.loc[row.index.get_level_values(0) == 'Count0', :]
135
- tmp.index = tmp.index.droplevel(0)
136
- data[section_type]['primary_count'] = tmp.to_dict()
137
-
138
- # sholl plots
139
- tmp = row.loc[row.index.get_level_values(0).str.startswith('Count'), :]
140
- data[section_type]['sholl_plot'] = {
141
- 'bin_size':row[('bin_size', 'mean')].tolist(),
142
- 'mean':tmp.loc[tmp.index.get_level_values(1) == 'mean', :].tolist(),
143
- 'std':tmp.loc[tmp.index.get_level_values(1) == 'std', :].tolist()
144
- }
145
-
146
- return data
147
-
@@ -1,14 +0,0 @@
1
- import pandas as pd
2
- from morphgen_rates import compute_rates, get_data
3
-
4
- # Bundle inputs exactly as loaded (no preprocessing)
5
- data = get_data('aPC/PYR')['apical_dendrite']
6
-
7
- print(data)
8
-
9
- max_step_size = 5.
10
-
11
- rates = compute_rates(data, max_step_size=max_step_size)
12
-
13
- print("Bifurcation rate:", rates.get("bifurcation_rate"))
14
- print("Annihilation rate:", rates.get("annihilation_rate"))
File without changes
File without changes
File without changes