From be5ee3629ac5a2913e6d1546b9b3fe8e70c44afa Mon Sep 17 00:00:00 2001 From: Philipp Schlegel Date: Fri, 30 Aug 2024 12:31:42 +0100 Subject: [PATCH 1/3] remove hard-wired link types & use (cached) call to remote instance --- pymaid/config.py | 81 +++------------------------------------- pymaid/fetch/__init__.py | 4 +- pymaid/upload.py | 4 +- 3 files changed, 10 insertions(+), 79 deletions(-) diff --git a/pymaid/config.py b/pymaid/config.py index 0c219d1..3cafc55 100644 --- a/pymaid/config.py +++ b/pymaid/config.py @@ -16,6 +16,8 @@ import numpy as np +from functools import lru_cache + logger = logging.getLogger('pymaid') def default_logging(): @@ -116,82 +118,11 @@ def ipywidgets_installed(): tqdm = tqdm_classic trange = trange_classic -# Hard-wired connector types. Use this to check for what's on the server: -# types = remote_instance.fetch(remote_instance._get_connector_types_url()) -link_types = [{'name': 'Presynaptic', - 'type': 'Synaptic', - 'type_id': 'synaptic-connector', - 'relation': 'presynaptic_to', - 'isreciprocal': False, - 'cardinality': 1, - 'partner_reference': 'outgoing', - 'partner_relation': 'postsynaptic_to', - 'relation_id': 14}, - {'name': 'Postsynaptic', - 'type': 'Synaptic', - 'type_id': 'synaptic-connector', - 'relation': 'postsynaptic_to', - 'isreciprocal': False, - 'cardinality': None, - 'partner_reference': 'incoming', - 'partner_relation': 'presynaptic_to', - 'relation_id': 8}, - {'name': 'Abutting', - 'type': 'Abutting', - 'type_id': 'abutting-connector', - 'relation': 'abutting', - 'isreciprocal': True, - 'cardinality': None, - 'partner_reference': 'abutting', - 'partner_relation': 'abutting', - 'relation_id': 54650}, - {'name': 'Gap junction', - 'type': 'Gap junction', - 'type_id': 'gapjunction-connector', - 'relation': 'gapjunction_with', - 'isreciprocal': True, - 'cardinality': 2, - 'partner_reference': 'gapjunction', - 'partner_relation': 'gapjunction_with', - 'relation_id': 686364}, - {'name': 'Tight junction', - 'type': 'Tight junction', - 'type_id': 'tightjunction-connector', - 'relation': 'tightjunction_with', - 'isreciprocal': True, - 'cardinality': 2, - 'partner_reference': 'tightjunction', - 'partner_relation': 'tightjunction_with', - 'relation_id': 10686621}, - {'name': 'Desmosome', - 'type': 'Desmosome', - 'type_id': 'desmosome-connector', - 'relation': 'desmosome_with', - 'isreciprocal': True, - 'cardinality': 2, - 'partner_reference': 'desmosome', - 'partner_relation': 'desmosome_with', - 'relation_id': 10686622}, - {'name': 'Attachment', - 'type': 'Attachment', - 'type_id': 'attachment-connector', - 'relation': 'attached_to', - 'isreciprocal': False, - 'cardinality': None, - 'partner_reference': 'attachment', - 'partner_relation': 'close_to', - 'relation_id': 5989640}, - {'name': 'Close to', - 'type': 'Spatial', - 'type_id': 'spatial-connector', - 'relation': 'close_to', - 'isreciprocal': True, - 'cardinality': None, - 'partner_reference': 'close_object', - 'partner_relation': 'close_to', - 'relation_id': 6216812}] - compact_skeleton_relations = {0: 'presynaptic_to', 1: 'postsynaptic_to', 2: 'gapjunction_with', 3: 'abutting'} + +@lru_cache +def get_link_types(remote_instance): + return remote_instance.fetch(remote_instance._get_connector_types_url()) \ No newline at end of file diff --git a/pymaid/fetch/__init__.py b/pymaid/fetch/__init__.py index bcc985e..d0e03ac 100644 --- a/pymaid/fetch/__init__.py +++ b/pymaid/fetch/__init__.py @@ -1225,7 +1225,7 @@ def get_connectors(x, relation_type=None, tags=None, remote_instance=None): # Map hardwire connector type ID to their type name # ATTENTION: "attachment" can be part of any connector type - rel_ids = {r['relation_id']: r for r in config.link_types} + rel_ids = {r['relation_id']: r for r in config.get_link_types(remote_instance)} # Get connector type IDs cn_ids = {k: v[0][3] for k, v in data['partners'].items()} @@ -1314,7 +1314,7 @@ def get_connector_links(x, with_tags=False, chunk_size=50, df_collection = [] tags = {} - link_types = [l['relation'] for l in config.link_types] + link_types = [l['relation'] for l in config.get_link_types(remote_instance)] with config.tqdm(desc='Fetching links', total=len(skids), disable=config.pbar_hide, diff --git a/pymaid/upload.py b/pymaid/upload.py index bb038dc..5c4bb4a 100644 --- a/pymaid/upload.py +++ b/pymaid/upload.py @@ -1336,7 +1336,7 @@ def link_connector(links, remote_instance=None): (node_id, connector_id, 'presynaptic_to') will make node presynaptic to connector (node_id, connector_id, 'postsynaptic_to') will make node postsynaptic to connector - See ``pymaid.config.link_types`` for allowed `relation`. + See ``pymaid.config.get_link_types(remote_instance)`` for allowed `relation`. remote_instance : CatmaidInstance, optional If not passed directly, will try using global. @@ -1368,7 +1368,7 @@ def link_connector(links, remote_instance=None): '(node_id, connector_id, relation)') # Make sure all relations are correct - ALLOWED_RELATIONS = [l['relation'] for l in config.link_types] + ALLOWED_RELATIONS = [l['relation'] for l in config.get_link_types(remote_instance)] if any([l[2] not in ALLOWED_RELATIONS for l in links]): raise ValueError('Tuple relationships must be either: {}'.format(', '.join(ALLOWED_RELATIONS))) From 40b3733e48d8df1a1aad7f303f9b7d22e91bac86 Mon Sep 17 00:00:00 2001 From: Philipp Schlegel Date: Fri, 30 Aug 2024 12:35:48 +0100 Subject: [PATCH 2/3] get_connectors: use link "name" instead of link "type" (see comment) --- pymaid/fetch/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pymaid/fetch/__init__.py b/pymaid/fetch/__init__.py index d0e03ac..c5d6688 100644 --- a/pymaid/fetch/__init__.py +++ b/pymaid/fetch/__init__.py @@ -1230,9 +1230,11 @@ def get_connectors(x, relation_type=None, tags=None, remote_instance=None): # Get connector type IDs cn_ids = {k: v[0][3] for k, v in data['partners'].items()} - # Map type ID to relation (also note conversion of connector ID to integer) - cn_type = {int(k): rel_ids.get(v, {'type': 'unknown'})['type'] - for k, v in cn_ids.items()} + # Map type ID to relation; also note: + # 1. Conversion of connector ID to integer) + # 2. We're using the "name" field of the relation - this used to be "type" but + # on VFB CATMAID "type" is always "Synaptic" while name can be "Presynaptic" or "Postsynaptic" + cn_type = {int(k): rel_ids.get(v, {}).get('name', 'unknown') for k, v in cn_ids.items()} # Map connector ID to connector type df['type'] = df.connector_id.map(cn_type) From 801f68fefc83e1bda2ea9e80ecb1c7c8c178d153 Mon Sep 17 00:00:00 2001 From: Philipp Schlegel Date: Fri, 30 Aug 2024 12:44:59 +0100 Subject: [PATCH 3/3] CatmaidInstance: add custom hash function --- pymaid/client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pymaid/client.py b/pymaid/client.py index 0148daa..fa438b1 100644 --- a/pymaid/client.py +++ b/pymaid/client.py @@ -609,6 +609,10 @@ def __copy__(self): def __deepcopy__(self): return self.copy() + def __hash__(self): + """Hash based on server, api_token, http user, http password and project_id.""" + return hash((self.server, self.api_token, self.http_user, self.http_password, self.project_id)) + def copy(self): """Returns a copy of this CatmaidInstance. Does not copy cache.""" return CatmaidInstance(server=self.server,