Source code for bsv.fetch_upstream_regions
import time
import requests
from .atlas_utils import load_projection_info
[docs]
def fetch_upstream_regions(target_regions, min_projection_volume=0.01, mouse_line=''):
"""Query the Allen API for brain regions that project TO given target region(s).
Uses the precomputed ProjectionStructureUnionize table to find all anterograde
tracing experiments with signal in the target structure(s), then returns the
injection site acronyms (= upstream source regions).
Parameters
----------
target_regions : str or list of str
Target brain region acronym(s) (e.g. ``'CP'`` or ``['CP', 'STR']``).
min_projection_volume : float, optional
Minimum projection_volume (mm^3) threshold to count as a projection.
Default is 0.01.
mouse_line : str, optional
Reserved for API consistency with :func:`find_connectivity_experiments`.
Not used in the PSU query.
Returns
-------
list of str
Unique injection-site acronyms of experiments projecting to the target,
sorted alphabetically.
"""
if isinstance(target_regions, str):
target_regions = [target_regions]
projection_info = load_projection_info()
all_upstream = set()
for target in target_regions:
# 1. Resolve acronym -> Allen structure ID
id_url = (
'http://api.brain-map.org/api/v2/data/query.json'
f"?criteria=model::Structure,rma::criteria,[acronym$eq'{target}']&num_rows=1"
)
structure_id = None
for attempt in range(3):
try:
resp = requests.get(id_url)
data = resp.json()
if data.get('success') and data.get('msg'):
structure_id = data['msg'][0]['id']
break
except Exception:
pass
if attempt < 2:
time.sleep(1)
if structure_id is None:
print(f"Warning: Could not resolve structure ID for '{target}'")
continue
print(f"Querying upstream projections to {target} (structure_id={structure_id})...")
# 2. Query ProjectionStructureUnionize for non-injection records in this structure
psu_url = (
'http://connectivity.brain-map.org/api/v2/data/ProjectionStructureUnionize/query.json'
f'?criteria=[structure_id$eq{structure_id}][is_injection$eqfalse]'
f'[projection_volume$gt{min_projection_volume}]'
'&num_rows=all'
)
result = None
for attempt in range(3):
try:
resp = requests.get(psu_url)
result = resp.json()
if result.get('success'):
break
except Exception:
pass
if attempt < 2:
time.sleep(1)
if result is None or not result.get('success'):
print(f"Warning: PSU query failed for target '{target}'")
continue
records = result.get('msg', [])
exp_ids = {r['section_data_set_id'] for r in records}
print(f" Found {len(exp_ids)} experiments projecting to {target}")
# 3. Look up injection structure acronyms from local projection_info CSV
matched = projection_info[projection_info['id'].isin(exp_ids)]
acronyms = matched['structure_abbrev'].dropna().unique().tolist()
all_upstream.update(acronyms)
return sorted(all_upstream)