def connected(start): log.debug(start) blob = data_sgd.neurons_connectivity(start)#, limit=9999) edges = blob['edges'] neurons = {} types = {} rows = [] start_type = None sc = OntId(start).curie for e in edges: s, p, o = e['sub'], e['pred'], e['obj'] if p == 'operand': continue if s.startswith('_:'): if s not in neurons: neurons[s] = [] types[s] = {} otp = OntTerm(p) oto = OntTerm(o) neurons[s].append((otp, oto)) if o == sc: start_type = otp if oto not in types[s]: types[s][oto] = [] types[s][oto].append(otp) for v in neurons.values(): v.sort() return OntTerm(start), start_type, neurons, types
def route_dynamic(path): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None try: j = sgd.dispatch(path, **args) except rHTTPError as e: log.exception(e) abort(e.response.status_code) # DO NOT PASS ALONG THE MESSAGE except ValueError as e: log.exception(e) abort(404) if j is None or 'edges' not in j or not j['edges']: log.error(pformat(j)) log.debug(sgd._last_url) return abort(400) prov = [ hfn.titletag(f'Dynamic query result for {path}'), f'<meta name="date" content="{UTCNOWISO()}">', f'<link rel="http://www.w3.org/ns/prov#wasGeneratedBy" href="{wgb}">', '<meta name="representation" content="SciGraph">', f'<link rel="http://www.w3.org/ns/prov#wasDerivedFrom" href="{sgd._last_url}">' ] kwargs = {'json': cleanBad(j), 'html_head': prov} tree, extras = creatTree(*Query(None, None, direction, None), **kwargs) #print(extras.hierarhcy) #print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [ OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n ] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return hfn.htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return hfn.htmldoc(extras.html, other=prov, styles=hfn.tree_styles)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # PLEASE DO NOT PUT PMIDs as external ids!!! # FIXME idlib PMID(thing) urg the regex state machine is so simple ;_; if self.id.startswith('PMID:'): log.warning('PMIDs should never be External IDs!') self._term = fake self.s = OntId(self.id).URIRef return self._term = OntTerm(self.id) self.s = self._term.URIRef
def query_scigraph_for_curies(self, label: str, prefixes:List[str] = ['UBERON', 'ILX']) -> list: curies = [] # return [] # for prefix in prefixes: # BUG: prefixes cant be used because it gives random errors if the prefix isn't exact for prefix in prefixes: neighbors = [v.OntTerm for v in OntTerm.query(label=label.strip(), prefix=prefix)] if not neighbors: continue for neighbor in neighbors: oid = OntId(neighbor) curies.append(oid.curie) return curies
def res_stats(res): hrm = [(o, n['id']) for o, r in res for n in r['nodes']] hrmt = len(hrm) ntotal = len(set(hrm)) assert hrmt == ntotal nunique = len(set(t for o, t in hrm)) dupes = [(t, c) for t, c in Counter([t for o, t in hrm]).most_common() if c > 1] ndupes = len(dupes) total_extra = sum(c for t, c in dupes) - ndupes many = [(c, OntTerm(t)) for t, c in dupes if c > 2] # the extra 7142 terms are the result of 6695 terms that # appear more than once across multiple organs breakpoint()
def get_curies_from_scigraph_label_query(label: str, prefixes: List[str] = [ 'UBERON', 'ILX', 'PAXRAT' ]) -> list: curies = set() for prefix in prefixes: # TODO: if not stipped the label will return nothing. Seems to be trailing spaces neighbors = [ v.OntTerm for v in OntTerm.query(label=label.strip(), prefix=prefix) ] if not neighbors: continue for neighbor in neighbors: curies.add(OntId(neighbor).curie) return list(curies)
def route_sparc_dynamic(path): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None j = data_sgd.dispatch(path, **args) #breakpoint() if not j['edges']: log.error(pprint(j)) return abort(400) kwargs = {'json': j} tree, extras = creatTree(*Query(None, None, direction, None), **kwargs) #print(extras.hierarhcy) print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [ OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n ] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return htmldoc(extras.html, styles=hfn.tree_styles)
def server(api_key=None, verbose=False): # data endpoint #_dataBP = 'https://sparc.olympiangods.org/scigraph' _dataBP = 'http://sparc-data.scicrunch.io:9000/scigraph' scigraphd = moduleDirect(_dataBP, 'scigraphd') data_sgd = scigraphd.Dynamic(cache=True, verbose=True, do_error=True) data_sgd._basePath = _dataBP data_sgc = scigraphd.Cypher(cache=True, verbose=True) data_sgc._basePath = _dataBP f = Path(__file__).resolve() working_dir = get_working_dir(__file__) resources = auth.get_path('resources') if working_dir: git_dir = working_dir / '.git' else: git_dir = Path('/dev/null') try: if working_dir is not None: ref = subprocess.check_output(['git', '--git-dir', git_dir.as_posix(), '--work-tree', working_dir.as_posix(), 'rev-parse', 'HEAD'], stderr=subprocess.DEVNULL).decode().rstrip() else: ver = __version__ if '+' in ver: ref = ver.split('+', 1)[-1] else: ref = ver except subprocess.CalledProcessError: ref = 'master' # 'NO-REPO-AT-MOST-TODO-GET-LATEST-HASH' wasGeneratedBy = ('https://github.com/tgbugs/pyontutils/blob/' f'{ref}/pyontutils/{f.name}' '#L{line}') line = getSourceLine(render) wgb = wasGeneratedBy.format(line=line) importchain = ImportChain(sgg=sgg, sgc=sgc, wasGeneratedBy=wasGeneratedBy) importchain.make_html() # run this once, restart services on a new release loop = asyncio.get_event_loop() app = Flask('ontology tree service') app.config['loop'] = loop # gsheets = GoogleSheets() sparc_view = open_custom_sparc_view_yml() # sparc_view_raw = open_custom_sparc_view_yml(False) log.info('starting index load') uot_terms = [OntTerm(t) for t in uot] uot_lookup = {t.label:t for t in uot_terms} uot_ordered = sorted(t.label for t in uot_terms) basename = 'trees' @app.route(f'/{basename}', methods=['GET']) @app.route(f'/{basename}/', methods=['GET']) def route_(): d = url_for('route_docs') e = url_for('route_examples') i = url_for('route_import_chain') return hfn.htmldoc(hfn.atag(d, 'Docs'), '<br>', hfn.atag(e, 'Examples'), '<br>', hfn.atag(i, 'Import chain'), title='NIF ontology hierarchies') @app.route(f'/{basename}/docs', methods=['GET']) def route_docs(): return redirect('https://github.com/SciCrunch/NIF-Ontology/blob/master/docs') # TODO @app.route(f'/{basename}/examples', methods=['GET']) def route_examples(): links = hfn.render_table( [[name, hfn.atag(url_for("route_query", pred=pred, root=root) + (args[0] if args else ''), f'../query/{pred}/{root}{args[0] if args else ""}')] for name, pred, root, *args in examples], 'Root class', '../query/{predicate-curie}/{root-curie}?direction=INCOMING&depth=10&branch=master&local=false', halign='left') flinks = hfn.render_table( [[name, hfn.atag(url_for("route_filequery", pred=pred, root=root, file=file) + (args[0] if args else ''), f'../query/{pred}/{root}/{file}{args[0] if args else ""}')] for name, pred, root, file, *args in file_examples], 'Root class', '../query/{predicate-curie}/{root-curie}/{ontology-filepath}?direction=INCOMING&depth=10&branch=master&restriction=false', halign='left') dlinks = hfn.render_table( [[name, hfn.atag(url_for("route_dynamic", path=path) + (querystring if querystring else ''), f'../query/dynamic/{path}{querystring if querystring else ""}')] for name, path, querystring in dynamic_examples], 'Root class', '../query/dynamic/{path}?direction=OUTGOING&dynamic=query&args=here', halign='left') return hfn.htmldoc(links, flinks, dlinks, title='Example hierarchy queries') @app.route(f'/{basename}/sparc/demos/isan2019/neuron-connectivity', methods=['GET']) def route_sparc_demos_isan2019_neuron_connectivity(): def connected(start): log.debug(start) blob = data_sgd.neurons_connectivity(start)#, limit=9999) edges = blob['edges'] neurons = {} types = {} rows = [] start_type = None sc = OntId(start).curie for e in edges: s, p, o = e['sub'], e['pred'], e['obj'] if p == 'operand': continue if s.startswith('_:'): if s not in neurons: neurons[s] = [] types[s] = {} otp = OntTerm(p) oto = OntTerm(o) neurons[s].append((otp, oto)) if o == sc: start_type = otp if oto not in types[s]: types[s][oto] = [] types[s][oto].append(otp) for v in neurons.values(): v.sort() return OntTerm(start), start_type, neurons, types hrm = [connected(t) for t in set(test_terms)] header =['Start', 'Start Type', 'Neuron', 'Relation', 'Target'] rows = [] for start, start_type, neurons, types in sorted(hrm): start = start.atag() start_type = start_type.atag() if start_type is not None else '' for i, v in enumerate(neurons.values(), 1): neuron = i for p, o in v: relation = p.atag() target = o.atag() row = start, start_type, neuron, relation, target rows.append(row) rows.append(['|'] + [' '] * 4) h = hfn.htmldoc(hfn.render_table(rows, *header), title='neuron connectivity') return h @app.route(f'/{basename}/sparc/demos/isan2019/flatmap-queries', methods=['GET']) def route_sparc_demos_isan2019_flatmap_queries(): # lift up to load from an external source at some point # from pyontutils.core import OntResPath # orp = OntResPath('annotations.ttl') # [i for i in sorted(set(OntId(e) for t in orp.graph for e in t)) if i.prefix in ('UBERON', 'FMA', 'ILX')] query = """ MATCH (blank)- [entrytype:ilxtr:hasSomaLocatedIn|ilxtr:hasAxonLocatedIn|ilxtr:hasDendriteLocatedIn|ilxtr:hasPresynapticTerminalsIn] ->(location:Class{{iri: "{iri}"}}) WITH entrytype, location, blank MATCH (phenotype)<-[predicate]-(blank)<-[:equivalentClass]-(neuron) WHERE NOT (phenotype.iri =~ ".*_:.*") RETURN location, entrytype.iri, neuron.iri, predicate.iri, phenotype """ def fetch(iri, limit=10): q = query.format(iri=iri) log.debug(q) blob = data_sgc.execute(q, limit, 'application/json') # oh boy # if there are less results than the limit scigraph segfaults # and returns nothing return blob hrm = [fetch(oid) for oid in test_terms] return hfn.htmldoc(hfn.render_table([[1, 2]],'oh', 'no'), title='Simulated flatmap query results', ) @app.route(f'/{basename}/sparc/demos/apinat', methods=['GET']) @app.route(f'/{basename}/sparc/demos/apinat/', methods=['GET']) def route_sparc_demos_apinat(): return 'apinat' @app.route(f'/{basename}/sparc/connectivity/query', methods=['GET']) def route_sparc_connectivity_query(): kwargs = request.args log.debug(kwargs) script = """ var ele = document.getElementById('model-selector') ele.onselect """ return hfn.htmldoc(hfn.render_form( [[('Model',), {}], [None, None], [ #('Kidney', 'Defensive breathing',), # TODO autopopulate ('Urinary Omega Tree',), {'id':'model-selector', 'name': 'model'}]], # FIXME auto via js? # FIXME must switch start and stop per model (argh) # or hide/show depending on which model is selected [[('start',), {}], [None, None], [ #('one', 'two', 'three'), # TODO auto populate uot_ordered, {'name': 'start'}]], # FIXME auto via js? [[('end',), {}], [None, None], [ #('one', 'two', 'three'), # TODO auto populate uot_ordered, {'name': 'end'}]], # FIXME auto via js? [[tuple(), {}], [tuple(), {'type': 'submit', 'value': 'Query'}], [None, None]] # FIXME auto via js? , action='view', method='POST' ), scripts=(script,), title='Connectivity query') @app.route(f'/{basename}/sparc/connectivity/view', methods=['POST']) def route_sparc_connectivity_view(): kwargs = request.args log.debug(kwargs) # FIXME error handling for bad data model = request.form['model'] start = request.form['start'] end = request.form['end'] sid = uot_lookup[start].curie eid = uot_lookup[end].curie #start = 'UBERON:0005157' #end = 'UBERON:0001255' return redirect(f'/{basename}/sparc/dynamic/shortestSimple?start_id={sid}' f'&end_id={eid}&direction=INCOMING&format=table') # TODO #return hfn.htmldoc(title='Connectivity view') @app.route(f'/{basename}/sparc/simple/dynamic/<path:path>', methods=['GET']) def route_sparc_simple_dynamic(path): return sparc_dynamic(data_sgd, data_sgc, path, wgb, simplify) @app.route(f'/{basename}/sparc/dynamic/<path:path>', methods=['GET']) def route_sparc_dynamic(path): return sparc_dynamic(data_sgd, data_sgc, path, wgb) @app.route(f'/{basename}/dynamic/<path:path>', methods=['GET']) def route_dynamic(path): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None try: j = sgd.dispatch(path, **args) except rHTTPError as e: log.exception(e) abort(e.response.status_code) # DO NOT PASS ALONG THE MESSAGE except ValueError as e: log.exception(e) abort(404) if j is None or 'edges' not in j or not j['edges']: log.error(pformat(j)) log.debug(sgd._last_url) return abort(400) prov = [hfn.titletag(f'Dynamic query result for {path}'), f'<meta name="date" content="{UTCNOWISO()}">', f'<link rel="http://www.w3.org/ns/prov#wasGeneratedBy" href="{wgb}">', '<meta name="representation" content="SciGraph">', f'<link rel="http://www.w3.org/ns/prov#wasDerivedFrom" href="{sgd._last_url}">'] kwargs = {'json': cleanBad(j), 'html_head': prov} tree, extras = creatTree(*Query(None, None, direction, None), **kwargs) #print(extras.hierarhcy) #print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return hfn.htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return hfn.htmldoc(extras.html, other=prov, styles=hfn.tree_styles) @app.route(f'/{basename}/imports/chain', methods=['GET']) def route_import_chain(): return importchain.html @app.route(f'/{basename}/query/<pred>/<root>', methods=['GET']) def route_query(pred, root): kwargs = getArgs(request) kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) return render(pred, root, **kwargs) @app.route(f'/{basename}/query/<pred>/http:/<path:iri>', methods=['GET']) # one / due to nginx @app.route(f'/{basename}/query/<pred>/https:/<path:iri>', methods=['GET']) # just in case def route_iriquery(pred, iri): # TODO maybe in the future root = 'http://' + iri # for now we have to normalize down can check request in future if verbose: log.debug(f'ROOOOT {root}') kwargs = getArgs(request) kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) return render(pred, root, **kwargs) @app.route(f'/{basename}/query/<pred>/<root>/<path:file>', methods=['GET']) def route_filequery(pred, root, file): kwargs = getArgs(request) kwargs['local_filepath'] = file kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) try: return render(pred, root, **kwargs) except HTTPError: return abort(404, 'Unknown ontology file.') # TODO 'Unknown git branch.' @app.route(f'/{basename}/sparc/view/<tier1>', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/<tier2>', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/<tier2>/', methods=['GET']) def route_sparc_view_query(tier1, tier2=None): journey = sparc_view if tier1 not in journey: return abort(404) journey = journey[tier1] if tier2 is not None: if tier2 not in journey: return abort(404) journey = journey[tier2] hyp_rows = hyperlink_tree(journey) return hfn.htmldoc( hfn.render_table(hyp_rows), title = 'Terms for ' + (tier2 if tier2 is not None else tier1), metas = ({'name':'date', 'content':time()},), ) @app.route(f'/{basename}/sparc/view', methods=['GET']) @app.route(f'/{basename}/sparc/view/', methods=['GET']) def route_sparc_view(): hyp_rows = [] spaces = hfn.nbsp * 8 for tier1, tier2_on in sorted(sparc_view.items()): url = url_for('route_sparc_view_query', tier1=tier1) tier1_row = tier1.split(YML_DELIMITER) tier1_row += tier2_on['CURIES'] tagged_tier1_row = tag_row(tier1_row, url) hyp_rows.append(tagged_tier1_row) if not tier2_on: continue # BUG: Will break what we want if more is added to spinal cord if len(tier2_on.keys()) > 15: continue if tier1_row[0] == 'Nerve roots of spinal cord segments': continue for tier2, tier3_on in tier2_on.items(): if tier2 == 'CURIES': continue url = url_for('route_sparc_view_query', tier1=tier1, tier2=tier2) tier2_row = tier2.split(YML_DELIMITER) tier2_row += tier3_on['CURIES'] tagged_tier2_row = tag_row(row=tier2_row, url=url, tier_level=1) if len(list(sparc_view[tier1_row[0]][tier2_row[0]].keys())) == 1: tagged_tier2_row[0] = spaces+tier2_row[0] hyp_rows.append(tagged_tier2_row) return hfn.htmldoc( hfn.render_table(hyp_rows), title= 'Main Page Sparc', styles= ["p {margin: 0px; padding: 0px;}"], metas= ({'name':'date', 'content':time()},), ) @app.route(f'/{basename}/sparc/index', methods=['GET']) @app.route(f'/{basename}/sparc/index/', methods=['GET']) def route_sparc_index(): hyp_rows = hyperlink_tree(sparc_view) return hfn.htmldoc( hfn.render_table(hyp_rows), title = 'SPARC Anatomical terms index', metas = ({'name':'date', 'content':time()},), ) @app.route(f'/{basename}/sparc', methods=['GET']) @app.route(f'/{basename}/sparc/', methods=['GET']) def route_sparc(): # FIXME TODO route to compiled p = Path('/var/www/ontology/trees/sparc/sawg.html') if p.exists(): return send_from_directory(p.parent.as_posix(), p.name) log.critical(f'{resources}/sawg.org has not been published') return send_from_directory(resources.as_posix(), 'sawg.org') #return hfn.htmldoc( #atag(url_for('route_sparc_view'), 'Terms by region or atlas'), '<br>', #atag(url_for('route_sparc_index'), 'Index'), #title='SPARC Anatomical terms', styles=["p {margin: 0px; padding: 0px;}"], #metas = ({'name':'date', 'content':time()},), #) return app
def sparc_dynamic(data_sgd, data_sgc, path, wgb, process=lambda coll, blob: blob): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None if 'apinat' in path: # FIXME bad hardcoded hack _old_get = data_sgd._get try: data_sgd._get = data_sgd._normal_get j = data_sgd.dispatch(path, **args) except ValueError as e: log.exception(e) abort(404) except rHTTPError as e: log.exception(e) abort(e.response.status_code) # DO NOT PASS ALONG THE MESSAGE finally: data_sgd._get = _old_get else: try: j = data_sgd.dispatch(path, **args) except rHTTPError as e: log.exception(e) abort(e.response.status_code) # DO NOT PASS ALONG THE MESSAGE except ValueError as e: log.exception(e) abort(404) j = process(collapse_apinat, j) if j is None or 'edges' not in j: log.error(pformat(j)) return abort(400) elif not j['edges']: return node_list(j['nodes']) # FIXME ... really should error? if path.endswith('housing-lyphs'): # FIXME hack root = 'NLX:154731' #direction = 'INCOMING' else: root = None prov = [ hfn.titletag(f'Dynamic query result for {path}'), f'<meta name="date" content="{UTCNOWISO()}">', f'<link rel="http://www.w3.org/ns/prov#wasGeneratedBy" href="{wgb}">', '<meta name="representation" content="SciGraph">', ('<link rel="http://www.w3.org/ns/prov#wasDerivedFrom" ' f'href="{data_sgd._last_url}">')] kwargs = {'json': cleanBad(j), 'html_head': prov, 'prefixes': data_sgc.getCuries(), # FIXME efficiency } tree, extras = creatTree(*Query(root, None, direction, None), **kwargs) #print(extras.hierarhcy) #print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return hfn.htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return hfn.htmldoc(extras.html, other=prov, styles=hfn.tree_styles)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._term = OntTerm(self.id) self.s = self._term.URIRef
def main(): sparc_terms = convert_view_text_to_dict() print('Linearizing graph') sparc_terms_unpaired = list(linearize_graph(sparc_terms)) print('Adding ids to terms list') sparc_terms_paired = pair_terms(sparc_terms_unpaired) # embed() avoid_in_bl = [ 'Gross anatomy', 'Internal anatomy', 'Segmental Anatomy', 'Atlas Nomenclature', 'Allen Mouse Brainstem', 'Paxinos Rar Brainstem' 'Berman Cat Brainstem', 'Nerves (also includes Cranial)', 'UBERON', ] accepted_prefixes_for_bl = [ 'UBERON', 'PAXRAT', ] print('Building sparc terms list txt') sparc_terms_text, sparc_terms_bl = '', [] for term in sparc_terms_paired: sparc_terms_text += ' ' * 4 * term.tier_level + '\t'.join( [term.label] + term.curies) + '\n' if not term.curies and term.label.strip() not in avoid_in_bl: sparc_terms_bl.append(term.label) # Labels with no ID # Slow as heck print( f'Building list for terms with no IDs with len:{len(sparc_terms_bl)}') for i, bl_term in enumerate(sparc_terms_bl): neighbors = OntTerm.search(bl_term.split(' ')[0]) for neighbor in neighbors: if set(neighbor.split(' ')) == set(bl_term.split(' ')): # if neighbor.curie.split(':')[0] in accepted_prefixes_for_bl: view_text_bl[i] += '\t' + neighbor.curie # Original IDs with wrong label print('Building list for terms with wrong IDs') sparc_terms_with_bad_ids = [] for term in sparc_terms_unpaired: for curie in term.curies: onts = OntTerm.query(curie=curie) if not onts: continue for ont in onts: if term.label.lower().strip() != ont.label.lower().strip(): sparc_terms_with_bad_ids.append({ **vars(term), 'searched_label': ont.label }) # embed() with open(resources / 'sparc_terms_populated3.txt', 'w') as outfile: outfile.write(sparc_terms_text) with open(resources / 'sparc_terms_unpopulated_terms3.txt', 'w') as outfile: outfile.write('\n'.join(sorted(sparc_terms_bl))) with open(resources / 'sparc_terms_with_bad_ids3.json', 'w') as outfile: json.dump(sparc_terms_with_bad_ids, outfile, indent=4)
# methods helper (subset of the larger ontology to speed up development) ### restHasValue = Restriction(None, owl.hasValue) filename = 'methods-helper' prefixes = None OntCuries['HBP_MEM'] = 'http://www.hbp.FIXME.org/hbp_measurement_methods/' #OntCuries['HBP_MEM'] = 'http://www.hbp.FIXME.org/hbp_measurement_methods/' #imports = NIFTTL['nif_backend.ttl'], imports = methods_core.iri, comment = 'helper for methods development' _repo = True debug = True triples = ((tech.injection, owl.equivalentClass, OntTerm('BIRNLEX:2135')), ) triples += ( # protocols oc(prot.CLARITY, ilxtr.protocol), oc(prot.deepSequencing, ilxtr.protocol), oc(prot.sangerSequencing, ilxtr.protocol), oc(prot.shotgunSequencing, ilxtr.protocol), oc(prot.fMRI, ilxtr.protocol), oc(prot.dwMRI, ilxtr.protocol), oc(prot.DTI, ilxtr.protocol), ) triples += ( # information entity # information entities oc(ilxtr.informationEntity),
def server(api_key=None, verbose=False): f = Path(__file__).resolve() working_dir = get_working_dir(__file__) if working_dir: git_dir = working_dir / '.git' else: git_dir = Path('/dev/null') try: commit = subprocess.check_output( [ 'git', '--git-dir', git_dir.as_posix(), '--work-tree', working_dir.as_posix(), 'rev-parse', 'HEAD' ], stderr=subprocess.DEVNULL).decode().rstrip() except subprocess.CalledProcessError: commit = 'master' # 'NO-REPO-AT-MOST-TODO-GET-LATEST-HASH' wasGeneratedBy = ('https://github.com/tgbugs/pyontutils/blob/' f'{commit}/pyontutils/{f.name}' '#L{line}') line = getSourceLine(render) wgb = wasGeneratedBy.format(line=line) importchain = ImportChain(wasGeneratedBy=wasGeneratedBy) importchain.make_html() # run this once, restart services on a new release loop = asyncio.get_event_loop() app = Flask('ontology tree service') app.config['loop'] = loop # gsheets = GoogleSheets() sparc_view = open_custom_sparc_view_yml() log.info('starting index load') uot_terms = [OntTerm(t) for t in uot] uot_lookup = {t.label: t for t in uot_terms} uot_ordered = sorted(t.label for t in uot_terms) basename = 'trees' @app.route(f'/{basename}', methods=['GET']) @app.route(f'/{basename}/', methods=['GET']) def route_(): d = url_for('route_docs') e = url_for('route_examples') i = url_for('route_import_chain') return htmldoc(atag(d, 'Docs'), '<br>', atag(e, 'Examples'), '<br>', atag(i, 'Import chain'), title='NIF ontology hierarchies') @app.route(f'/{basename}/docs', methods=['GET']) def route_docs(): return redirect( 'https://github.com/SciCrunch/NIF-Ontology/blob/master/docs' ) # TODO @app.route(f'/{basename}/examples', methods=['GET']) def route_examples(): links = render_table( [[ name, atag( url_for("route_query", pred=pred, root=root) + (args[0] if args else ''), f'../query/{pred}/{root}{args[0] if args else ""}') ] for name, pred, root, *args in examples], 'Root class', '../query/{predicate-curie}/{root-curie}?direction=INCOMING&depth=10&branch=master&local=false', halign='left') flinks = render_table( [[ name, atag( url_for("route_filequery", pred=pred, root=root, file=file) + (args[0] if args else ''), f'../query/{pred}/{root}/{file}{args[0] if args else ""}') ] for name, pred, root, file, *args in file_examples], 'Root class', '../query/{predicate-curie}/{root-curie}/{ontology-filepath}?direction=INCOMING&depth=10&branch=master&restriction=false', halign='left') dlinks = render_table( [[ name, atag( url_for("route_dynamic", path=path) + (querystring if querystring else ''), f'../query/dynamic/{path}{querystring if querystring else ""}' ) ] for name, path, querystring in dynamic_examples], 'Root class', '../query/dynamic/{path}?direction=OUTGOING&dynamic=query&args=here', halign='left') return htmldoc(links, flinks, dlinks, title='Example hierarchy queries') @app.route(f'/{basename}/sparc/connectivity/query', methods=['GET']) def route_sparc_connectivity_query(): kwargs = request.args log.debug(kwargs) script = """ var ele = document.getElementById('model-selector') ele.onselect """ return hfn.htmldoc( hfn.render_form( [ [('Model', ), {}], [None, None], [ #('Kidney', 'Defensive breathing',), # TODO autopopulate ( 'Urinary Omega Tree', ), { 'id': 'model-selector', 'name': 'model' } ] ], # FIXME auto via js? # FIXME must switch start and stop per model (argh) # or hide/show depending on which model is selected [ [('start', ), {}], [None, None], [ #('one', 'two', 'three'), # TODO auto populate uot_ordered, { 'name': 'start' } ] ], # FIXME auto via js? [ [('end', ), {}], [None, None], [ #('one', 'two', 'three'), # TODO auto populate uot_ordered, { 'name': 'end' } ] ], # FIXME auto via js? [[tuple(), {}], [tuple(), { 'type': 'submit', 'value': 'Query' }], [None, None]] # FIXME auto via js? , action='view', method='POST'), scripts=(script, ), title='Connectivity query') @app.route(f'/{basename}/sparc/connectivity/view', methods=['POST']) def route_sparc_connectivity_view(): kwargs = request.args log.debug(kwargs) # FIXME error handling for bad data model = request.form['model'] start = request.form['start'] end = request.form['end'] sid = uot_lookup[start].curie eid = uot_lookup[end].curie #start = 'UBERON:0005157' #end = 'UBERON:0001255' return redirect( f'/{basename}/sparc/dynamic/shortestSimple?start_id={sid}&end_id={eid}&direction=INCOMING&format=table' ) # TODO #return hfn.htmldoc(title='Connectivity view') @app.route(f'/{basename}/sparc/dynamic/<path:path>', methods=['GET']) def route_sparc_dynamic(path): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None j = data_sgd.dispatch(path, **args) #breakpoint() if not j['edges']: log.error(pprint(j)) return abort(400) kwargs = {'json': j} tree, extras = creatTree(*Query(None, None, direction, None), **kwargs) #print(extras.hierarhcy) print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [ OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n ] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return htmldoc(extras.html, styles=hfn.tree_styles) @app.route(f'/{basename}/dynamic/<path:path>', methods=['GET']) def route_dynamic(path): args = dict(request.args) if 'direction' in args: direction = args.pop('direction') else: direction = 'OUTGOING' # should always be outgoing here since we can't specify? if 'format' in args: format_ = args.pop('format') else: format_ = None j = sgd.dispatch(path, **args) if not j['edges']: log.error(pprint(j)) return abort(400) kwargs = {'json': j} tree, extras = creatTree(*Query(None, None, direction, None), **kwargs) #print(extras.hierarhcy) print(tree) if format_ is not None: if format_ == 'table': #breakpoint() def nowrap(class_, tag=''): return (f'{tag}.{class_}' '{ white-space: nowrap; }') ots = [ OntTerm(n) for n in flatten_tree(extras.hierarchy) if 'CYCLE' not in n ] #rows = [[ot.label, ot.asId().atag(), ot.definition] for ot in ots] rows = [[ot.label, hfn.atag(ot.iri, ot.curie), ot.definition] for ot in ots] return htmldoc(hfn.render_table(rows, 'label', 'curie', 'definition'), styles=(hfn.table_style, nowrap('col-label', 'td'))) return htmldoc(extras.html, styles=hfn.tree_styles) @app.route(f'/{basename}/imports/chain', methods=['GET']) def route_import_chain(): return importchain.html @app.route(f'/{basename}/query/<pred>/<root>', methods=['GET']) def route_query(pred, root): kwargs = getArgs(request) kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) return render(pred, root, **kwargs) @app.route(f'/{basename}/query/<pred>/http:/<path:iri>', methods=['GET']) # one / due to nginx @app.route(f'/{basename}/query/<pred>/https:/<path:iri>', methods=['GET']) # just in case def route_iriquery(pred, iri): # TODO maybe in the future root = 'http://' + iri # for now we have to normalize down can check request in future if verbose: log.debug(f'ROOOOT {root}') kwargs = getArgs(request) kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) return render(pred, root, **kwargs) @app.route(f'/{basename}/query/<pred>/<root>/<path:file>', methods=['GET']) def route_filequery(pred, root, file): kwargs = getArgs(request) kwargs['local_filepath'] = file kwargs['wgb'] = wgb maybe_abort = sanitize(pred, kwargs) if maybe_abort is not None: return maybe_abort if verbose: kwargs['verbose'] = verbose log.debug(str(kwargs)) try: return render(pred, root, **kwargs) except HTTPError: return abort( 404, 'Unknown ontology file.') # TODO 'Unknown git branch.' @app.route(f'/{basename}/sparc/view/<tier1>', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/<tier2>', methods=['GET']) @app.route(f'/{basename}/sparc/view/<tier1>/<tier2>/', methods=['GET']) def route_sparc_view_query(tier1, tier2=None): journey = sparc_view if tier1 not in journey: return abort(404) journey = journey[tier1] if tier2 is not None: if tier2 not in journey: return abort(404) journey = journey[tier2] hyp_rows = hyperlink_tree(journey) return htmldoc( render_table(hyp_rows), title='Terms for ' + (tier2 if tier2 is not None else tier1), metas=({ 'name': 'date', 'content': time() }, ), ) @app.route(f'/{basename}/sparc/view', methods=['GET']) @app.route(f'/{basename}/sparc/view/', methods=['GET']) def route_sparc_view(): hyp_rows = [] spaces = nbsp * 8 for tier1, tier2_on in sorted(sparc_view.items()): url = url_for('route_sparc_view_query', tier1=tier1) tier1_row = tier1.split(YML_DELIMITER) tier1_row += tier2_on['CURIES'] tagged_tier1_row = tag_row(tier1_row, url) hyp_rows.append(tagged_tier1_row) if not tier2_on: continue # BUG: Will break what we want if more is added to spinal cord if len(tier2_on.keys()) > 6: continue for tier2, tier3_on in tier2_on.items(): if tier2 == 'CURIES': continue url = url_for('route_sparc_view_query', tier1=tier1, tier2=tier2) tier2_row = tier2.split(YML_DELIMITER) tier2_row += tier3_on['CURIES'] tagged_tier2_row = tag_row(row=tier2_row, url=url, tier_level=1) hyp_rows.append(tagged_tier2_row) return htmldoc( render_table(hyp_rows), title='Main Page Sparc', styles=["p {margin: 0px; padding: 0px;}"], metas=({ 'name': 'date', 'content': time() }, ), ) @app.route(f'/{basename}/sparc/index', methods=['GET']) @app.route(f'/{basename}/sparc/index/', methods=['GET']) def route_sparc_index(): hyp_rows = hyperlink_tree(sparc_view) return htmldoc( render_table(hyp_rows), title='SPARC Anatomical terms index', metas=({ 'name': 'date', 'content': time() }, ), ) @app.route(f'/{basename}/sparc', methods=['GET']) @app.route(f'/{basename}/sparc/', methods=['GET']) def route_sparc(): # FIXME TODO route to compiled p = Path('/var/www/ontology/trees/sparc/sawg.html') if p.exists(): return send_from_directory(p.parent.as_posix(), p.name) log.critical(f'{devconfig.resources}/sawg.org has not been published') return send_from_directory( Path(devconfig.resources).as_posix(), 'sawg.org') #return htmldoc( #atag(url_for('route_sparc_view'), 'Terms by region or atlas'), '<br>', #atag(url_for('route_sparc_index'), 'Index'), #title='SPARC Anatomical terms', styles=["p {margin: 0px; padding: 0px;}"], #metas = ({'name':'date', 'content':time()},), #) return app