@@ -1262,7 +1262,14 @@ def SimilarMorphologyTo_to_schema(name, take_default):
12621262 "default" : take_default ,
12631263 }
12641264 preview = 5
1265- preview_columns = ["id" ,"score" ,"name" ,"tags" ,"thumbnail" ]
1265+ # Match the v1.10.1 SimilarMorphologyTo* preview shape and add the new
1266+ # type column this PR exposes — keeps term-info previews in sync with
1267+ # the full /run_query response. source/source_id are intentionally
1268+ # omitted; they're noisy in compact previews and only meaningful when
1269+ # the user opens the full table. Keep score before name so preview
1270+ # sorting continues to default to score-descending under the current
1271+ # header-order-based preview sort selection.
1272+ preview_columns = ["id" , "score" , "name" , "tags" , "type" , "template" , "technique" , "thumbnail" ]
12661273
12671274 return Query (query = query , label = label , function = function , takes = takes , preview = preview , preview_columns = preview_columns )
12681275
@@ -2453,19 +2460,50 @@ def get_similar_neurons(neuron, similarity_score='NBLAST_score', return_datafram
24532460 count_df = pd .DataFrame .from_records (get_dict_cursor ()(count_results ))
24542461 total_count = count_df ['total_count' ][0 ] if not count_df .empty else 0
24552462
2456- main_query = f"""MATCH (c1:Class)<-[:INSTANCEOF]-(n1)-[r:has_similar_morphology_to]-(n2)-[:INSTANCEOF]->(c2:Class)
2463+ # Extends the v1.10.1 channel/template/technique pattern. Adds:
2464+ # - type = pipe-joined parent class labels (n2 -[:INSTANCEOF]-> Class)
2465+ # matches v2 prod's `Type` column from SOLR's `types` collection
2466+ # - template = `[symbol](short_form)` markdown of the alignment template
2467+ # - technique = imaging technique label (channel -[:is_specified_output_of]-> Class)
2468+ #
2469+ # Each OPTIONAL branch is wrapped in a CALL subquery so the outer query
2470+ # carries one row per n2 throughout. Without this, an n2 with N
2471+ # cross-references × M alignments × K types would produce N×M×K rows
2472+ # that DISTINCT then collapses at the end — wasteful, especially on
2473+ # densely-typed neurons. Each subquery either aggregates (for `type`)
2474+ # or LIMIT 1s (for the single representative cross-ref / alignment
2475+ # the V2 row needs), so n2 stays the row key end-to-end.
2476+ main_query = f"""MATCH (c1:Class)<-[:INSTANCEOF]-(n1:Individual)-[r:has_similar_morphology_to]-(n2:Individual)-[:INSTANCEOF]->(c2:Class)
24572477 WHERE n1.short_form = '{ neuron } ' and exists(r.{ similarity_score } )
2458- WITH c1, n1, r, n2, c2
2459- OPTIONAL MATCH (n2)-[rx:database_cross_reference]->(site:Site)
2460- WHERE site.is_data_source
2461- WITH n2, r, c2, rx, site
2462- OPTIONAL MATCH (n2)<-[:depicts]-(:Individual)-[ri:in_register_with]->(:Template)-[:depicts]->(templ:Template)
2463- RETURN DISTINCT n2.short_form as id,
2464- apoc.text.format("[%s](%s)", [n2.label, n2.short_form]) AS name,
2478+ WITH DISTINCT r, n2
2479+ CALL {{
2480+ WITH n2
2481+ OPTIONAL MATCH (n2)-[:INSTANCEOF]->(typ:Class)
2482+ RETURN apoc.text.join([l IN collect(DISTINCT typ.label) WHERE l IS NOT NULL AND l <> ''], '|') AS type
2483+ }}
2484+ CALL {{
2485+ WITH n2
2486+ OPTIONAL MATCH (n2)-[rx:database_cross_reference]->(site:Site)
2487+ WHERE site.is_data_source
2488+ WITH rx, site LIMIT 1
2489+ RETURN rx, site
2490+ }}
2491+ CALL {{
2492+ WITH n2
2493+ OPTIONAL MATCH (n2)<-[:depicts]-(channel:Individual)-[ri:in_register_with]->(:Template)-[:depicts]->(templ:Template)
2494+ OPTIONAL MATCH (channel)-[:is_specified_output_of]->(technique:Class)
2495+ WITH ri, templ, technique LIMIT 1
2496+ RETURN ri, templ, technique
2497+ }}
2498+ RETURN n2.short_form as id,
2499+ apoc.text.format("[%s](%s)", [n2.label, n2.short_form]) AS name,
24652500 r.{ similarity_score } [0] AS score,
2466- apoc.text.join(n2.uniqueFacets, '|') AS tags,
2501+ apoc.text.join(coalesce(n2.uniqueFacets, []), '|') AS tags,
2502+ type,
24672503 REPLACE(apoc.text.format("[%s](%s)",[COALESCE(site.symbol[0],site.label),site.short_form]), '[null](null)', '') AS source,
24682504 REPLACE(apoc.text.format("[%s](%s)",[rx.accession[0], (site.link_base[0] + rx.accession[0])]), '[null](null)', '') AS source_id,
2505+ REPLACE(apoc.text.format("[%s](%s)",[COALESCE(templ.symbol[0],templ.label),templ.short_form]), '[null](null)', '') AS template,
2506+ coalesce(technique.label, '') AS technique,
24692507 REPLACE(apoc.text.format("[](%s)",[COALESCE(n2.symbol[0],n2.label) + " aligned to " + COALESCE(templ.symbol[0],templ.label), REPLACE(COALESCE(ri.thumbnail[0],""),"thumbnailT.png","thumbnail.png"), COALESCE(n2.symbol[0],n2.label) + " aligned to " + COALESCE(templ.symbol[0],templ.label), templ.short_form + "," + n2.short_form]), "[](null)", "") as thumbnail
24702508 ORDER BY score DESC"""
24712509
@@ -2478,9 +2516,13 @@ def get_similar_neurons(neuron, similarity_score='NBLAST_score', return_datafram
24782516 # Convert the results to a DataFrame
24792517 df = pd .DataFrame .from_records (get_dict_cursor ()(results ))
24802518
2481- columns_to_encode = ['name' , 'source' , 'source_id' , 'thumbnail' ]
2519+ # template is a `[symbol](short_form)` markdown link — must be encoded the
2520+ # same way as name/source/source_id/thumbnail so the V2 frontend's link
2521+ # parser renders it consistently. type/technique are plain text and
2522+ # don't need encoding.
2523+ columns_to_encode = ['name' , 'source' , 'source_id' , 'template' , 'thumbnail' ]
24822524 df = encode_markdown_links (df , columns_to_encode )
2483-
2525+
24842526 if return_dataframe :
24852527 return df
24862528 else :
@@ -2490,8 +2532,11 @@ def get_similar_neurons(neuron, similarity_score='NBLAST_score', return_datafram
24902532 "score" : {"title" : "Score" , "type" : "numeric" , "order" : 1 , "sort" : {0 : "Desc" }},
24912533 "name" : {"title" : "Name" , "type" : "markdown" , "order" : 1 , "sort" : {1 : "Asc" }},
24922534 "tags" : {"title" : "Tags" , "type" : "tags" , "order" : 2 },
2493- "source" : {"title" : "Source" , "type" : "metadata" , "order" : 3 },
2494- "source_id" : {"title" : "Source ID" , "type" : "metadata" , "order" : 4 },
2535+ "type" : {"title" : "Type" , "type" : "text" , "order" : 3 },
2536+ "source" : {"title" : "Source" , "type" : "metadata" , "order" : 4 },
2537+ "source_id" : {"title" : "Source ID" , "type" : "metadata" , "order" : 5 },
2538+ "template" : {"title" : "Template" , "type" : "markdown" , "order" : 6 },
2539+ "technique" : {"title" : "Imaging Technique" , "type" : "text" , "order" : 7 },
24952540 "thumbnail" : {"title" : "Thumbnail" , "type" : "markdown" , "order" : 9 }
24962541 },
24972542 "rows" : [
@@ -2502,8 +2547,11 @@ def get_similar_neurons(neuron, similarity_score='NBLAST_score', return_datafram
25022547 "name" ,
25032548 "score" ,
25042549 "tags" ,
2550+ "type" ,
25052551 "source" ,
25062552 "source_id" ,
2553+ "template" ,
2554+ "technique" ,
25072555 "thumbnail"
25082556 ]
25092557 }
0 commit comments