mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-16 21:37:59 +08:00
This splits the backend into two parts: the local backend for desktop cellxgene and the AWS backend for hosted cellxgene. The local backend is in local_server while the hosted remains in server. The general idea is to copy everything from server to local_server, pull unneeded stuff out of local_server, and keep server as-is for this PR. Not touching server means all the infra and deployment code will continue working just as it did before so we can make those changes incrementally.
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
from abc import ABCMeta, abstractmethod
|
|
|
|
import fastobo
|
|
import fsspec
|
|
|
|
from local_server.common.errors import OntologyLoadFailure
|
|
from local_server.common.utils.type_conversion_utils import get_schema_type_hint_of_array
|
|
|
|
|
|
class Annotations(metaclass=ABCMeta):
|
|
""" baseclass for annotations, including ontologies"""
|
|
|
|
""" our default ontology is the PURL for the Cell Ontology.
|
|
See http://www.obofoundry.org/ontology/cl.html """
|
|
DefaultOnotology = "http://purl.obolibrary.org/obo/cl.obo"
|
|
|
|
def __init__(self):
|
|
self.ontology_data = None
|
|
|
|
def load_ontology(self, path):
|
|
"""Load and parse ontologies - currently support OBO files only."""
|
|
if path is None:
|
|
path = self.DefaultOnotology
|
|
|
|
try:
|
|
with fsspec.open(path) as f:
|
|
obo = fastobo.iter(f)
|
|
terms = filter(lambda stanza: type(stanza) is fastobo.term.TermFrame, obo)
|
|
names = [tag.name for term in terms for tag in term if type(tag) is fastobo.term.NameClause]
|
|
self.ontology_data = names
|
|
|
|
except FileNotFoundError as e:
|
|
raise OntologyLoadFailure("Unable to find OBO ontology path") from e
|
|
|
|
except SyntaxError as e:
|
|
raise OntologyLoadFailure("Syntax error loading OBO ontology") from e
|
|
|
|
except Exception as e:
|
|
raise OntologyLoadFailure("Error loading OBO file") from e
|
|
|
|
def get_schema(self, data_adaptor):
|
|
schema = []
|
|
labels = self.read_labels(data_adaptor)
|
|
if labels is not None and not labels.empty:
|
|
for col in labels.columns:
|
|
col_schema = dict(name=col, writable=True)
|
|
col_schema.update(get_schema_type_hint_of_array(labels[col]))
|
|
schema.append(col_schema)
|
|
|
|
return schema
|
|
|
|
@abstractmethod
|
|
def set_collection(self, name):
|
|
"""set or create a new annotation collection"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def read_labels(self, data_adaptor):
|
|
"""Return the labels as a pandas.DataFrame"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def write_labels(self, df, data_adaptor):
|
|
"""Write the labels (df) to a persistent storage such that it can later be read"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def update_parameters(self, parameters, data_adaptor):
|
|
"""Update configuration parameters that describe information about the annotations feature"""
|
|
pass
|