Skip to content

Commit

Permalink
- Finish up motifs backend
Browse files Browse the repository at this point in the history
- show spinner
- explainer
- sample query
- fix test
  • Loading branch information
arie-matsliah committed Jul 15, 2023
1 parent 7dba20c commit 7649743
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 52 deletions.
20 changes: 4 additions & 16 deletions src/blueprints/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,22 +1429,10 @@ def motifs():
motifs_query = MotifSearchQuery.from_form_query(
request.args, NeuronDataFactory.instance()
)
try:
search_results = motifs_query.search()
log_activity(
f"Motif search with {motifs_query} found {len(search_results)} matches"
)
except Exception as e:
error = f"Error searching for motif: {e=}"
log_error(error)
return render_template(
"motif_search.html",
regions=list(REGIONS.keys()),
results=search_results,
error=error,
NEURO_TRANSMITTER_NAMES=NEURO_TRANSMITTER_NAMES,
query=request.args,
)
search_results = motifs_query.search()
log_activity(
f"Motif search with {motifs_query} found {len(search_results)} matches"
)

return render_template(
"motif_search.html",
Expand Down
40 changes: 7 additions & 33 deletions src/service/motif_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,9 @@ def row_satisfies_constraints(row, edge_constraints):
return True

@staticmethod
def _feasible_pairs(
def feasible_pairs(
neuron_db, x_candidates, y_candidates, xy_constraints, yx_constraints
):
print("+++ here!")
ins, outs = neuron_db.input_output_partners_with_synapse_counts()

if not xy_constraints and not yx_constraints:
Expand Down Expand Up @@ -503,7 +502,7 @@ def _feasible_pairs(
else: # both edges are specified
for x_rid in x_candidates:
y_candidates_filtered = y_candidates.intersection(
set(ins[x_rid].keys()).intersection(set(outs[x_rid]).keys())
set(ins[x_rid].keys()).intersection(set(outs[x_rid].keys()))
)
rows = neuron_db.connections_.rows_for_cell(x_rid)
from_x_tuples = defaultdict(list)
Expand Down Expand Up @@ -575,16 +574,6 @@ def _search_triplets(
assert all(
[isinstance(c, set) for c in [x_candidates, y_candidates, z_candidates]]
)
print(
f"+++ x, y, z: {len(x_candidates)}, {len(y_candidates)}, {len(z_candidates)}"
)

print(f"+++ xy_ec: {xy_edge_constraints}")
print(f"+++ xz_ec: {xz_edge_constraints}")
print(f"+++ yx_ec: {yx_edge_constraints}")
print(f"+++ yz_ec: {yz_edge_constraints}")
print(f"+++ zx_ec: {zx_edge_constraints}")
print(f"+++ zy_ec: {zy_edge_constraints}")

x_query, y_query, z_query = [], [], []
MotifSearchQuery.append_edge_queries(xy_edge_constraints, x_query, y_query)
Expand All @@ -604,37 +593,27 @@ def _search_triplets(
neuron_db, z_candidates, z_query
)

print(
f"+++ x, y, z after edge queries: {len(x_candidates)}, {len(y_candidates)}, {len(z_candidates)}"
)

ins, outs = neuron_db.input_output_partner_sets()

def z_satisfies_constraints(x_rid, y_rid, z_rid):
constraints_satisfied = set()

print("+++ checking if z satisfies constraints")
if not xz_edge_constraints:
if z_rid in outs[x_rid]:
print("+++ xz should not be an edge")
return False
else:
constraints_satisfied.add("xz")
if not zx_edge_constraints:
if x_rid in outs[z_rid]:
print("+++ zx should not be an edge")
return False
else:
constraints_satisfied.add("zx")
if not yz_edge_constraints:
if z_rid in outs[y_rid]:
print("+++ yz should not be an edge")
return False
else:
constraints_satisfied.add("yz")
if not zy_edge_constraints:
if y_rid in outs[z_rid]:
print("+++ zy should not be an edge")
return False
else:
constraints_satisfied.add("zy")
Expand All @@ -643,7 +622,7 @@ def z_satisfies_constraints(x_rid, y_rid, z_rid):
return True

z_rows = neuron_db.connections_.rows_for_cell(z_rid)
print("+++ checking if z satisfies rows")

for r in z_rows:
if (
r[0] == x_rid
Expand All @@ -659,7 +638,7 @@ def z_satisfies_constraints(x_rid, y_rid, z_rid):
if (
r[0] == y_rid
and r[1] == z_rid
and not MotifSearchQuery.row_satisfies_constraints(
and MotifSearchQuery.row_satisfies_constraints(
r, yz_edge_constraints
)
):
Expand All @@ -670,7 +649,7 @@ def z_satisfies_constraints(x_rid, y_rid, z_rid):
if (
r[0] == z_rid
and r[1] == x_rid
and not MotifSearchQuery.row_satisfies_constraints(
and MotifSearchQuery.row_satisfies_constraints(
r, zx_edge_constraints
)
):
Expand All @@ -681,7 +660,7 @@ def z_satisfies_constraints(x_rid, y_rid, z_rid):
if (
r[0] == z_rid
and r[1] == y_rid
and not MotifSearchQuery.row_satisfies_constraints(
and MotifSearchQuery.row_satisfies_constraints(
r, zy_edge_constraints
)
):
Expand All @@ -705,24 +684,19 @@ def filtered_z_candidates(x_rid, y_rid):
return res

matches = []
print("+++ starting the loop")
for _x_rid, _y_rid in MotifSearchQuery._feasible_pairs(
for _x_rid, _y_rid in MotifSearchQuery.feasible_pairs(
neuron_db=neuron_db,
x_candidates=x_candidates,
y_candidates=y_candidates,
xy_constraints=xy_edge_constraints,
yx_constraints=yx_edge_constraints,
):
print(f"+++ examining {_x_rid}, {_y_rid}")

z_candidates_filtered = filtered_z_candidates(_x_rid, _y_rid)

for _z_rid in z_candidates_filtered:
if _z_rid == _x_rid or _z_rid == _y_rid:
print("+++ z is equal to y or x")
continue
if z_satisfies_constraints(x_rid=_x_rid, y_rid=_y_rid, z_rid=_z_rid):
print(f"+++ appending result, have {len(matches)} need {limit}")
matches.append(
MotifSearchQuery.make_match_dict(
neuron_db=neuron_db,
Expand Down
2 changes: 1 addition & 1 deletion src/templates/motif_search.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
{% endfor %}

<div class="d-flex justify-content-center">
<button type="submit" class="btn btn-primary">Search</button>
<button type="submit" class="btn btn-primary" onclick="loading(event);">Search</button>
</div>
</form>
</div>
Expand Down
11 changes: 9 additions & 2 deletions static/js/motif_search.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ function ExplainerCard() {
<div class="card" style=${{ margin: "15px" }}>
<div class="card-header" sttyle=${{ color: "purple" }}>What is this?</div>
<div class="card-body">
[TODO: explanatory text and demo query]
With this tool you can search for specific motifs (sub-graphs) of size 3 in the connectome network. With A, B, C
denoting the motif node names, you can specify a filter for each node (same query language as in search) as well
as connectivity of each pair of nodes (not connected, connected one way,
connected both ways). Additionally you can apply neurotransmitter / brain region / min synapse count constraints
for every pair of connected nodes. Matching
motifs (if found) will be presented as a network along with 3D rendering of the corresponding cells.
<br /><br />
<button class="btn btn btn-outline-success my-2 my-sm-0" type="button">Try Example Query</button>
<a class="btn btn btn-outline-success my-2 my-sm-0" href="/app/motifs/?queryA=720575940613052200&queryB=DL1_dorsal&queryC=DL1_dorsal&enabledAB=on&regionAB=Any&minSynapseCountAB=20&ntTypeAB=GLUT&enabledBA=on&regionBA=Any&minSynapseCountBA=20&ntTypeBA=GLUT&enabledAC=on&regionAC=Any&minSynapseCountAC=15&ntTypeAC=GLUT&enabledCA=on&regionCA=Any&minSynapseCountCA=15&ntTypeCA=GLUT&enabledBC=on&regionBC=Any&minSynapseCountBC=&ntTypeBC=GLUT&enabledCB=on&regionCB=Any&minSynapseCountCB=&ntTypeCB=GLUT">
Try Example Query
</a>
</div>
</div>
</div>`;
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_motif_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def test_search_size_3(self):
msq.add_node("b", "id == 720575940620181077")
msq.add_node("c", "id == 720575940626634789")
msq.add_edge("a", "b", regions=None, min_synapse_count=0, nt_type=None)
msq.add_edge("b", "a", regions=None, min_synapse_count=0, nt_type=None)
msq.add_edge("b", "c", regions=None, min_synapse_count=0, nt_type=None)
msq.add_edge("a", "c", regions=None, min_synapse_count=0, nt_type=None)
res = msq.search(limit=limit)
Expand Down

0 comments on commit 7649743

Please sign in to comment.