|
| 1 | +# catmaid_interface: A library for interacting with CATMAID projects through python |
| 2 | +# Started by Tom Kazimiers (1/2013) |
| 3 | +# Adapted by Albert Cardona (1/2013) |
| 4 | +# Continued since by Casey Schneider-Mizell with a lot of assistance from Andrew Champion |
| 5 | + |
| 6 | +import json |
| 7 | +import requests |
| 8 | + |
| 9 | +# requests.py authentication class for a CATMAID server with both token authentication and HTTP Basic authentication |
| 10 | +class catmaid_auth_token( requests.auth.HTTPBasicAuth ): |
| 11 | + def __init__(self, token, authname=None, authpass=None): |
| 12 | + self.token = token |
| 13 | + super(catmaid_auth_token, self).__init__(authname, authpass) |
| 14 | + def __call__(self, r): |
| 15 | + r.headers['X-Authorization'] = 'Token {}'.format(self.token) |
| 16 | + return super(catmaid_auth_token, self).__call__(r) |
| 17 | + |
| 18 | +# Project info |
| 19 | +def set_project_opts( baseurl, project_id, token, authname = None, authpass = None): |
| 20 | + proj_opts = dict() |
| 21 | + proj_opts['baseurl'] = baseurl |
| 22 | + proj_opts['project_id'] = project_id |
| 23 | + proj_opts['token'] = token |
| 24 | + proj_opts['authname'] = authname |
| 25 | + proj_opts['authpass'] = authpass |
| 26 | + return proj_opts |
| 27 | + |
| 28 | +# get_neuron_name: Given a skeleton ID, fetch the neuron name |
| 29 | +def get_neuron_name( skeleton_id, proj_opts ): |
| 30 | + url = proj_opts['baseurl'] + '/{}/skeleton/{}/neuronname'.format( proj_opts['project_id'], skeleton_id) |
| 31 | + d = requests.get( url, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ).json() |
| 32 | + return d['neuronname'] |
| 33 | + |
| 34 | +# skeleton_object: Fetch full JSON info (plus a few other useful things) for a skeleton |
| 35 | +# sk[0] is the list of skeleton nodes |
| 36 | +# sk[1] is the list of connectors |
| 37 | +# sk[2] is tags |
| 38 | +# sk[3] is the skeleton id |
| 39 | +# sk[4] is the neuron name |
| 40 | +# sk[5] is the number of postsynaptic targets for each presynaptic connector |
| 41 | +def get_skeleton_json( skeleton_id, proj_opts, withtags = True): |
| 42 | + if withtags: |
| 43 | + url = proj_opts['baseurl'] + '/{}/{}/1/1/compact-skeleton'.format( proj_opts['project_id'], skeleton_id) |
| 44 | + else: |
| 45 | + url = proj_opts['baseurl'] + '/{}/{}/1/0/compact-skeleton'.format( proj_opts['project_id'], skeleton_id) |
| 46 | + d = requests.get( url, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ).json() |
| 47 | + d.append( skeleton_id ) |
| 48 | + d.append( get_neuron_name( skeleton_id, proj_opts ) ) |
| 49 | + presyn_weight = post_synaptic_count( [conn[1] for conn in d[1] if conn[2] == 0], proj_opts ) |
| 50 | + if presyn_weight!=None: |
| 51 | + d.append([ [cid, presyn_weight[cid]] for cid in presyn_weight.keys() ]) |
| 52 | + else: |
| 53 | + d.append([]) |
| 54 | + return d |
| 55 | + |
| 56 | +# add_annotation: Add a single annotation to a list of skeleton IDs. |
| 57 | +def add_annotation( annotation_list, id_list, proj_opts ): |
| 58 | + if type(annotation_list) is not list: |
| 59 | + raise TypeError('annotation_list must be a list even if just one element') |
| 60 | + if type(id_list) is not list: |
| 61 | + raise TypeError('id_list must be a list even if just one element') |
| 62 | + |
| 63 | + url = proj_opts['baseurl'] + '/{}/annotations/add'.format( proj_opts['project_id']) |
| 64 | + postdata = dict() |
| 65 | + for i, anno in enumerate(annotation_list): |
| 66 | + postdata['annotations[{}]'.format(i)] = anno |
| 67 | + for i, id in enumerate(id_list): |
| 68 | + postdata['skeleton_ids[{}]'.format(i)] = id |
| 69 | + d = requests.post( url, data = postdata, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ) |
| 70 | + return d |
| 71 | + |
| 72 | +# get_annotation_dict: Gets the dict of annotation_id to annotation string for a project |
| 73 | +def get_annotation_dict( proj_opts ): |
| 74 | + url = proj_opts['baseurl'] + '/{}/annotations/'.format(proj_opts['project_id']) |
| 75 | + all_annotations = requests.get( url, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ).json() |
| 76 | + anno_dict = { item['name']:item['id'] for item in all_annotations['annotations'] } |
| 77 | + return anno_dict |
| 78 | + |
| 79 | +# get_ids_from_annotation: Given an annotation id, pull all skeletons with that annotation |
| 80 | +def get_ids_from_annotation( annotation_id_list, proj_opts ): |
| 81 | + if type(annotation_id_list) is not list: |
| 82 | + raise TypeError('annotation_id_list must be a list even if just one element') |
| 83 | + url = proj_opts['baseurl'] + '/{}/annotations/query-targets'.format( proj_opts['project_id'] ) |
| 84 | + skids = [] |
| 85 | + for anno_id in annotation_id_list: |
| 86 | + postdata = { 'annotated_with' : anno_id } |
| 87 | + d = requests.post( url, data = postdata, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ).json() |
| 88 | + ids_returned = [ item['skeleton_ids'][0] for item in d['entities'] ] |
| 89 | + skids = skids + ids_returned |
| 90 | + return list( set( skids ) ) |
| 91 | + |
| 92 | +# get_ids_by_nodecount: Ids of all skeletons with more nodes than min_nodes |
| 93 | +def get_ids_by_nodecount( min_nodes, proj_opts ): |
| 94 | + url = proj_opts['baseurl'] + '/{}/skeletons/'.format( proj_opts['project_id'] ) |
| 95 | + d = requests.get( url, data = {'nodecount_gt': min_nodes}, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ) |
| 96 | + return d |
| 97 | + |
| 98 | +# get_connected_skeleton_info: get skeleton ids, nodes, and number of synapses connected upstream/downstream for a list of ids. |
| 99 | +def get_connected_skeleton_info( id_list, proj_opts ): |
| 100 | + if type(id_list) is not list: |
| 101 | + raise TypeError('id_list must be a list even if just one element') |
| 102 | + |
| 103 | + url = proj_opts['baseurl'] + '/{}/skeletons/connectivity'.format( proj_opts['project_id'] ) |
| 104 | + postdata = {'boolean_op' : 'OR'} |
| 105 | + for i, id in enumerate( id_list ): |
| 106 | + postdata['source_skeleton_ids[{}]'.format(i)] = id |
| 107 | + d = requests.post( url, data = postdata, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] ) ).json() |
| 108 | + connected_inds = dict() |
| 109 | + connected_inds['incoming'] = {} |
| 110 | + connected_inds['outgoing'] = {} |
| 111 | + for id in d['incoming'].keys(): |
| 112 | + connected_inds['incoming'][int(id)] = d['incoming'][id] |
| 113 | + for id in d['outgoing'].keys(): |
| 114 | + connected_inds['outgoing'][int(id)] = d['outgoing'][id] |
| 115 | + return connected_inds |
| 116 | + |
| 117 | +# Grow a list of skeleton ids along the connectivity network |
| 118 | +def increase_id_list( id_list, proj_opts, min_pre=0, min_post=0, hops=1): |
| 119 | + if type(id_list) is not list: |
| 120 | + raise TypeError('id_list must be a list even if just one element') |
| 121 | + |
| 122 | + postdata = {'n_circles': hops, |
| 123 | + 'min_pre': min_pre, |
| 124 | + 'min_post': min_post} |
| 125 | + for i, id in enumerate(id_list): |
| 126 | + postdata[ 'skeleton_ids[{}]'.format(i) ] = id |
| 127 | + |
| 128 | + url = proj_opts['baseurl'] + '/{}/graph/circlesofhell'.format(proj_opts['project_id']) |
| 129 | + d = requests.post( url, data = postdata, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] )).json() |
| 130 | + |
| 131 | + for id in id_list_base: |
| 132 | + id_list.append( id ) |
| 133 | + id_list = list(set(id_list)) |
| 134 | + return id_list |
| 135 | + |
| 136 | +# post_synaptic_count: Count how many postsynaptic targets are associated with each connector in a list of connectors |
| 137 | +def post_synaptic_count( connector_list, proj_opts ): |
| 138 | + url = proj_opts['baseurl'] + '/{}/connector/skeletons'.format(proj_opts['project_id']) |
| 139 | + opts = {} |
| 140 | + for ind, id in enumerate(connector_list): |
| 141 | + opts[ 'connector_ids[{}]'.format(ind) ] = id |
| 142 | + d = requests.post( url, data = opts, auth = catmaid_auth_token( proj_opts['token'], proj_opts['authname'], proj_opts['authpass'] )).json() |
| 143 | + nps = dict() |
| 144 | + for conn in d: |
| 145 | + nps[conn[0]] = len( conn[1]['postsynaptic_to'] ) |
| 146 | + return nps |
| 147 | + |
| 148 | +# write_skeletons_from_list: pull JSON files (plus key details) for |
| 149 | +def write_skeletons_from_list( id_list, proj_opts ): |
| 150 | + for id in id_list: |
| 151 | + sk = get_skeleton_json( id, proj_opts ) |
| 152 | + f_nodes = open( 'sk_' + str(id) + '.json' ,'w') |
| 153 | + json.dump(sk,f_nodes) |
| 154 | + f_nodes.close() |
| 155 | + |
| 156 | +####### |
| 157 | + |
| 158 | +# Parse a file to a list of skeleton ids. |
| 159 | +def import_ids(filename): |
| 160 | + f = open(filename,'r') |
| 161 | + id_list = [] |
| 162 | + for line in f: |
| 163 | + if int(line) == -1: |
| 164 | + f.close() |
| 165 | + return [] |
| 166 | + else: |
| 167 | + id_list.append(int(line)) |
| 168 | + f.close() |
| 169 | + return id_list |
0 commit comments