Source code for bsv.find_connectivity_experiments
import time
import requests
from .fetch_upstream_regions import fetch_upstream_regions
from .atlas_utils import load_projection_info
[docs]
def find_connectivity_experiments(regions, mouse_line='', primary_injection=True, target_regions=None):
"""Query the Allen API for connectivity experiments by injection region.
Parameters
----------
regions : list of str
Brain region acronyms to search for (e.g. ``['VISp', 'VISl']``).
Ignored when *target_regions* is provided and *regions* is empty.
mouse_line : str, optional
Transgenic mouse line filter. ``''`` for all lines, ``'0'`` for
wild-type only.
primary_injection : bool, optional
If True, only return experiments where the region is the primary
injection site.
target_regions : str or list of str or None, optional
If provided, call :func:`fetch_upstream_regions` to discover which
source regions project to these target(s), then query experiments
injected in those sources. If *regions* is also non-empty it is used
as an additional filter (intersection).
Returns
-------
list of int
Experiment IDs matching the query.
"""
if target_regions is not None:
upstream = fetch_upstream_regions(target_regions, mouse_line=mouse_line)
if regions:
# Match upstream leaves against caller-supplied regions, supporting
# parent acronyms: 'ACA' should match 'ACAd', 'ACAv', etc.
upstream = [
r for r in upstream
if any(r == s or r.startswith(s) for s in regions)
]
regions = upstream
if not regions:
print("Warning: No upstream regions found for the specified target(s).")
return []
experiment_ids = []
primary = 'true' if primary_injection else 'false'
projection_info = load_projection_info()
# Expand parent regions to their children.
# A region is considered a parent if it never appears as a primary injection
# site in the database but prefix-matches child regions that do (same
# convention as find_structure_indices in atlas_utils).
all_abbrevs = set(projection_info['structure_abbrev'].dropna())
expanded = []
for region in regions:
if region in all_abbrevs:
expanded.append(region)
else:
children = sorted(
a for a in all_abbrevs
if a != region and a.startswith(region)
)
if children:
print(f"'{region}' expanded to children: {children}")
expanded.extend(children)
else:
expanded.append(region) # pass through; API will handle it
# Deduplicate while preserving order
seen = set()
regions = [r for r in expanded if not (r in seen or seen.add(r))]
for region in regions:
url = 'http://api.brain-map.org/api/v2/data/query.json?criteria=service::mouse_connectivity_injection_structure'
url += f'[injection_structures$eq{region}]'
if mouse_line:
url += f'[transgenic_lines$eq{mouse_line}]'
url += f'[primary_structure_only$eq{primary}]'
result = None
for attempt in range(3):
try:
resp = requests.get(url)
result = resp.json()
if result.get('success'):
break
except Exception:
pass
if attempt < 2:
time.sleep(1)
if result is not None and result.get('success'):
for entry in result.get('msg', []):
if 'id' in entry:
experiment_ids.append(entry['id'])
print(f"Found {len(result.get('msg', []))} experiments in {region}")
else:
# Allen service fails for some valid regions; fall back to local CSV
rows = projection_info[projection_info['structure_abbrev'] == region]
if mouse_line:
rows = rows[rows['transgenic_line'] == mouse_line]
fallback_ids = rows['id'].tolist()
experiment_ids.extend(fallback_ids)
print(f"Found {len(fallback_ids)} experiments in {region} (via local CSV fallback)")
return experiment_ids