@@ -935,6 +935,14 @@ def term_info_parse_object(results, short_form):
935935 q = TransgeneExpressionHere_to_schema (termInfo ["Name" ], {"short_form" : vfbTerm .term .core .short_form })
936936 queries .append (q )
937937
938+ # Class connectivity queries — downstream and upstream partner neuron classes
939+ # Matches criteria: Class + Neuron (neuron class with indexed connectivity data)
940+ if termInfo ["SuperTypes" ] and contains_all_tags (termInfo ["SuperTypes" ], ["Class" , "Neuron" ]):
941+ q = DownstreamClassConnectivity_to_schema (termInfo ["Name" ], {"short_form" : vfbTerm .term .core .short_form })
942+ queries .append (q )
943+ q = UpstreamClassConnectivity_to_schema (termInfo ["Name" ], {"short_form" : vfbTerm .term .core .short_form })
944+ queries .append (q )
945+
938946 # For individuals that are painted domains of anatomical regions, add parent class queries
939947 if termInfo ["IsIndividual" ] and termInfo ["Technique" ] and any ('computer' in t .lower () for t in termInfo ["Technique" ]):
940948 anatomical_classes = []
@@ -1434,6 +1442,44 @@ def NeuronRegionConnectivityQuery_to_schema(name, take_default):
14341442 return Query (query = query , label = label , function = function , takes = takes , preview = preview , preview_columns = preview_columns )
14351443
14361444
1445+ def DownstreamClassConnectivity_to_schema (name , take_default ):
1446+ """
1447+ Schema for downstream class connectivity query.
1448+ Shows which neuron classes receive synapses from this neuron class.
1449+ Matching criteria: Class + Neuron
1450+ Query chain: Solr downstream_connectivity_query field
1451+ """
1452+ query = "DownstreamClassConnectivity"
1453+ label = f"Downstream connectivity classes for { name } "
1454+ function = "get_downstream_class_connectivity"
1455+ takes = {
1456+ "short_form" : {"$and" : ["Class" , "Neuron" ]},
1457+ "default" : take_default ,
1458+ }
1459+ preview = 5
1460+ preview_columns = ["downstream_class" , "total_n" , "connected_n" , "percent_connected" , "pairwise_connections" , "total_weight" , "avg_weight" ]
1461+ return Query (query = query , label = label , function = function , takes = takes , preview = preview , preview_columns = preview_columns )
1462+
1463+
1464+ def UpstreamClassConnectivity_to_schema (name , take_default ):
1465+ """
1466+ Schema for upstream class connectivity query.
1467+ Shows which neuron classes send synapses to this neuron class.
1468+ Matching criteria: Class + Neuron
1469+ Query chain: Solr upstream_connectivity_query field
1470+ """
1471+ query = "UpstreamClassConnectivity"
1472+ label = f"Upstream connectivity classes for { name } "
1473+ function = "get_upstream_class_connectivity"
1474+ takes = {
1475+ "short_form" : {"$and" : ["Class" , "Neuron" ]},
1476+ "default" : take_default ,
1477+ }
1478+ preview = 5
1479+ preview_columns = ["upstream_class" , "total_n" , "connected_n" , "percent_connected" , "pairwise_connections" , "total_weight" , "avg_weight" ]
1480+ return Query (query = query , label = label , function = function , takes = takes , preview = preview , preview_columns = preview_columns )
1481+
1482+
14371483def TractsNervesInnervatingHere_to_schema (name , take_default ):
14381484 """
14391485 Schema for TractsNervesInnervatingHere query.
@@ -2924,6 +2970,172 @@ def get_neuron_region_connectivity(short_form: str, return_dataframe=True, limit
29242970 }
29252971
29262972
2973+ @with_solr_cache ('downstream_class_connectivity_query' )
2974+ def get_downstream_class_connectivity (short_form : str , return_dataframe = True , limit : int = - 1 ):
2975+ """
2976+ Retrieves downstream connectivity classes for the specified neuron class.
2977+
2978+ Reads the downstream_connectivity_query Solr field, which contains a JSON array
2979+ of vfb_query-format objects populated by the neuron_downstream_connectivity_indexer.
2980+ Each element represents one (primary_class → downstream_class) connection summary.
2981+
2982+ Matching criteria: Class + Neuron
2983+
2984+ :param short_form: short form of the neuron class
2985+ :param return_dataframe: Returns pandas DataFrame if True, otherwise returns formatted dict
2986+ :param limit: maximum number of results to return (default -1, returns all results)
2987+ :return: Downstream partner neuron classes with connectivity statistics
2988+ """
2989+ solr_field = 'downstream_connectivity_query'
2990+ try :
2991+ results = vfb_solr .search (f'id:{ short_form } ' , fl = solr_field , rows = 1 )
2992+ except Exception as e :
2993+ print (f"Error querying Solr for downstream class connectivity: { e } " )
2994+ if return_dataframe :
2995+ return pd .DataFrame ()
2996+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
2997+
2998+ if not results .hits or not results .docs or solr_field not in results .docs [0 ]:
2999+ if return_dataframe :
3000+ return pd .DataFrame ()
3001+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
3002+
3003+ raw = results .docs [0 ][solr_field ]
3004+ field_json = raw [0 ] if isinstance (raw , list ) else raw
3005+ try :
3006+ entries = json .loads (field_json )
3007+ except (json .JSONDecodeError , TypeError ) as e :
3008+ print (f"Error parsing downstream_connectivity_query JSON for { short_form } : { e } " )
3009+ if return_dataframe :
3010+ return pd .DataFrame ()
3011+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
3012+
3013+ if not isinstance (entries , list ):
3014+ entries = [entries ]
3015+
3016+ rows = []
3017+ for entry in entries :
3018+ cc = entry .get ('class_connectivity' , {})
3019+ obj = entry .get ('object' , {})
3020+ ds_id = obj .get ('short_form' , cc .get ('downstream_class_id' , '' ))
3021+ ds_label = obj .get ('label' , cc .get ('downstream_class' , '' ))
3022+ row = {
3023+ 'id' : ds_id ,
3024+ 'downstream_class' : f"[{ ds_label } ]({ ds_id } )" if ds_id else ds_label ,
3025+ 'total_n' : cc .get ('total_upstream_count' , '' ),
3026+ 'connected_n' : cc .get ('connected_upstream_count' , '' ),
3027+ 'percent_connected' : cc .get ('percent_connected' , '' ),
3028+ 'pairwise_connections' : cc .get ('pairwise_connections' , '' ),
3029+ 'total_weight' : cc .get ('total_weight' , '' ),
3030+ 'avg_weight' : cc .get ('average_weight' , '' ),
3031+ }
3032+ rows .append (row )
3033+
3034+ total_count = len (rows )
3035+ if limit != - 1 :
3036+ rows = rows [:limit ]
3037+
3038+ if return_dataframe :
3039+ df = pd .DataFrame (rows )
3040+ df = encode_markdown_links (df , ['downstream_class' ])
3041+ return df
3042+
3043+ headers = {
3044+ 'id' : {'title' : 'ID' , 'type' : 'selection_id' , 'order' : - 1 },
3045+ 'downstream_class' : {'title' : 'Downstream Class' , 'type' : 'markdown' , 'order' : 0 },
3046+ 'total_n' : {'title' : 'Total N' , 'type' : 'number' , 'order' : 1 },
3047+ 'connected_n' : {'title' : 'Connected N' , 'type' : 'number' , 'order' : 2 },
3048+ 'percent_connected' : {'title' : '% Connected' , 'type' : 'number' , 'order' : 3 },
3049+ 'pairwise_connections' : {'title' : 'Pairwise Connections' , 'type' : 'number' , 'order' : 4 },
3050+ 'total_weight' : {'title' : 'Total Weight' , 'type' : 'number' , 'order' : 5 },
3051+ 'avg_weight' : {'title' : 'Avg Weight' , 'type' : 'number' , 'order' : 6 },
3052+ }
3053+ return {'headers' : headers , 'rows' : rows , 'count' : total_count }
3054+
3055+
3056+ @with_solr_cache ('upstream_class_connectivity_query' )
3057+ def get_upstream_class_connectivity (short_form : str , return_dataframe = True , limit : int = - 1 ):
3058+ """
3059+ Retrieves upstream connectivity classes for the specified neuron class.
3060+
3061+ Reads the upstream_connectivity_query Solr field, which contains a JSON array
3062+ of vfb_query-format objects populated by the neuron_upstream_connectivity_indexer.
3063+ Each element represents one (upstream_class → primary_class) connection summary.
3064+
3065+ Matching criteria: Class + Neuron
3066+
3067+ :param short_form: short form of the neuron class
3068+ :param return_dataframe: Returns pandas DataFrame if True, otherwise returns formatted dict
3069+ :param limit: maximum number of results to return (default -1, returns all results)
3070+ :return: Upstream partner neuron classes with connectivity statistics
3071+ """
3072+ solr_field = 'upstream_connectivity_query'
3073+ try :
3074+ results = vfb_solr .search (f'id:{ short_form } ' , fl = solr_field , rows = 1 )
3075+ except Exception as e :
3076+ print (f"Error querying Solr for upstream class connectivity: { e } " )
3077+ if return_dataframe :
3078+ return pd .DataFrame ()
3079+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
3080+
3081+ if not results .hits or not results .docs or solr_field not in results .docs [0 ]:
3082+ if return_dataframe :
3083+ return pd .DataFrame ()
3084+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
3085+
3086+ raw = results .docs [0 ][solr_field ]
3087+ field_json = raw [0 ] if isinstance (raw , list ) else raw
3088+ try :
3089+ entries = json .loads (field_json )
3090+ except (json .JSONDecodeError , TypeError ) as e :
3091+ print (f"Error parsing upstream_connectivity_query JSON for { short_form } : { e } " )
3092+ if return_dataframe :
3093+ return pd .DataFrame ()
3094+ return {'headers' : {}, 'rows' : [], 'count' : 0 }
3095+
3096+ if not isinstance (entries , list ):
3097+ entries = [entries ]
3098+
3099+ rows = []
3100+ for entry in entries :
3101+ cc = entry .get ('class_connectivity' , {})
3102+ obj = entry .get ('object' , {})
3103+ us_id = obj .get ('short_form' , cc .get ('upstream_class_id' , '' ))
3104+ us_label = obj .get ('label' , cc .get ('upstream_class' , '' ))
3105+ row = {
3106+ 'id' : us_id ,
3107+ 'upstream_class' : f"[{ us_label } ]({ us_id } )" if us_id else us_label ,
3108+ 'total_n' : cc .get ('total_upstream_count' , '' ),
3109+ 'connected_n' : cc .get ('connected_upstream_count' , '' ),
3110+ 'percent_connected' : cc .get ('percent_connected' , '' ),
3111+ 'pairwise_connections' : cc .get ('pairwise_connections' , '' ),
3112+ 'total_weight' : cc .get ('total_weight' , '' ),
3113+ 'avg_weight' : cc .get ('average_weight' , '' ),
3114+ }
3115+ rows .append (row )
3116+
3117+ total_count = len (rows )
3118+ if limit != - 1 :
3119+ rows = rows [:limit ]
3120+
3121+ if return_dataframe :
3122+ df = pd .DataFrame (rows )
3123+ df = encode_markdown_links (df , ['upstream_class' ])
3124+ return df
3125+
3126+ headers = {
3127+ 'id' : {'title' : 'ID' , 'type' : 'selection_id' , 'order' : - 1 },
3128+ 'upstream_class' : {'title' : 'Upstream Class' , 'type' : 'markdown' , 'order' : 0 },
3129+ 'total_n' : {'title' : 'Total N' , 'type' : 'number' , 'order' : 1 },
3130+ 'connected_n' : {'title' : 'Connected N' , 'type' : 'number' , 'order' : 2 },
3131+ 'percent_connected' : {'title' : '% Connected' , 'type' : 'number' , 'order' : 3 },
3132+ 'pairwise_connections' : {'title' : 'Pairwise Connections' , 'type' : 'number' , 'order' : 4 },
3133+ 'total_weight' : {'title' : 'Total Weight' , 'type' : 'number' , 'order' : 5 },
3134+ 'avg_weight' : {'title' : 'Avg Weight' , 'type' : 'number' , 'order' : 6 },
3135+ }
3136+ return {'headers' : headers , 'rows' : rows , 'count' : total_count }
3137+
3138+
29273139@with_solr_cache ('images_neurons' )
29283140def get_images_neurons (short_form : str , return_dataframe = True , limit : int = - 1 ):
29293141 """
0 commit comments