Metadata-Version: 2.4
Name: morphgen-rates
Version: 1.2.0
Summary: Compute bifurcation and annihilation rates from morphology data
Author-email: Francesco Cavarretta <fcavarretta@ualr.edu>
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5
Requires-Dist: pyomo>=6.6
Dynamic: license-file

<img src="https://raw.githubusercontent.com/fcavarretta-ualr/morphgen-rates/master/docs/morphgen_rates_logo.png" alt="MorphGen-Rates banner" />

# MorphGen-Rates

* [Overview](#1-overview)
* [Installation](#2-installation)
* [Quick start](#3-quick-start)
* [Data Format Specifications](#4-data-format-specifications)
* [Troubleshooting](#5-troubleshooting)

## 1. Overview

`morphgen-rates` is a Python package that estimates bifurcation and annihilation rates from morphological data obtained from experimentally reconstructed neuron morphologies. These rates are core parameters in mathematical models used to generate realistic neuron morphologies via random-walk–based generation processes.

[View the full repository on GitHub](https://github.com/fcavarretta-ualr/morphgen-rates)

This package implements computational methods from the publication

[Cavarretta F (2025) *A mathematical model for data-driven synthesis of neuron morphologies based on random walks.* Front. Appl. Math. Stat. 11:1632271. doi: 10.3389/fams.2025.1632271](https://www.frontiersin.org/journals/applied-mathematics-and-statistics/articles/10.3389/fams.2025.1632271/full)

For questions, issues, or contributions, please contact:

- Author: Francesco Cavarretta
- Email: [fcavarretta@ualr.edu](mailto:fcavarretta@ualr.edu)

### What does this package do?

The package analyzes neuronal morphology data to estimate two spatially varying rates that govern dendritic tree generation:

- **Bifurcation rate (β)**: Probability per unit distance that a synthesized dendritic segment splits into two branches
- **Annihilation rate (α)**: Probability per unit distance that a synthesized dendritic segment terminates

The rates vary with distance from the soma and are inferred from:

- **Sholl analysis data**: Mean and standard deviation of dendrite intersection counts across radial distance bins from the soma
- **Bifurcation statistics (Optional)**: Summary statistics describing the number of branching points in the reconstructed dendritic tree

In the latest version, the package has been expanded with a new function that estimates the probability distribution of the number of primary dendrites using the mean, standard deviation, minimum, and maximum of the experimental counts.

## 2. Installation

### Requirements

- Python >= 3.9
- numpy >= 1.23
- pandas >= 1.5
- pyomo >= 6.6
- A nonlinear optimization solver (typically IPOPT)

### Install the package

```bash
pip install morphgen-rates
```

### Install IPOPT (recommended solver)

The package requires a nonlinear solver. IPOPT is recommended.

On Ubuntu/Debian:

```bash
sudo apt-get install coinor-libipopt-dev
pip install cyipopt
```

On macOS:

```bash
brew install ipopt
pip install cyipopt
```

On Windows:

Follow instructions at:

https://github.com/coin-or/Ipopt

## 3. Quick start

### Calculation of bifurcation and annihilation rates
The primary function implemented in this package is the calculation of bifurcation and annihilation rates as a function of the distance from the soma.
To do this, first you need to import the module:
```python
from morphgen_rates import compute_rates
```
Next, identify the morphometric dataset you want and pass it to the function as the parameters argument.
Below is an example that shows how the morphometric data should be structured when passed as the `parameters` argument:

```python
parameters = {
    "sholl_plot": {
        "bin_size": 50,
        "mean"[1.0, 4.5, 6.2, 6.2, 8.0, 7.0, 5.0, 4.5, 0.0],
        "std":[0.5, 1.5, 2.0, 3.0, 1.5, 2.0, 3.0, 1.0, 0.0]
    },
    "bifurcation_count": {
        "mean": 18,
        "std": 5,
    },
}
```
In particular, `bifurcation_count` is optional.

Then compute the bifurcation and annihilation rates:
```python
rates = compute_rates(parameters, max_step_size=5.0)
```

Below is a the full example on how to use this function.

```python
# Step 1: Import package
from morphgen_rates import compute_rates

# Step 2: Determine morphometric parameters
parameters = {
    "sholl_plot": {
        "bin_size": 50,
        "mean"[1.0, 4.5, 6.2, 6.2, 8.0, 7.0, 5.0, 4.5, 0.0],
        "std":[0.5, 1.5, 2.0, 3.0, 1.5, 2.0, 3.0, 1.0, 0.0]
    },
    "bifurcation_count": {
        "mean": 18,
        "std": 5,
    },
}


# Step 3: Computer bifurcation and annhilation rates
rates = compute_rates(parameters, max_step_size=5.0)

# Step 4: Display results
print("Bifurcation rates by radial bin:")
for i, (bif, ann) in enumerate(zip(rates["bifurcation_rate"], rates["annihilation_rate"])):
    distance = parameters["sholl_plot"]["bin_size"] * (i + 0.5)
    print(f"  {distance:.1f} μm: β={bif:.4f}, α={ann:.4f}")
```
The output of this example is:
```
Bifurcation rates by radial bin:
  25.0 μm: β=0.0301, α=0.0000
  75.0 μm: β=0.0064, α=0.0000
  125.0 μm: β=0.0355, α=0.0355
  175.0 μm: β=0.0051, α=0.0000
  225.0 μm: β=0.0000, α=0.0027
  275.0 μm: β=0.0000, α=0.0067
  325.0 μm: β=0.0000, α=0.0021
  375.0 μm: β=0.0000, α=inf
```
The output above shows the spatial bin centers in the left column and the corresponding bifurcation (β) and annihilation (α) rates in the right column, computed for each 50-µm bin.

### Primary Dendrite Distribution Estimation
In recent versions, we implemented a function that enables estimation of the distribution of the number of primary dendrites from morphometric parameters (i.e., the mean, standard deviation, minimum, and maximum of the experimental counts).

To do this, first you need to import the module:
```python
from morphgen_rates import compute_init_number_probs
```
Next, identify the morphometric parameters to be passed as the arguments (i.e., `mean_primary_dendrites`, `sd_primary_dendrites`, `min_primary_dendrites`, `max_primary_dendrites`).

```python
probs = compute_init_number_probs(
    mean_primary_dendrites=3.5,
    sd_primary_dendrites=1.2,
    min_primary_dendrites=1,
    max_primary_dendrites=7,
    slack_penalty=0.1
)
```


Below is a the full example on how to use this function.

```python
from morphgen_rates import compute_init_number_probs
import numpy as np

# Compute probability distribution
probs = compute_init_number_probs(
    mean_primary_dendrites=3.5,
    sd_primary_dendrites=1.2,
    min_primary_dendrites=1,
    max_primary_dendrites=7,
    slack_penalty=0.1
)

# Display results
for n_dendrites, prob in enumerate(probs):
    if prob > 1e-6:
        print(f"P({n_dendrites} primary dendrites) = {prob:.4f}")

# Verify moments
actual_mean = np.sum(np.arange(len(probs)) * probs)
actual_var = np.sum((np.arange(len(probs)) - actual_mean)**2 * probs)
```
The output of this example is:
```
P(1 primary dendrites) = 0.0880
P(2 primary dendrites) = 0.1705
P(3 primary dendrites) = 0.2355
P(4 primary dendrites) = 0.2321
P(5 primary dendrites) = 0.1631
P(6 primary dendrites) = 0.0817
P(7 primary dendrites) = 0.0292
```
The output above shows the probability of observing a given number of primary dendrites.

## 4. Data Format Specifications

### Built-in Dataset Format

The package includes a CSV file (`morph_data.csv`) with the following columns:

| Column | Type | Description |
|---|---|---|
| area | str | Brain region (e.g., “aPC”, “Neocortex”, “OB”) |
| neuron_type | str | Cell class (e.g., “PYR”, “SL”, “MITRAL”, “TUFTED”) |
| neuron_name | str | Individual cell identifier |
| section_type | str | Dendrite type ("apical_dendrite" or "basal_dendrite") |
| bifurcation_count | float | Number of bifurcation points |
| total_length | float | Total dendritic length (μm) |
| bin_size | float | Radial bin size for Sholl analysis (μm) |
| Count0 | float | Primary dendrite count (Sholl at r=0) |
| Count1 | float | Sholl intersections at bin 1 |
| Count2 | float | Sholl intersections at bin 2 |
| … | … | … |
| CountN | float | Sholl intersections at bin N |

Records can be accessed with `get_data`, as shown below:

```python
from morphgen_rates import get_data

# Retrieve morphometric data for semilunar cells from the anterior piriform cortex
parameters = get_data("aPC", "SL")

# Compute rates
rates = compute_rates(parameters, max_step_size=5.0)

...

```

In this example, `get_data` returns an object in the format expected by `compute_rates`, so you can pass it directly as the first argument.

## 5. Troubleshooting

### Solver Not Found

Error:

```text
RuntimeError: Solver 'ipopt' is not available
```

Solution:

- Install IPOPT solver (see Installation section)

### Data Not Found

Error:

```text
AssertionError: The area ... or neuron class ... are not known
```

Solution:

- Check available combinations using:

```python
import pandas as pd

df = pd.read_csv("morph_data.csv")
print("Available combinations:")
print(df[["area", "neuron_type"]].drop_duplicates())
```

### Numerical Instability

Symptom:

- Very large or very small rate values

Solution:

- Check that max_step_size is appropriate for your data scale
- Ensure Sholl data is smoothly decreasing (no sudden jumps)
- Verify that variance values are non-negative

### Poor Moment Matching in Primary Dendrite Distribution

Symptom:

- Computed distribution doesn't match target mean/std

Solution:

- Increase slack_penalty:

```python
probs = compute_init_number_probs(
    mean_primary_dendrites=3.5,
    sd_primary_dendrites=1.2,
    min_primary_dendrites=1,
    max_primary_dendrites=7,
    slack_penalty=1.0  # Increase from default 0.1
)
```
