# -*- org-adapt-indentation: nil; org-edit-src-content-indentation: 0; orgstrap-cypher: sha256; orgstrap-norm-func-name: orgstrap-norm-func--dprp-1-0; orgstrap-block-checksum: c0beaa9b5b973262b2d5b55ed0754b0259c6179cadeee3279c8e977ec8e4515e; -*- # [[orgstrap][jump to the orgstrap block for this file]] # [[file:queries.pdf]] [[file:queries.html]] #+name: orgstrap-shebang #+begin_src bash :eval never :results none :exports none set -e "-C" "-e" "-e" { null=/dev/null;} > "${null:=/dev/null}" { args=;file=;MyInvocation=;__p=$(mktemp -d);touch ${__p}/=;chmod +x ${__p}/=;__op=$PATH;PATH=${__p}:$PATH;} > "${null}" $file = $MyInvocation.MyCommand.Source { file=$0;PATH=$__op;rm ${__p}/=;rmdir ${__p};} > "${null}" emacs -batch -no-site-file -eval "(let (vc-follow-symlinks) (defun org-restart-font-lock ()) (defun orgstrap--confirm-eval (l _) (not (memq (intern l) '(elisp emacs-lisp)))) (let ((file (pop argv)) enable-local-variables) (find-file-literally file) (end-of-line) (when (eq (char-before) ?\^m) (let ((coding-system-for-read 'utf-8)) (revert-buffer nil t t)))) (let ((enable-local-eval t) (enable-local-variables :all) (major-mode 'org-mode) find-file-literally) (require 'org) (org-set-regexps-and-options) (hack-local-variables)))" "${file}" -- ${args} "${@}" exit <# powershell open #+end_src #+title: SPARC queries #+startup: showall #+category: SPARC #+options: ^:nil #+latex_header: \usepackage[inkscapelatex=false]{svg} #+begin: properties #+property: header-args :eval no-export # header-args:sparql :url http://localhost:10035/repositories/test <> #+property: header-args:sparql :url http://localhost:9999/blazegraph/sparql #+property: header-args:sparql+ :format text/csv #+property: header-args:sparql+ :results table #+property: header-args:sparql+ :exports both #+property: header-args:sparql+ :var limit="10" # TODO figure out how to allow missing limit to not set epilogue, likely requires modifications to core # XXX of course that would require epilogue to actually be implemented :/ # #+property: header-args:sparql+ :epilogue "LIMIT ?limit" <> # #+property: header-args:cypher :scigraph https://scicrunch.org/api/1/sparc-scigraph :api-key (and (fboundp 'get-scicrunch-api-key) (get-scicrunch-api-key)) # #+property: header-args:cypher :scigraph https://scicrunch.org/api/1/sckan-scigraph :api-key (and (fboundp 'get-scicrunch-api-key) (get-scicrunch-api-key)) #+property: header-args:cypher :scigraph http://localhost:9000/scigraph #+property: header-args:cypher+ :limit 10 #+end: #+begin: prefixes # TODO consider a setup file for these maybe? # or populate additional local curies via orgstrap # FIXME doi collides which is bad #+link: doi https://doi.org/ #+link: PMID http://www.ncbi.nlm.nih.gov/pubmed/ #+link: dataset https://api.pennsieve.io/datasets/N:dataset: #+link: datasetbf https://api.blackfynn.io/datasets/N:dataset: #+link: TEMP http://uri.interlex.org/temp/uris/ #+link: TEMPRAW http://uri.interlex.org/temp/uris/raw/ #+link: awards http://uri.interlex.org/temp/uris/awards/ #+link: rdf http://www.w3.org/1999/02/22-rdf-syntax-ns# #+link: fma http://purl.org/sig/ont/fma/ #+link: FMA http://purl.org/sig/ont/fma/fma #+link: obo http://purl.obolibrary.org/obo/ #+link: IAO http://purl.obolibrary.org/obo/IAO_ #+link: UBERON http://purl.obolibrary.org/obo/UBERON_ #+link: NCBITaxon http://purl.obolibrary.org/obo/NCBITaxon_ #+link: PATO http://purl.obolibrary.org/obo/PATO_ #+link: CHEBI http://purl.obolibrary.org/obo/CHEBI_ #+link: GO http://purl.obolibrary.org/obo/GO_ #+link: CL http://purl.obolibrary.org/obo/CL_ #+link: EMAPA http://purl.obolibrary.org/obo/EMAPA_ #+link: oboInOwl http://www.geneontology.org/formats/oboInOwl# #+link: BIRNLEX http://uri.neuinfo.org/nif/nifstd/birnlex_ #+link: owl http://www.w3.org/2002/07/owl# #+link: rdfs http://www.w3.org/2000/01/rdf-schema# #+link: dc http://purl.org/dc/elements/1.1/ #+link: dcterms http://purl.org/dc/terms/ #+link: ILX http://uri.interlex.org/base/ilx_ #+link: ilxr http://uri.interlex.org/base/readable/ #+link: ilxtr http://uri.interlex.org/tgbugs/uris/readable/ #+link: sparc http://uri.interlex.org/tgbugs/uris/readable/sparc/ #+link: tech http://uri.interlex.org/tgbugs/uris/readable/technique/ #+link: asp http://uri.interlex.org/tgbugs/uris/readable/aspect/ #+link: unit http://uri.interlex.org/tgbugs/uris/readable/aspect/unit/ #+link: build http://uri.interlex.org/tgbugs/uris/readable/build/ #+link: buildid http://uri.interlex.org/tgbugs/uris/readable/build/id/ #+link: ilxtio http://uri.interlex.org/tgbugs/uris/indexes/ontologies/ #+link: nposimtest http://uri.interlex.org/tgbugs/uris/readable/npo-simple-test-1/ #+link: hyp-protcur https://uilx.org/tgbugs/u/hypothesis/protcur/ #+link: NLXINV http://uri.neuinfo.org/nif/nifstd/nlx_inv_ #+link: SAO http://uri.neuinfo.org/nif/nifstd/sao #+link: NLX http://uri.neuinfo.org/nif/nifstd/nlx_ #+link: pio.api https://www.protocols.io/api/v4/protocols/ #+link: pio.api3 https://www.protocols.io/api/v3/protocols/ #+link: pio.view https://www.protocols.io/view/ #+link: pio.html https://www.protocols.io/view/%s.html #+link: ror https://ror.org/ #+link: SCR http://scicrunch.org/resolver/SCR_ #+link: apinatomy https://apinatomy.org/uris/readable/ #+link: elements https://apinatomy.org/uris/elements/ #+link: aacar https://apinatomy.org/uris/models/ard-arm-cardiac/ids/ #+link: bolew https://apinatomy.org/uris/models/bolser-lewis/ids/ #+link: kblad https://apinatomy.org/uris/models/keast-bladder/ids/ #+link: bromo https://apinatomy.org/uris/models/bronchomotor/ids/ #+link: scaft https://apinatomy.org/uris/models/scaffold-test/ids/ #+link: vagnr https://apinatomy.org/uris/models/vagus-nerve/ids/ #+link: sdcol https://apinatomy.org/uris/models/sawg-distal-colon/ids/ #+link: sstom https://apinatomy.org/uris/models/sawg-stomach/ids/ #+link: dlcon https://apinatomy.org/uris/models/dev-layout-conn/ids/ #+link: splen https://apinatomy.org/uris/models/spleen/ids/ #+link: pancr https://apinatomy.org/uris/models/pancreas/ids/ #+link: wbrcm https://apinatomy.org/uris/models/wbrcm/ids/ # FIXME definition is not expanding as expected, probably because my # implementation is wrong?? but only occasionally? other times it works ?? #+link: definition http://purl.obolibrary.org/obo/IAO_0000115 #+link: rawmethods https://raw.githubusercontent.com/SciCrunch/NIF-Ontology/methods/ttl/ #+link: rawneurons https://raw.githubusercontent.com/SciCrunch/NIF-Ontology/neurons/ttl/ #+link: cassont https://cassava.ucsd.edu/sparc/ontologies/ #+link: sparc-olymp-apinat https://sparc.olympiangods.org/ApiNATOMY/ontologies/ #+link: prov http://www.w3.org/ns/prov# #+link: foaf http://xmlns.com/foaf/0.1/ #+link: NIFRID http://uri.neuinfo.org/nif/nifstd/readable/ #+link: swrl http://www.w3.org/2003/11/swrl# #+link: prism http://prismstandard.org/namespaces/basic/2.1/ #+link: BFO http://purl.obolibrary.org/obo/BFO_ #+link: RO http://purl.obolibrary.org/obo/RO_ #+link: HP http://purl.obolibrary.org/obo/HP_ #+link: UBPROP http://purl.obolibrary.org/obo/UBPROP_ #+link: chebi http://purl.obolibrary.org/obo/chebi/ #+link: ncbitaxon http://purl.obolibrary.org/obo/ncbitaxon# #+link: cl http://purl.obolibrary.org/obo/cl# #+link: MIRO http://uri.interlex.org/MIRO/uris/readable/ #+link: bibo http://purl.org/ontology/bibo/ #+link: cito http://purl.org/spar/cito/ #+link: swrl http://swrl.stanford.edu/ontologies/3.3/swrla.owl# #+link: doap http://usefulinc.com/ns/doap# #+link: xsd http://www.w3.org/2001/XMLSchema# #+link: skos http://www.w3.org/2004/02/skos/core# #+link: mba http://api.brain-map.org/api/v2/data/Structure/ #+link: jax http://jaxmice.jax.org/strain/ #+link: npokb http://uri.interlex.org/npo/uris/neurons/ #+link: PAXRAT http://uri.interlex.org/paxinos/uris/rat/labels/ #+link: NIFEXT http://uri.neuinfo.org/nif/nifstd/nifext_ #+end: * Data queries ** Datasets *** Dataset Predicates #+begin_src sparql SELECT DISTINCT ?p # ?pp # ?po WHERE { ?dataset a sparc:Dataset . ?dataset ?p ?o . # ?p ?pp ?po . } ORDER BY ?p #+end_src *** Electrophysiology datasets #+begin_src sparql SELECT DISTINCT ?d ?label ?approach WHERE { VALUES ?match { "electrophysiology" } ?d a sparc:Dataset ; rdfs:label ?l ; TEMP:hasExperimentalApproach ?approach . FILTER (str(?approach) = str(?match)) BIND(substr(str(?l), 0, 40) AS ?label) # TODO lift and pull filetypes } #+end_src *** Datasets by contents updated time #+begin_src sparql SELECT DISTINCT ?dataset ?ut (substr(str(?l), 0, 40) as ?label) WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:contentsWereUpdatedAtTime ?ut . ?dataset rdfs:label ?l . } ORDER BY DESC(?ut) #+end_src *** Human dataset queries #+name: human-datasets-queries #+begin_src python :results output drawer :exports both :eval no-export import rdflib from pyontutils.core import OntResIri from pyontutils.namespaces import sparc, TEMP, dc, rdfs ori = OntResIri('https://cassava.ucsd.edu/sparc/preview/exports/curation-export.ttl') g = ori.graph gns = g.namespace_manager def fmt(s, u): return f'[[{u}][{s.n3(gns)}]]' species = set([fmt(do, urih) for s, p, o in g if isinstance(o, rdflib.Literal) and ('human' in o.lower() or 'homo' in o.lower()) and p == sparc.animalSubjectIsOfSpecies for do in g[s:TEMP.hasDerivedInformationAsParticipant] for urih in g[do:TEMP.hasUriHuman]]) hlabel = set([fmt(s, urih) for s, p, o in g if isinstance(o, rdflib.Literal) and ('human' in o.lower() or 'homo' in o.lower()) and p == rdfs.label for urih in g[s:TEMP.hasUriHuman]]) htitle = set([fmt(s, urih) for s, p, o in g if isinstance(o, rdflib.Literal) and ('human' in o.lower() or 'homo' in o.lower()) and p == dc.title for urih in g[s:TEMP.hasUriHuman]]) htd = set([fmt(s, urih) for s, p, o in g if isinstance(o, rdflib.Literal) and ('human' in o.lower() or 'homo' in o.lower()) and (p == dc.title or p == dc.description) for urih in g[s:TEMP.hasUriHuman]]) counts = dict(species=len(human), label=len(hlabel), title=len(htitle), title_and_desc=len(htd)) [print(_ + r' \\') for _ in ['species n= ' + str(counts['species'])] + sorted(species) + ['label n= ' + str(counts['label'])] + sorted(hlabel) + ['title n= ' + str(counts['title'])] + sorted(htitle) + ['td n= ' + str(counts['title_and_desc'])] + sorted(htd)] #+end_src *** Test Originally from =sparcur.reports.SparqlQueries=. **** Dataset about #+begin_src sparql SELECT DISTINCT ?dataset ?about WHERE { ?type rdfs:subClassOf* sparc:Resource . ?dataset rdf:type ?type . ?dataset isAbout: ?about . } LIMIT ?limit #+end_src **** Dataset subjects #+name: dataset-subjects #+begin_src sparql SELECT DISTINCT ?dataset ?subj WHERE { ?startsubj a sparc:Subject . ?startsubj TEMP:hasDerivedInformationAsParticipant ?dataset . ?subj a sparc:Subject . ?subj TEMP:hasDerivedInformationAsParticipant ?dataset . } LIMIT ?limit #+end_src #+call: dataset-subjects(startsubj="", limit="100") **** Dataset groups #+name: dataset-groups #+begin_src sparql SELECT DISTINCT ?dataset ?group ?subj WHERE { ?startsubj TEMP:hasDerivedInformationAsParticipant ?dataset . ?subj TEMP:hasDerivedInformationAsParticipant ?dataset . ?subj TEMP:hasAssignedGroup ?group . } LIMIT ?limit #+end_src #+call: dataset-groups(startsubj="", limit="100") **** Dataset bundle #+name: dataset-bundle #+begin_src sparql SELECT DISTINCT ?dataset WHERE { ?startdataset TEMP:collectionTitle ?string . ?dataset TEMP:collectionTitle ?string . } LIMIT ?limit #+end_src #+call: dataset-bundle(startdataset="dataset:bec4d335-9377-4863-9017-ecd01170f354") **** Dataset subject species #+begin_src sparql :var limit="100" SELECT DISTINCT ?dataset ?species WHERE { ?dataset TEMP:isAboutParticipant ?subject . ?subject sparc:animalSubjectIsOfSpecies ?species . FILTER ( CONTAINS(str(?species), "human") || CONTAINS(str(?species), "homo sapiens") || ?species = NCBITaxon:9606 ) } LIMIT ?limit #+end_src **** Dataset human subjects and samples #+begin_src sparql :var limit="10" SELECT DISTINCT ?dataset ?subject ?subject_meta ?sample ?sample_meta ?species WHERE { ?dataset TEMP:isAboutParticipant ?subject . ?subject sparc:animalSubjectIsOfSpecies ?species . ?subject ?sup ?subject_meta . FILTER ( CONTAINS(str(?species), "human") || CONTAINS(str(?species), "homo sapiens") || ?species = NCBITaxon:9606 ) ?sample TEMP:wasDerivedFromSubject ?subject . ?sample ?sap ?sample_meta . } LIMIT ?limit #+end_src **** Dataset milestone completion date #+begin_src sparql SELECT DISTINCT ?dataset ?date WHERE { ?dataset TEMP:milestoneCompletionDate ?date . } ORDER BY ASC(?date) LIMIT ?limit #+end_src **** Award affiliations Can we see the multi-institutional nature of SPARC collaborations? #+begin_src sparql SELECT DISTINCT ?award ?affiliation (str(?affil_l) as ?al) WHERE { ?dataset TEMP:hasAwardNumber ?award . ?contributor TEMP:contributorTo ?dataset . ?contributor TEMP:hasAffiliation ?affiliation . ?affiliation rdfs:label ?affil_l . # FILTER isUri(?affiliation) } ORDER BY ASC(?award) ASC(?al) LIMIT ?limit #+end_src *** Connectivity datasets #+begin_src sparql select distinct ?published_uri ?isDescBy #?dataset #?connectivity where { ?dataset a sparc:Dataset . ?dataset TEMP:hasExperimentalApproach ?connectivity . ?dataset TEMP:hasUriPublished ?published_uri . filter contains(str(?connectivity), "connectivity") optional { ?dataset TEMP:isDescribedBy ?isDescBy } } order by ?published_id #+end_src ** Protocols *** Protocol general report # TODO (make-directory "./reports/") How to interpret this report. The rows are ordered by 1. whether there is a dataset directly associated with the protocol id 2. whether the protocol has a human readable uri. 3. by the number of protcur annotations that have been made on the protocol If there are zero protcur annotations it usually means that only the minimal protocol curation workflow was completed. If there the number of protocol annotations is null it means that no annotations of any kind have been made on that protocol. This can only happen for protocols that come from the dataset description file. If the dataset is null and there are annotations it usually means that the protocol is transitively related to a dataset. There are annotations on the protocols that link them directly to the dataset in question but we are not currently pulling them into the knowledge graph. It also means that the protocol url in question was not listed in the dataset description file but may have been listed in another protocol or in a collection of protocols. If =hasUri= is false and dataset is not null then it usually means that the protocol has been deleted or that something else has gone wrong. If dataset is null and =hasUri= is null it just means that the protocol is present only in =protcur.ttl= and the additional identifiers have not been processed. # FIXME mkdir reports somehow #+header: :results file :file ./reports/protocol-report.csv :exports code #+begin_src sparql select distinct ?protocol ?n (sample(?dataset) AS ?datasetx) ?doi_protocol (sample(bound(?urih_protocol)) as ?hasUri) (sample(bound(?some_child)) as ?hasComplexAnnos) where { ?protocol a sparc:Protocol . optional { ?protocol TEMP:hasNumberOfProtcurAnnotations ?n } optional { #?dataset TEMP:hasProtocol ?protocol { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol } } optional { ?protocol TEMP:hasDoi ?doi_protocol } optional { ?protocol TEMP:hasUriHuman ?urih_protocol } optional { ?protocol ?some_predicate ?annotation . ?annotation TEMP:protcurChildren ?some_child } } group by ?protocol ?n ?doi_protocol ?hasUri order by desc(bound(?datasetx)) asc(?hasUri) desc(?n) #+end_src #+RESULTS: [[file:./reports/protocol-report.csv]] *** Total protocols XXX FIXME producing complete nonsense right now #+name: sparql-count-protocols #+begin_src sparql SELECT (COUNT(DISTINCT ?protocol) AS ?count) #DISTINCT ?protocol WHERE { ?protocol a sparc:Protocol . } #order by str(?protocol) #+end_src *** Total protocols with at least one protcur annotation #+name: sparql-count-protocols-at-least-one-protc #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> }} #+end_src #+name: sparql-count-protocols-pio-api-at-least-one-protc #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: sparql-protocols-pio-api-at-least-one-protc #+begin_src sparql :noweb yes :epilogue " order by desc(?anno_count)" <> FILTER CONTAINS(str(?protocol), "protocols.io/api") #FILTER CONTAINS(str(?protocol), "protocols.io") } #+end_src #+begin_src bash :eval never grep -oE 'TEMP:protocol[^\ ]+' protcur.ttl | sort -u #+end_src #+name: sparql-protocols-at-least-one-protc #+begin_src sparql :epilogue "} order by desc(?anno_count)" select distinct ?protocol ?anno_count where { values ?some_predicate { TEMP:protocolEmploysTechnique TEMP:protocolInvolvesAction TEMP:protocolInvolvesAspect TEMP:protocolInvolvesBlackBox TEMP:protocolInvolvesParameter TEMP:protocolInvolvesInvariant # these two are noisy because they also include tags converted from sparc: TEMP:protocolInvolvesBlackBoxComponent TEMP:protocolInvolvesInput } ?protocol a sparc:Protocol ; ?some_predicate ?annotation ; # this line an the filter should wind up with the same number TODO add a test to check TEMP:hasNumberOfProtcurAnnotations ?anno_count . FILTER (?anno_count > 0 ) #+end_src *** Published protocols with complex protcur annotations #+name: sparql-complex-protocols-count #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> }} #+end_src #+name: sparql-complex-protocols-published-count #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: sparql-complex-protocols-published #+begin_src sparql :noweb no-export :epilogue "order by desc(?anno_count)" <> ?protocol TEMP:hasDoi ?doi . } #+end_src #+name: sparql-complex-protocols #+begin_src sparql :epilogue "} order by desc(?anno_count)" select distinct ?protocol ?anno_count where { ?annotation TEMP:protcurChildren ?some_child . ?protocol a sparc:Protocol ; ?some_predicate ?annotation ; TEMP:hasNumberOfProtcurAnnotations ?anno_count . #+end_src # FIXME one failure of noweb is that you cannot remix and recombine in # case where there is nesting, e.g. if I wanted the where clause to be # the same except for one line, I couldn't reuse a block because you # can make a noweb ref something that can be passed as an argument *** Conditions studied *** Experimental groups #+name: experimental-groups-core #+begin_src sparql :var limit="10" :eval never WHERE { ?startsubj TEMP:hasDerivedInformationAsParticipant ?dataset . ?subj TEMP:hasDerivedInformationAsParticipant ?dataset . ?subj TEMP:hasAssignedGroup ?group . } #+end_src #+name: experimental-groups #+begin_src sparql :var limit="10" :noweb yes SELECT DISTINCT ?dataset ?group ?subj <> ORDER BY ASC(?dataset) ASC(?group) LIMIT ?limit #+end_src #+name: experimental-groups-by-dataset #+begin_src sparql :noweb yes :var limit="10" SELECT DISTINCT ?group ?subj <> ORDER BY ASC(?group) LIMIT ?limit #+end_src # #+call: experimental-groups-by-dataset(limit="20",dataset="dataset:01b5cc2d-b321-4fed-8767-52771c4d680f") # FIXME this is broken #+call: experimental-groups-by-dataset(limit="20", dataset="dataset:257a485a-89b3-4187-888a-9843b277e6cb") *** Techniques # #+header: :var dataset=(or) #+begin_src sparql SELECT DISTINCT ?dataset ?technique # ?protocol # ?technique_p WHERE { { ?dataset a sparc:Dataset . ?dataset TEMP:protocolEmploysTechnique ?technique . # ?technique rdfs:label ?tl } UNION { #?dataset TEMP:hasProtocol ?protocol . { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol } ?protocol TEMP:protocolEmploysTechnique ?technique . # ?technique rdfs:label ?tl } } LIMIT ?limit #+end_src *** Test Originally from =sparcur.reports.SparqlQueries=. **** Protocol techniques #+begin_src sparql SELECT DISTINCT ?protocol ?technique WHERE { ?protocol rdf:type sparc:Protocol . ?protocol TEMP:protocolEmploysTechnique ?technique . } LIMIT ?limit #+end_src **** Protocol aspects #+begin_src sparql SELECT DISTINCT ?protocol ?aspect WHERE { ?protocol rdf:type sparc:Protocol . ?protocol TEMP:protocolInvolvesAspect ?ast . ?ast rdf:type protcur:aspect . ?ast TEMP:hasValue ?aspect . } LIMIT ?limit #+end_src **** Protocol inputs # Note that the ontology alignment here is often incorrect #+begin_src sparql SELECT DISTINCT ?protocol ?ast_in ?input WHERE { ?protocol rdf:type sparc:Protocol . ?protocol TEMP:protocolInvolvesInput ?ast_in . ?ast_in rdf:type protcur:input . ?ast_in TEMP:hasValue ?input . } LIMIT ?limit #+end_src **** Protocol species dose #+name: sparql-species-dose #+begin_src sparql SELECT DISTINCT ?dataset ?protocol (str(?label_drug) as ?l_drug) ?value_lt WHERE { VALUES ?t {protcur:invariant protcur:parameter} . ?ast_inv a ?t . ?ast_inv TEMP:hasValue ?bnode . ?bnode rdf:value ?value_lt . #?bnode TEMP:hasUnit unit:milligram%20%2F%20kilogram . # seems like the %20 etc. break curies? ?bnode TEMP:hasUnit . FILTER (?value_lt < ?limit) ?ast_drug a protcur:input . ?ast_drug TEMP:hasValue ?drug . ?drug rdfs:label ?label_drug . ?ast_drug TEMP:protcurChildren+ ?ast_child . ?ast_child TEMP:hasValue ?bnode . ?protocol a sparc:Protocol . ?protocol TEMP:protocolInvolvesInput ?ast_drug . ?protocol TEMP:protocolInvolvesInput ?ast_in_sp . ?ast_in_sp rdf:type protcur:input . ?ast_in_sp TEMP:hasValue ?species . OPTIONAL { # ?dataset TEMP:hasProtocol ?protocol { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol } } } ORDER BY ?label_input ?value_lt #+end_src **** Protocols with known anaesthetic or analgesic roles #+begin_src sparql select distinct ?pro ?ana ?l ?u ?v where { ?pro TEMP:protocolInvolvesInput ?anno . ?anno TEMP:hasValue ?ana . ?anno TEMP:protcurChildren ?ad . ?ad TEMP:hasValue ?asp . ?ad TEMP:protcurChildren ?ai . ?ai TEMP:hasValue ?bn . ?bn TEMP:hasUnit ?u . ?bn rdf:value ?v . ?ana rdfs:label ?l . ?ana ?p ?b . ?b owl:onProperty RO:0000087 . ?b owl:someValuesFrom ?o . ?o rdfs:subClassOf* ?role . values ?asp {asp:dose asp:percent-volume} . values ?role {CHEBI:38867 CHEBI:35480} . } order by ?l #+end_src *** exploration **** aspect counts #+begin_src sparql select distinct ?val_asp (count(?val_asp) as ?ac) where { ?ast_asp a protcur:aspect ; TEMP:hasValue ?val_asp . } GROUP BY ?val_asp ORDER BY desc(?ac) #+end_src **** input counts #+begin_src sparql select distinct ?val_inp ?lbl_inp (count(?val_inp) as ?ic) where { ?ast_inp a protcur:input ; TEMP:hasValue ?val_inp . OPTIONAL { ?val_inp rdfs:label ?lbl_inp } } GROUP BY ?val_inp ?lbl_inp ORDER BY desc(?ic) asc(str(?val_inp)) #+end_src **** samples few have additional parameterize #+begin_src sparql select distinct ?ast_in where { ?ast_in TEMP:hasValue sparc:Sample ; TEMP:protcurChildren ?ast_n . } #+end_src ***** explore :noexport: #+begin_src sparql :var limit="999" select distinct ?ast_in ?next_type ?next_value ?nv_value ?nv_unit ?nv_rv ?nn_type ?nn_value ?nnn_value ?nnn_unit ?nnn_rv where { ?ast_in TEMP:hasValue sparc:Sample ; TEMP:protcurChildren ?ast_n . ?ast_n a ?next_type ; TEMPRAW:hasValue ?nv_rv ; TEMP:hasValue ?next_value . optional { ?next_value rdf:value ?nv_value . ?next_value TEMP:hasUnit ?nv_unit . } optional { ?ast_n TEMP:protcurChildren+ ?ast_nn . ?ast_nn a ?nn_type ; TEMPRAW:hasValue ?nnn_rv ; TEMP:hasValue ?nn_value . optional { ?nn_value rdf:value ?nnn_value . ?nn_value TEMP:hasUnit ?nnn_unit . #?nn_value TEMPRAW:hasValue ?nnn_rv . #?nn_value rdf:value ?nnn_value ; #ilxtr:hasUnit ?nnn_unit . #?ast_nn TEMP:protcurChildren+ ?ast_nnn . #?ast_nnn a ?nnn_type ; #TEMP:hasValue ?nnn_value . } } } LIMIT ?limit #+end_src **** dilution the inputs that have dilation aspects associated are not normalized really need RRIDs for this part of the graph #+begin_src sparql select distinct #?val_inp ?rv_inp #(count(distinct ?rv_inp) as ?crv) where { ?ast_inp TEMPRAW:hasValue ?rv_inp ; # TEMP:hasValue ?val_inp ; TEMP:protcurChildren ?ast_asp . ?ast_asp TEMP:hasValue asp:dilution . } order by asc(str(?rv_inp)) #+end_src **** age #+begin_src sparql select distinct #?val_inp ?rv_inp #(count(distinct ?rv_inp) as ?crv) ?ast_value ?unit ?value ?rbunit ?rbvalue ?reunit ?revalue #?p #?o where { ?ast_inp TEMPRAW:hasValue ?rv_inp ; # TEMP:hasValue ?val_inp ; TEMP:protcurChildren ?ast_asp . ?ast_asp TEMP:hasValue asp:age ; TEMP:protcurChildren ?ast_invpar . ?ast_invpar TEMP:hasValue ?ast_value . ?ast_value ?p ?o . optional { ?ast_value TEMP:rangeStart ?rb . ?rb rdf:value ?rbvalue ; TEMP:hasUnit ?rbunit . ?ast_value TEMP:rangeStop ?re . ?re rdf:value ?revalue ; TEMP:hasUnit ?reunit . } optional { ?ast_value rdf:value ?value . ?ast_value TEMP:hasUnit ?unit . } } order by asc(str(?rv_inp)) #+end_src **** techniques #+begin_src sparql select distinct #?protocol ?tech (count(?tech) as ?ct) where { ?protocol a sparc:Protocol ; TEMP:protocolEmploysTechnique ?tech . } group by ?tech order by desc(?ct) #+end_src **** techniques raw here is the actual list of techniques that we have, however it definitely needs a further normalization pass than what we have here, very close to exverbs in terms of how it has been used as a catchall, and also because the annotations were targeting text with the expectation that we would normalize later and haven't #+begin_src sparql select distinct ?trs (count(?trs) as ?ct) where { ?protocol a sparc:Protocol ; TEMPRAW:protocolEmploysTechnique ?tech_raw . bind (lcase(str(?tech_raw)) as ?trs) } group by ?trs order by desc(?ct) #+end_src **** microscopy ***** explore as technique #+begin_src sparql select distinct ?protocol #?trs #(count(?trs) as ?ct) where { ?protocol a sparc:Protocol ; TEMPRAW:protocolEmploysTechnique ?tech_raw . bind (lcase(str(?tech_raw)) as ?trs) filter regex(?trs, "microsc") } #group by ?trs order by desc(?ct) #+end_src datasets with protocols missing microscopy where there is no protocol associated with that dataset that does include microscopy #+name: sparql-microscopy-mismatch #+begin_src sparql :noweb yes select distinct ?dataset ?protocol ?na where { filter (bound(?protocol)) filter (!bound(?somepred)) { <> } MINUS { # to get minus to work it needs to share a variable with the core query ?dataset a sparc:Dataset ; TEMP:hasExperimentalApproach ?approach . { ?protocol2 TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol2 } ?protocol2 TEMP:hasNumberOfProtcurAnnotations ?na2 . filter (?na2 > 0) ?protocol2 a sparc:Protocol ; ?somepred2 ?somestr2 . bind (lcase(str(?somestr2)) as ?lcs2) filter (?somepred2 != ) filter regex(?lcs2, "microsc") } } order by desc(?na) #+end_src clearly we have an issue the number of datasets with protocols that do not have anything about microscopy ... isn't quit what this does, but it close #+name: sparql-microscopy-check #+begin_src sparql select distinct ?dataset ?protocol ?na ?somepred ?lcs where { ?dataset a sparc:Dataset ; TEMP:hasExperimentalApproach ?approach . filter (str(?approach) = "microscopy") optional { { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol } ?protocol TEMP:hasNumberOfProtcurAnnotations ?na . # must be in protcur.ttl basically filter (?na > 0 ) optional { ?protocol a sparc:Protocol ; ?somepred ?somestr . bind (lcase(str(?somestr)) as ?lcs) filter (?somepred != ) filter regex(?lcs, "microsc") } } } order by ?dataset ?protocol ?somepred ?lcs # TODO order datasets based on how many rows they have in this table? #+end_src ***** maybe example query #+begin_src sparql select distinct ?species (count(distinct ?ast_in_sp) as ?cs) where { ?protocol a sparc:Protocol ; ?sigh ?ast_asp ; TEMP:protocolInvolvesInput ?ast_in_sp . ?ast_in_sp rdf:type protcur:input ; TEMP:hasValue ?species . #filter contains(str(iri(?species)), "NCBITaxon") ?species rdfs:subClassOf* NCBITaxon:1 . } group by ?species #+end_src another not-so-great attempt #+begin_src sparql select distinct ?s0 ?s1 where { ?region (rdfs:subClassOf|owl:someValuesFrom)+ UBERON:0000010 . ?s0 rdfs:subClassOf ?bn0 . ?bn0 a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?region_p0 . filter (?region = ?s0) filter (?region = ?region_p0) #?s1 rdfs:subClassOf ?bn1 . #?bn1 a owl:Restriction ; # owl:onProperty partOf: ; # owl:someValuesFrom ?region_p1 . #?s2 rdfs:subClassOf ?bn2 . #?bn2 a owl:Restriction ; # owl:onProperty partOf: ; # owl:someValuesFrom ?region_p2 . # #?s3 rdfs:subClassOf ?bn3 . #?bn3 a owl:Restriction ; # owl:onProperty partOf: ; # owl:someValuesFrom ?region_p3 . # #?s4 rdfs:subClassOf ?bn4 . #?bn4 a owl:Restriction ; # owl:onProperty partOf: ; # owl:someValuesFrom ?region_p4 . #values ?region_pn { UBERON:0000010 } . #filter (?s0 = ?region_pn) #?s rdfs:subClassOf ?bn0; owl:someValuesFrom UBERON:0000010 . #?bn1 owl:someValuesFrom } limit 10 #+end_src one approach to the part of query which doesn't filter properly :/ #+begin_src sparql select distinct ?region (str(?rl) as ?label) where { ?region rdfs:subClassOf+ UBERON:0001062 ; # with this it is 67 secons ??? (rdfs:subClassOf|owl:someValuesFrom)+ UBERON:0000010 ; # 41 - 45 seconds :/ rdfs:label ?rl ; rdfs:subClassOf ?rest . ?rest a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?region2 . # ?region rdfs:subClassOf ?rest ; rdfs:label ?rl . # ?rest a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?region2 . # # ?region2 rdfs:subClassOf+ UBERON:0001062 . # ?region2 (rdfs:subClassOf|owl:someValuesFrom)+ UBERON:0000010 . #?region2 UBERON:0000010 . #?region2 (rdfs:subClassOf|owl:someValuesFrom)* UBERON:0000010 . #{ } } limit 100 #+end_src this one can be a little bit different show me the species and objective magnification for datasets with protocols that involve magnification and that involve +part of the peripheral nervous system the nodose ganglion+ nerves or ganglia +as written this query is annoyingly slow+ the original ~partOf:~ based query was extremely slow #+name: sparql-magnification #+begin_src sparql SELECT DISTINCT ?dataset ?protocol ?id_species ?species ?id_region ?region ?value ?unit WHERE { ?protocol a sparc:Protocol ; TEMP:protocolInvolvesAspect ?ast_asp ; TEMP:protocolInvolvesInput ?ast_species ; ?_ ?ast_region . ?ast_asp a protcur:aspect ; TEMP:hasValue asp:magnification ; TEMP:protcurChildren [ TEMP:hasValue [ rdf:value ?value ; TEMP:hasUnit ?unit ] ] . ?ast_species rdf:type protcur:input ; TEMP:hasValue ?id_species . ?id_species rdfs:subClassOf+ NCBITaxon:33208 ; # metazoa rdfs:label ?sl . BIND (str(?sl) AS ?species) ?ast_region TEMP:protcurChildren* ?ast_reg ; TEMP:hasValue ?id_region . ?id_region rdfs:subClassOf+ ?nerves_and_ganglia ; rdfs:label ?rl . BIND (str(?rl) AS ?region) VALUES ?nerves_and_ganglia { UBERON:0000122 # neuron projection bundle UBERON:0000045 # ganglion } OPTIONAL { { ?dataset TEMP:hasProtocol ?protocol } UNION { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset }} } ORDER BY ?region ?dataset ?protocol #+end_src #+RESULTS: sparql-magnification | dataset | protocol | id_species | species | id_region | region | value | unit | |----------------------------------------------+---------------+-----------------+-------------------+----------------+---------------------------+-------+-----------| | dataset:d484110a-e6e3-4574-aab2-418703c978e2 | pio.api:22831 | NCBITaxon:10116 | Rattus norvegicus | UBERON:0005363 | inferior vagus X ganglion | 40 | unit:fold | | dataset:d484110a-e6e3-4574-aab2-418703c978e2 | pio.api:22831 | NCBITaxon:10116 | Rattus norvegicus | UBERON:0005363 | inferior vagus X ganglion | 63 | unit:fold | | dataset:e4bfb720-a367-42ab-92dd-31fd7eefb82e | pio.api:22831 | NCBITaxon:10116 | Rattus norvegicus | UBERON:0005363 | inferior vagus X ganglion | 40 | unit:fold | | dataset:e4bfb720-a367-42ab-92dd-31fd7eefb82e | pio.api:22831 | NCBITaxon:10116 | Rattus norvegicus | UBERON:0005363 | inferior vagus X ganglion | 63 | unit:fold | | dataset:6fa2666c-aa3d-4e27-a405-7848fc061b04 | pio.api:19131 | NCBITaxon:10116 | Rattus norvegicus | UBERON:0001759 | vagus nerve | 20 | unit:fold | | dataset:ff6eb067-62d4-4bfb-b4b2-15ad65db0999 | pio.api:19143 | NCBITaxon:10090 | Mus musculus | UBERON:0001759 | vagus nerve | 20 | unit:fold | **** pressure :PROPERTIES: :CREATED: [2023-07-26 Wed 23:47] :END: blood pressure might work maybe? #+begin_src sparql select distinct ?protocol #?val_inp ?ast_asp ?in_type ?rv_inp #(count(distinct ?rv_inp) as ?crv) ?c_type ?raw_invpar ?ast_val_invpar where { ?protocol TEMP:protocolInvolvesAspect ?ast_asp . ?ast_asp TEMP:hasValue asp:pressure . optional { ?ast_inp a ?in_type ; TEMPRAW:hasValue ?rv_inp ; # TEMP:hasValue ?val_inp ; TEMP:protcurChildren ?ast_asp . } optional { ?ast_asp TEMP:protcurChildren ?c . ?c a ?c_type . } values ?invpar {protcur:invariant protcur:parameter} . optional { ?ast_asp TEMP:protcurChildren ?ast_invpar . ?ast_invpar a ?invpar ; TEMPRAW:hasValue ?raw_invpar ; TEMP:hasValue ?ast_val_invpar . } } order by ?protocol asc(str(?rv_inp)) #+end_src [[pio.html:18655]] deleted ??? [[pio.html:18786]] also del ??? [[pio.html:22863]] ** Datasets following same protocol with different subjects *** Completeness #+begin_src sparql SELECT DISTINCT ?dataset ?completeness WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:completenessOfDataset ?completeness . } LIMIT ?limit #+end_src *** Dataset collections #+begin_src sparql SELECT DISTINCT ?title ?dataset WHERE { ?startdataset TEMP:collectionTitle ?title . ?dataset TEMP:collectionTitle ?title . } ORDER BY ASC(?title) LIMIT ?limit #+end_src ** Subjects *** Members Show me all of the experimental subjects that a dataset contains information about. #+begin_src sparql SELECT DISTINCT ?dataset ?subject WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:isAboutParticipant ?subject . ?subject a sparc:Subject . } LIMIT ?limit #+end_src *** Total Show me the total number of subjects in the knowledge graph. #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?subject) as ?count_subject) WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:isAboutParticipant ?subject . ?subject a sparc:Subject . } #+end_src *** Subject Metadata Show me a regularized set of metadata for all subjects that includes the following. - Identifier - Group - Species - Strain - Sex - Age Category - Age - Mass # #+header: :var species="NCBITaxon:10116" # #+header: :var species="NCBITaxon:9685" #+name: subject-metadata #+begin_src sparql SELECT DISTINCT ?local_id ?assigned_group ?l_species ?strain ?l_sex ?age_category ?age_value ?age_unit ?mass_value ?mass_unit WHERE { ?subject a sparc:Subject . ?subject TEMP:localId ?local_id . ?subject sparc:animalSubjectIsOfSpecies ?species . OPTIONAL { ?species rdfs:label ?l_species . } OPTIONAL { ?subject sparc:animalSubjectIsOfStrain ?strain . } # ?strain rdfs:label ?l_strain . OPTIONAL { ?subject TEMP:hasBiologicalSex ?sex . ?sex rdfs:label ?l_sex . } OPTIONAL { ?subject TEMP:hasAgeCategory ?age_category . } OPTIONAL { ?subject TEMP:hasAssignedGroup ?assigned_group . } # OPTIONAL { ?subject TEMP:participantInPerformanceOf ?protocol . } OPTIONAL { # mass ?subject sparc:animalSubjectHasWeight ?bn_mass . ?bn_mass a sparc:Measurement . ?bn_mass TEMP:hasUnit ?mass_unit . ?bn_mass rdf:value ?mass_value . } OPTIONAL { # age ?subject TEMP:hasAge ?bn_age . ?bn_age a sparc:Measurement . ?bn_age TEMP:hasUnit ?age_unit . ?bn_age rdf:value ?age_value . } # VALUES ?l_s {?species ?sex} # doesn't work, if it did it would duplicate rows # ?l_s rdfs:label ?label } LIMIT ?limit #+end_src #+call: subject-metadata() :var species="NCBITaxon:10090" *** TODO By sex #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?subject) as ?count_subject) WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:isAboutParticipant ?subject . ?subject a sparc:Subject . } #+end_src ** Samples *** Members Show me all of the experimental samples that a dataset contains information about. #+begin_src sparql SELECT DISTINCT ?dataset ?sample WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:isAboutParticipant ?sample . ?sample a sparc:Sample . } LIMIT ?limit #+end_src *** Total Show me the total number of samples in the knowledge graph. #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?sample) as ?count_sample) WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:isAboutParticipant ?sample . ?sample a sparc:Sample . } #+end_src *** Sample predicates #+begin_src sparql SELECT DISTINCT ?p WHERE { ?sample a sparc:Sample . ?sample ?p ?o . } #+end_src *** Sample Metadata Show me a regularized set of metadata for all subjects that includes the following. - Identifier - Group - Anatomical entity #+name: sample-metadata #+begin_src sparql SELECT DISTINCT ?subject_lid ?local_id ?assigned_group (str(?anat_ent_src) as ?aess) WHERE { ?sample a sparc:Sample . ?sample TEMP:localId ?local_id . ?sample TEMP:wasDerivedFromSubject ?subject . ?subject TEMP:localId ?subject_lid . ?subject a sparc:Subject . OPTIONAL { ?sample TEMP:hasAssignedGroup ?assigned_group . } OPTIONAL { ?sample TEMPRAW:wasExtractedFromAnatomicalRegion ?anat_ent_src . } # OPTIONAL { ?sample TEMP:hasAge ?abe . } # OPTIONAL { ?sample TEMP:participantInPerformanceOf ?protocol . } } LIMIT ?limit #+end_src ** Anatomical entities *** Dataset **** Involves # FIXME unused at the moment #+begin_src sparql :var limit="30" SELECT DISTINCT ?dataset ?protocol #?ae (str(?aes) as ?entity) WHERE { ?dataset a sparc:Dataset . #?dataset TEMP:hasProtocol ?protocol . { ?protocol TEMP:priorInformationalConstraintOnProcessThatGenerated ?dataset } union { ?dataset TEMP:hasProtocol ?protocol } ?protocol TEMPRAW:involvesAnatomicalRegion ?aes . # ?ae rdfs:label ?l_ae . } ORDER BY ASC(?entity) LIMIT ?limit #+end_src **** About #+begin_src sparql SELECT DISTINCT ?dataset # ?ae (str(?l_ae) as ?entity) WHERE { ?dataset a sparc:Dataset . ?dataset isAbout: ?ae . # TODO not 100% on the modelling here ?ae rdfs:label ?l_ae . ?ae rdfs:subClassOf* UBERON:0001062 . # have to load uberon for this } ORDER BY ASC(?l_ae) LIMIT ?limit #+end_src **** Sample Source #+name: dataset-sample-source #+begin_src sparql :var limit="20" SELECT DISTINCT ?dataset (str(?ae) as ?aes) # ?slid WHERE { ?sample TEMP:hasDerivedInformationAsParticipant ?dataset . ?sample TEMPRAW:wasExtractedFromAnatomicalRegion ?ae . ?sample a sparc:Sample . # ?sample TEMP:localId ?slid . ?dataset a sparc:Dataset . } ORDER BY DESC(?ae) # ASC(?slid) LIMIT ?limit #+end_src *** Protocol **** Simple #+name: sparql-count-protocols-pio-api #+begin_src sparql :noweb yes SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: sparql-protocols-pio-api #+begin_src sparql :var limit="10" :epilogue "LIMIT ?limit" SELECT DISTINCT ?protocol WHERE { ?protocol a sparc:Protocol . FILTER CONTAINS(str(?protocol), "protocols.io/api") #FILTER CONTAINS(str(?protocol), "protocols.io") } #+end_src **** Protocol triples #+begin_src sparql :var limit="20" SELECT DISTINCT ?protocol ?p ?o WHERE { ?protocol a sparc:Protocol . ?protocol ?p ?o FILTER CONTAINS(str(?protocol), "protocols.io") } LIMIT ?limit #+end_src **** Involves NOTE In order for these to work with subClassOf =UBERON= uberon must be loaded. #+begin_src sparql :var limit="20" SELECT DISTINCT ?protocol ?bb_value (str(?l_bb) as ?ls) WHERE { ?protocol a sparc:Protocol . ?protocol TEMP:protocolInvolvesBlackBox ?ast_bb . ?ast_bb rdf:type protcur:black-box . # TODO need to refine on organ an ingest the new alignment ?ast_bb TEMP:hasValue ?bb_value . ?bb_value rdfs:subClassOf+ UBERON:0001062 . ?bb_value rdfs:label ?l_bb . } LIMIT ?limit #+end_src # seems like there are some issues with labels https://jira.blazegraph.com/browse/BLZG-4476 # :format application/sparql-results+xml #+begin_src sparql :var limit="20" SELECT DISTINCT ?protocol ?bbc_value (str(?l_bbc) as ?bbl) WHERE { ?protocol a sparc:Protocol . ?protocol TEMP:protocolInvolvesBlackBoxComponent ?ast_bbc . ?ast_bbc rdf:type protcur:black-box-component . # TODO need to refine on organ an ingest the new alignment ?ast_bbc TEMP:hasValue ?bbc_value . ?bbc_value rdfs:subClassOf+ UBERON:0001062 . ?bbc_value rdfs:label ?l_bbc . } ORDER BY ?bbl LIMIT ?limit #+end_src **** Protc annotations #+begin_src bash :eval never grep -oE 'a\ protcur:[^\ ]+' protcur.ttl | sort -u | cut -d' ' -f2 #+end_src #+name: sparql-count-annotations-protc #+begin_src sparql :noweb yes select (count(*) as ?count) { <> }} #+end_src #+name: sparql-count-annotations-pio-api-protc #+begin_src sparql :noweb yes select (count(*) as ?count) { <> } #+end_src #+name: sparql-annotations-pio-api-protc #+begin_src sparql :noweb yes <> ?protocol a sparc:Protocol . ?protocol ?p ?banno . ?banno TEMP:protcurChildren* ?anno . FILTER CONTAINS(str(?protocol), "protocols.io/api") #FILTER CONTAINS(str(?protocol), "protocols.io") } #+end_src #+name: sparql-annotations-protc #+begin_src sparql :epilogue "}" select distinct ?anno where { # TODO subPropertyOf #values ?anno_predicate {} # this is a bad way to do this # ?s ?anno_predicate ?anno values ?anno_type { protcur:aspect protcur:black-box protcur:black-box-component protcur:executor-verb protcur:input protcur:invariant protcur:output protcur:parameter } ?anno a ?anno_type . #+end_src ** Uberon tests In order to use these you need to load the latest version of uberon into blazegraph. #+begin_src sparql :var limit="15" SELECT DISTINCT ?sc (str(?l) as ?label) WHERE { # BIND("brain" AS ?label) # Well would you look at that! VALUES (?root) { ( UBERON:0001062 ) } ?sc rdfs:subClassOf+ ?root . ?sc rdfs:label ?l . } ORDER BY ASC(?label) LIMIT ?limit #+end_src #+begin_src sparql select ?p ?o where { VALUES (?s) { ( UBERON:0001062 ) } ?s ?p ?o . } #+end_src ** Associated scaffolds ** Manifest files A SODA development use case. Find me datasets that have top level manifests with no errors. #+begin_src sparql SELECT DISTINCT ?dataset WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:hasPart+ ?file . ?file a sparc:File . ?file a sparc:Manifest . ?file TEMP:hasParent ?dataset . # this is the tricky bit, because we conflate the identifier for dataset and the folder ?file TEMP:hasErrors 0 . } LIMIT ?limit #+end_src ** Contributors *** Count #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?person) as ?cp) WHERE { ?person a sparc:Person . } LIMIT ?limit #+end_src *** ORCiD Count the number of contributors that have ORCiDs. #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?person) as ?cp) #?fn #?ln WHERE { ?person a sparc:Person . ?person sparc:firstName ?fn . ?person sparc:lastName ?ln . FILTER CONTAINS(str(?person), "orcid.org") } LIMIT ?limit #+end_src ** Other NOTE These are not yet in the ttl file, the queries written here will not work yet. *** File types In all likelihood we are not going to include the names of each of the individual files in the standard ttl export. We may put it in a named graph and then update the journal, possibly only for released datasets. The use cases for having individual files in the graph is not at all clear, we might have individual folders, or run it in the other direction where a subject could list the folders that contain data about it. Trying to keep the graph in sync with Blackfynn would be quite a pain, essentially we would store/append every single file that ever appears and then mark the deleted ones as deleted or something. #+begin_src sparql SELECT DISTINCT ?dataset ?file_type WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:containsFileWithType ?file_type . # TODO not 100% on the modelling here } LIMIT ?limit #+end_src In the =path-metadata= folder of =curation-export=. #+begin_src bash grep -rh 'mimetype":' | sort | uniq -c | sort -h #+end_src This doesn't get coverage for file extensions so in addition we run the following. #+begin_src bash grep -rh 'basename":.\+\.\([a-z]\+\)' | grep -o '\.[a-z]\+"' | sort | uniq -c | sort -h #+end_src *** Has Raw Data #+begin_src sparql SELECT DISTINCT ?dataset ?raw WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:containsFolderForRawData ?raw . # TODO not 100% on the modelling here } LIMIT ?limit #+end_src *** Has Derived Data #+begin_src sparql SELECT DISTINCT ?dataset ?derived WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:containsFolderForDerivedData ?derived . # TODO not 100% on the modelling here } LIMIT ?limit #+end_src *** Has Code #+begin_src sparql SELECT DISTINCT ?dataset ?code WHERE { ?dataset a sparc:Dataset . ?dataset TEMP:containsFolderForCode ?code . # TODO not 100% on the modelling here } LIMIT ?limit #+end_src *** Used in simulation This modeling is extremely preliminary. #+begin_src sparql SELECT DISTINCT ?dataset ?dataset_sim WHERE { ?dataset a sparc:Dataset . ?dataset_sim a sparc:Dataset . # TODO not 100% on this # the dataset holds the simulation, and is also what references the other datasets # whether we need an explicit type for simulation datasets is not clear, I suspect # that we do not, since datasets are just data, the aboutness or typeness probably # should come from the fact that the dataset specifies or houses a simulation ... # ?dataset_sim a sparc:SimulationDataset . # also not good # ?dataset_sim TEMP:isSubstrateForSomeComputationalSimulation true . # FIXME this is bad bad bad VALUES ?p {TEMP:derivesParametersFrom TEMP:derivesValidationDataFrom ilxtr:hasInformationInput} . ?dataset_sim ?p ?dataset . } LIMIT ?limit #+end_src ** Subject reconciliation first pass requires that the subject_id be identical *** v2 #+name: pds-v2-count #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: pds-v2 #+begin_src sparql :epilogue "\nLIMIT ?limit\n" :var limit="9" SELECT DISTINCT ?s ?dataset (str(?id) as ?local_id) ?award ?species WHERE { ?s a sparc:Subject; TEMP:localId ?id; TEMP:hasDerivedInformationAsParticipant ?dataset ; sparc:animalSubjectIsOfSpecies ?species . ?dataset a sparc:Dataset ; TEMP:hasAwardNumber ?award . { SELECT DISTINCT ?id WHERE { ?s a sparc:Subject ; TEMP:localId ?id ; TEMP:hasDerivedInformationAsParticipant ?dataset . } GROUP BY ?id HAVING (count(?id) > 1) } } ORDER BY ?id #+end_src # #+header: :results drawer output # #+header: :var by_id=(and) #+header: :epilogue "return table" :results value table #+name: pds-v2-python #+begin_src python :var data=pds-v2(limit="99999") :exports results import sys from pprint import pprint from collections import Counter counts = Counter([(id, species, award) for _, _, id, species, award in data]) #print(len([c for c in counts.values() if c > 1])) #pprint(counts) multi = [row for row in data if counts[tuple(row[2:])] > 1] for index in (0, 1, 3, 4): for row in multi: try: row[index] = OntId(row[index]).curie # shorten iris except Exception as e: sys.stderr.write(f'not a curie! {row[index]}') # FIXME how to stderr hardcoded_header = [ f'individuals (n={len(multi)})', 'dataset', f'id (n={len(set([r[2] for r in multi]))})', 'awards', 'species'] key_id = lambda row:(row[2], row[3], row[4], row[1]) key_award_species_dataset_id = lambda row:(row[3], row[1], row[2], row[4]) table = [hardcoded_header] + [None] + sorted(set(tuple(_) for _ in multi))#, key=(key_id if by_id else key_award_species_dataset_id) #+end_src #+begin_src elisp :results none :exports none (let ((org-table-convert-region-max-lines most-positive-fixnum)) (ow-babel-eval "pds-v2-python")) #+end_src *** v1 # #+header: :cache yes #+name: potential-duplicate-subjects #+begin_src sparql :cache yes # :results table # RUN:block SELECT distinct ?s1 ?s2 ?id ?dataset1 ?dataset2 ?species1 ?species2 ?award1 ?award2 WHERE { # Give me all subjects with duplicate IDs with unique datasets { SELECT ?id WHERE { ?s1 a owl:NamedIndividual ; TEMP:localId ?id ; TEMP:hasDerivedInformationAsParticipant ?datasetx . ?s2 a owl:NamedIndividual ; TEMP:localId ?id ; TEMP:hasDerivedInformationAsParticipant ?datasety . filter(?datasetx != ?datasety) } GROUP BY ?id having (count(?id) > 1)} # filter out the cases where there can't be a match because species doesn't match ?s1 TEMP:localId ?id ; sparc:animalSubjectIsOfSpecies ?species1; TEMP:hasDerivedInformationAsParticipant ?dataset1 . ?s2 TEMP:localId ?id ; sparc:animalSubjectIsOfSpecies ?species2; TEMP:hasDerivedInformationAsParticipant ?dataset2 . filter(?s1 != ?s2) filter(STR(IRI(?s1)) < STR(IRI(?s2))) # this is a hack to filter out duplicate triples # filter to find non-matching awards # using contact person doesn't make sense as they are 1:1 with award right now ?dataset1 a owl:NamedIndividual ; TEMP:hasAwardNumber ?award1 . ?dataset2 a owl:NamedIndividual ; TEMP:hasAwardNumber ?award2 . } order by ?id limit ?limit #+end_src # *[[RUN:][Run Query ▶]]* # #+header: :results drawer output #+header: :epilogue "return result" #+name: process-duplicate-subjects #+begin_src python :var data=potential-duplicate-subjects(limit="99999") :exports results from pprint import pprint import sys import itertools from collections import defaultdict, OrderedDict, Counter from sparcur.core import OntId def func(data): idmap = defaultdict(lambda: defaultdict(list)) # change to list; order for local_id for row in data: subj1, subj2, local_id = row[0], row[1], row[2] if not idmap[subj1]['local_id']: idmap[subj1]['local_id'].append(local_id) idmap[subj1]['cluster'].append(subj2) idmap[subj1]['local_id'].append(local_id) value_pairs = [(row[i], row[i+1]) for i in range(3, len(row), 2)] value_pairs_len = len(value_pairs) for i, value_pair in enumerate(value_pairs): v1, v2 = value_pair if v1 not in idmap[subj1][i]: idmap[subj1][i].append(v1) idmap[subj1][i].append(v2) header = ['cluster', 'local_id'] + [i for i in range(value_pairs_len)] # todo: replace this with sparql headers if possible columns = defaultdict(list) subjs = sorted([(v, v.split('/')[-1]) for v in idmap], key=lambda x: x[1]) for subj, _ in subjs: padding_max = max([len(v) for v in idmap[subj].values()]) for colname, values in idmap[subj].items(): values = list(values) values = [subj] + values if colname == 'cluster' else values padding = padding_max - len(values) if len(values) < padding_max else 0 columns[colname] += values # + ['-'] * padding + [''] __thing = [list(_) for _ in itertools.zip_longest(*[columns[k] for k in header])] _thing = sorted(list(_) for _ in set(tuple(_) for _ in __thing)) counts = Counter([(id, species, award) for _, id, _, species, award in _thing]) thing = [row for row in _thing if counts[tuple(row[x] for x in [1, 3, 4])] > 1] # remove unique rows since there is no chance they will match for index in (0, 2, 3, 4): for row in thing: try: row[index] = OntId(row[index]).curie # shorten iris except Exception as e: sys.stderr.write(f'not a curie! {row[index]}') # FIXME how to stderr hardcoded_header = [f'individuals (n={len(thing)})', f'id (n={len(set([r[1] for r in thing]))})', 'datasets', 'species', 'awards'] table = [hardcoded_header] + [None] + sorted(set(tuple(_) for _ in thing), key=lambda row:(row[1], row[3], row[4], row[2])) return table result = func(data) #+end_src #+RESULTS: process-duplicate-subjects * Python helper ** call # Use this block to run the next block an all dependencies without being asked again. #+begin_src elisp :results none :exports none (ow-babel-eval "neru-simplified") #+end_src #+header: :var json-string=python-neru-helper(result=cypher-neru-6-helper(neupop_id="ilxtr:neuron-type-aacar-12")) #+header: :var path="./images/neru-simplified-aacar-12.svg" :results file #+name: neru-simplified #+begin_src elisp :exports none (json->svg-file json-string path) #+end_src #+RESULTS: neru-simplified [[file:./images/neru-simplified-aacar-12.svg]] ** simple Python code to simplify =neru= and supporting functions to extract terminal regions. # FIXME emacs-jupyter doesn't convert t -> True !??! # FIXME this doesn't highlight correctly in init-simple.el # FIXME the python will run the epilogue for in a babel call but jupyter-python will not, fun times # #+header: :epilogue "\nimport json\nb, ed, s, ex, o = main(blob_string=result)\n#return json.dumps(b, indent=1, sort_keys=False)" #+header: :epilogue "\nimport json\nb, ed, s, ex, o = main(neupop_id=\"ilxtr:neuron-type-keast-6\")\nprint(json.dumps(b, indent=1, sort_keys=False))" #+header: :results drawer #+header: :var result=(or) remove=(or) #+name: python-process-neru #+begin_src jupyter-python :session pys from pyontutils.config import auth from nifstd_tools.simplify import apinat_deblob, sub, pred, obj, ematch from nifstd_tools.simplify import axon, dend, bag, top, ie, ies, iot, iots, ext, fasIn, endIn, layerIn, onts ext = onts # XXX schema change def query(neupop_id): import requests url = ('https://scicrunch.org/api/1/sparc-scigraph/scigraph/dynamic/' f'demos/apinat/neru-7/{neupop_id}?limit=9999999&key={auth.get("scigraph-api-key")}') resp = requests.get(url, headers={'Accept': 'application/json'}) blob = resp.json() return blob def find_terminals(blob, type): return [es for es in blob['edges'] if pred(es, iots) and obj(es, type) and ematch(blob, (lambda e, m: sub(e, m) and pred(e, top) and obj(e, bag)), sub(es))] def find_region(blob, edge): collect = [] def select(e, m, collect=collect): if sub(e, m): #print(e) if pred(e, layerIn) or pred(e, fasIn) or pred(e, endIn): return ematch(blob, select, obj(e)) elif pred(e, onts): region = obj(e) collect.extend([b for b in blob['nodes'] if b['id'] == region]) return region ematch(blob, select, sub(edge)) return collect def find_region_layer(blob, edge, bindex): _nonelayer = False collect = [] layers = [] layers_iots = [] donel = set() doner = set() def select_term(e, m, layers=layers): if sub(e, m): pprint(e) if (pred(e, onts) or pred(e, iot) or pred(e, iots)): layer = obj(e) if layer not in donel: donel.add(layer) if pred(e, iot) or pred(e, iots): layers_iots.append(bindex[layer]) else: layers.append(bindex[layer]) return layer def select(e, m, collect=collect): if sub(e, m): if pred(e, layerIn): # we're at a layer ematch(blob, select_term, sub(e)) return ematch(blob, select, obj(e)) elif (pred(e, fasIn) or pred(e, endIn)): return ematch(blob, select, obj(e)) elif pred(e, onts): region = obj(e) if region not in doner: doner.add(region) collect.append(bindex[region]) return region ematch(blob, select, sub(edge)) if collect and not layers and not layers_iots: layers = [None] _nonelayer = True elif layers_iots and not layers: layers = layers_iots if not layers and (_nonelayer or layers_iots): layers = [None] if len(collect) != len(layers): raise ValueError(f'len not matched {len(collect)} {len(layers)}') return list(zip(collect, layers)) def find_terminal_regions(blob, type): return [region for es in find_terminals(blob, type) for region in find_region(blob, es)] def find_terminal_region_layers(blob, type, bindex): return [(region, layer) for es in find_terminals(blob, type) for region, layer in find_region_layer(blob, es, bindex)] def main(blob=None, blob_string=None, neupop_id=None, remove_converge=remove): # do not call this function unless it is from an org babel block, there are free variables if blob is None and blob_string is not None: import json blob = json.loads(blob_string) neupop_id = neupop_id if neupop_id else 'ilxtr:neuron-type-keast-6' if blob is None: blob = query(neupop_id) blob, edges, somas, externals, ordering_edges = v = apinat_deblob( blob, remove_converge=remove_converge) test_call = False # change to True to test the #+call: expression if test_call: pprint(v) return v #+end_src #+call: python-process-neru(result=cypher-neru-6-helper(neupop_id="ilxtr:neuron-type-aacar-12")) #+begin_src jupyter-python :session pys pprint(blob) #+end_src # we need this block because jupyter-python doesn't include the epilogue when being called by another block wew # #+header: :epilogue "\nimport pprint\nreturn pprint.pformat(ed)" # #+header: :epilogue "\nimport json\nb, ed, s, ex, o = main(neupop_id=\"ilxtr:neuron-type-keast-6\")\nreturn json.dumps(b, indent=1, sort_keys=False)" # #+header: :var result=cypher-neru-3-helper(neupop_id="ilxtr:neuron-type-keast-6") #+header: :results drawer #+header: :var result=(or) remove=(and "sigh") #+header: :epilogue "\nimport json\nb, ed, s, ex, o = main(blob_string=result)\nreturn json.dumps(b, indent=1, sort_keys=False)" #+name: python-neru-helper #+begin_src python :noweb yes :exports none <> #+end_src ** terminal regions Find the ontology identifiers for terminal regions. # run this to populate/update the kernel (sigh) #+call: python-process-neru(result=cypher-neru-6-helper(neupop_id="ilxtr:neuron-type-aacar-5")) #+header: :var remove=(or) result=cypher-neru-6-helper(neupop_id="ilxtr:neuron-type-keast-6") #+name: neru-find-terminal-regions #+begin_src jupyter-python :session pys :exports both :var neupop_id="" :noweb yes <> from pprint import pprint blob, *_ = main(blob_string=result) bindex = {n['id']:n for n in blob['nodes']} # find terminal regions axon_terminal_regions = find_terminal_regions(blob, axon) dend_terminal_regions = find_terminal_regions(blob, dend) #pprint(axon_terminal_regions) #pprint(dend_terminal_regions) axon_terminal_rl = find_terminal_region_layers(blob, axon, bindex) dend_terminal_rl = find_terminal_region_layers(blob, dend, bindex) pprint([(r['id'], (l if l is None else l['id'])) for r, l in axon_terminal_rl]) pprint([(r['id'], (l if l is None else l['id'])) for r, l in dend_terminal_rl]) #+end_src ** connectivity pairs This code produces the basic connectivity of a neuron population. The result is a list of pairs, the pairs are the subject and object of the triple =subject (or apinatomy:next apinatomy:next*) object=. Thus they represent the full connectivity of the population. The contents of each element of the pair tuples with three elements. 1. The id for the neuronal process involved in the connection. 2. The ontology id for the layer in which the neuronal process is located. This may be None if no layer is specified in the model. 3. The ontology id for the region in which the neuronal process is located. In the example presented here for keast neuron 5 the final entries all have the same start and end location because they are the soma, and the roots of the axon and the dendrite. #+name: py-conn-pairs #+begin_src jupyter-python :session pys intIn = 'apinatomy:internalIn' def isLayer(blob, s): return ematch(blob, (lambda e, m: sub(e, m) and pred(e, layerIn)), s) def reclr(blob, start_link): # recurse up the hierarchy until fasIn endIn intIn terminates #print('starting reclr') collect = [] layer = [] col = True def select_ext(e, m, collect=collect): nonlocal col nonlocal layer if sub(e, m): if pred(e, 'apinatomy:cloneOf'): # should be zapped during simplify return ematch(blob, select_ext, obj(e)) if pred(e, onts) or pred(e, iot) or pred(e, iots): #print('select_ext', e) external = obj(e) #print('se', col, layer) if col: if layer: if len(layer) > 1: l, *layer = layer else: l = layer.pop() else: l = None r = [b for b in blob['nodes'] if b['id'] == external][0]['id'] # if this is empty we are in big trouble collect.append((l, r)) else: l = [b for b in blob['nodes'] if b['id'] == external][0]['id'] layer.append(l) #print(layer) return external def select(e, m): nonlocal col if sub(e, m): #print(e) if pred(e, layerIn) or pred(e, fasIn) or pred(e, endIn) or pred(e, intIn): #print('select', e) col = not isLayer(blob, obj(e)) #print('s', col) ematch(blob, select_ext, obj(e)) ematch(blob, select, obj(e)) ematch(blob, select, start_link) return collect def lay_reg(blob, start): direct = [obj(t) for t in ematch(blob, (lambda e, m: sub(e, m) and (pred(e, intIn) or # XXX why isn't this getting pulled in correctly for somas? answer: missing somas in starts? surely not, ARGH a lyph internalIn a layer # FIXME this is the interneuron case FIXME axon terminal in same region case even if leaves region pred(e, endIn) or pred(e, fasIn))), start)] layers = [obj(t) for d in direct for t in ematch(blob, (lambda e, m: sub(e, m) and isLayer(blob, m) and (pred(e, iot) or pred(e, iots) or pred(e, onts))), d)] lregs = [] if layers: ldir = [obj(t) for d in direct for t in ematch(blob, (lambda e, m: sub(e, m) and pred(e, layerIn)), d)] lregs = [obj(t) for d in ldir for t in ematch(blob, (lambda e, m: sub(e, m) and not isLayer(blob, m) and (pred(e, iot) or pred(e, iots) or # XXX ie seems to have no hits now pred(e, onts))), d)] regions = [obj(t) for d in direct for t in ematch(blob, (lambda e, m: sub(e, m) and not isLayer(blob, m) and (pred(e, iot) or pred(e, iots) or pred(e, onts))), d)] #if start == 'kblad:snl16': #print(start, direct, layers, regions) # FIXME TODO nested regions and layers lrs = reclr(blob, start) # FIXME doesn't pair regions and layers # FIXME SIGH SIGH SIGH start can be either part of a next >_< #print(lrs) assert not (lregs and regions), (lregs, regions) # not both regions = lregs if lregs else regions #out = start, layers[0] if layers else None, regions[0] if regions else None, tuple([l for l in lrs]) out = start, tuple(lrs) if out: return out def render_blob(blob): starts = [obj(e) for e in blob['edges'] if pred(e, 'apinatomy:lyphs')] nxt = 'apinatomy:next' nxts = 'apinatomy:next*' nexts = [(sub(t), obj(t)) for start in starts for t in ematch(blob, (lambda e, m: pred(e, nxt) or pred(e, nxts)), None)] #pprint(nexts) connected_pairs = sorted(set([tuple([lay_reg(blob, e) for e in p]) for p in nexts])) #pprint(connected_pairs) return connected_pairs #+end_src #+call: python-process-neru(result=cypher-neru-6-helper(neupop_id="ilxtr:neuron-type-keast-1")) #+begin_src jupyter-python :session pys blob, *_ = main(blob_string=result) render_blob(blob) #+end_src ** neru #+name: py-neupop-helper #+begin_src jupyter-python :noweb yes :session pys :var remove=(and "sigh") :results none from pprint import pprint from pyontutils.scigraph import Cypher, Vocabulary from pyontutils.scigraph_codegen import moduleDirect from pyontutils.config import auth scigraphd = moduleDirect(auth.get('scigraph-api'), 'scigraphd') <> <> sgv = Vocabulary() sgd = scigraphd.Dynamic(cache=True, verbose=True, do_error=True) sgc = scigraphd.Cypher(cache=True, verbose=True) q_neru_6 = """ <> """ q_neru_7 = """ <> """ q_cnap = """ <> """ def neupop_blob(neupop_id): # XXX requires a patch to Cypher and CypherBase to support arbitrary kwargs blob = sgc.execute(query=q_neru_7, limit=None, neupop_id=neupop_id, output='application/json') return blob def sigh(): blobs = [neupop_blob(f"ilxtr:neuron-type-keast-{npid}") for npid in range(1, 21)] debs = [main(blob=blob)[0] for blob in blobs] simples = [render_blob(deb) for deb in debs] #[pprint(simple) for simple in simples[:1]] def fbid(id): if id: result = sgv.findById(id) if result['labels']: return result['labels'][0] def fbids(ids): return [(id, fbid(id)) for id in ids] def rendlab(pairs): for pair in pairs: yield tuple((start, *(tuple(fbids(hp)) for hp in housings)) for start, housings in pair) #for (*tstart, sid, sasdf), (*tend, eid, easdf) in pairs: #yield ((*tstart, sid, fbid(sid), fbids(sasdf)) if sid else (*tstart, sid, fbids(sasdf)), #(*tend, eid, fbid(eid), fbids(easdf)) if eid else (*tend, eid, fbids(easdf))) #+end_src #+begin_src jupyter-python :session pys :results none from copy import deepcopy blobs = [neupop_blob(f"ilxtr:neuron-type-keast-{npid}") for npid in range(1, 21)] debs = [main(blob=deepcopy(blob))[0] for blob in blobs] simples = [render_blob(deb) for deb in debs] sigh = [s for n, si in enumerate(simples) for s in ((f'--------- {n + 1}','---------'), *sorted(rendlab(si)))] #+end_src #+begin_src jupyter-python :session pys #sigh #pprint(blobs[0]) #pprint(debs[0]) #pprint(simples[0]) #sigh[:200] sigh #+end_src #+header: :depend py-nbr-1 #+begin_src jupyter-python :session pys :results none from neurondm import orders from neurondm.models.nlp import add_partial_orders from pyontutils.core import OntId, OntGraph from pyontutils.utils import log from pyontutils.config import auth from pyontutils.namespaces import ilxtr def apinat_to_raw_adj(blob): dblob, *_ = apinat_deblob(blob) cpairs = render_blob(dblob) cpairs_bad = [c for c in cpairs if not (c[0][1] and c[1][1])] if cpairs_bad: log.error(f'cpairs_bad: {cpairs_bad}') cpairs_ok = [c for c in cpairs if c[0][1] and c[1][1]] raw_adj = [((r1, l1), (r2, l2)) for # region first since neurondm.orders.rl.__init__(self, region, layer=None) ((link1, ((l1, r1), *housing1)), (link2, ((l2, r2), *housing2))) # FIXME housing ... # FIXME no projections case ... do we link to self for soma? XXX yes, we link back to self in cpairs_ok] raw_adj = sorted(set(raw_adj), key=lambda tt: tuple(('' if t[0] is None else t[0], '' if t[1] is None else t[1]) for t in tt)) if len(raw_adj) > 1: # non degenerate case raw_adj = [(a, b) for a, b in raw_adj if a != b] # soma cycles if there are other connections return raw_adj def all_nst(ids, blobs): pos = {} for id, blob in zip(ids, blobs): #print(id) raw_adj = apinat_to_raw_adj(blob) nst = raw_adj_to_nst(raw_adj) if nst: pos[OntId(id).u] = nst return pos def raw_adj_to_nst(raw_adj): # apparently dupes ARE an issue on the input for some reason and produce # really wild results and aren't culled by set ??? or rather there are # issues with the stability of the rl sort which translate to unstable # representations in the ttl, so that will need to get sorted out def key(tt): return tuple(tuple('' if e is None else e for e in t) for t in tt) ss_adj = sorted(set(raw_adj), key=key) # dupes aren't an issue but removing them produces a slight performance improvement adj = sorted(set(tuple(orders.rl(*(a if a is None else OntId(a).u for a in rl)) for rl in rls) for rls in ss_adj)) nst = orders.adj_to_nst(adj) return nst def get_apinat_blobs(): d = sgc.execute(query=q_cnap, limit=99999, output='application/json') ids = [n['id'] for n in d['nodes']] for id in ids: blob = sgd.demos_apinat_neru_7_neupop_id(neupop_id=id) # FIXME slow, TODO parallize anst = all_nst(ids, blobs) olr = auth.get_path('ontology-local-repo') og = OntGraph().parse(olr / 'ttl/generated/neurons/apinat-simple-sheet.ttl') g = OntGraph() g.namespace_manager.populate_from(og) add_partial_orders(g, anst) g.write(olr / 'ttl/generated/neurons/apinat-partial-orders.ttl') #+end_src debug, looks like there are nasty issues with duplicate nodes on the input here to rl which is not good, like rl equality test is not working (this was indeed the case) #+begin_src jupyter-python :session pys :results none # wat = anst[OntId('ilxtr:neuron-type-aacar-6').u] #issue = 3 # 'ilxtr:neuron-type-splen-2' #issue = ids.index('ilxtr:neuron-type-aacar-6') #issue = ids.index('ilxtr:neuron-type-aacar-7v') issue = ids.index('ilxtr:neuron-type-keast-11') #issue = 101 # 'ilxtr:neuron-type-pancr-2' iblob = blobs[issue] idb, *_ = apinat_deblob(iblob) oof = render_blob(idb) owie = ids[issue] # oh boy, somas are missing housing entirely in some cases #ematch(iblob, sub, 'aacar:ac-atrial-epi-term-6_lnk_1') #ematch(iblob, obj, 'aacar:ac-atrial-epi-term-6_lnk_1') # lol forgot to deblob #ematch(iblob, sub, 'aacar:ac-sn-sgt3_6_lnk_2') #ematch(iblob, obj, 'aacar:ac-sn-sgt3_6_lnk_2') ouch = apinat_to_raw_adj(iblob) souch = sorted(set(ouch)) hrm = raw_adj_to_nst(ouch) wat1 = sorted(set(tuple(orders.rl(*(a if a is None else OntId(a).curie for a in rl)) for rl in rls) for rls in ouch)) wat2 = sorted(set(tuple(orders.rl(*(a if a is None else OntId(a).curie for a in rl)) for rl in rls) for rls in souch)) sigh1 = wat1 == wat2 # utoh wat3 = sorted(set(tuple(orders.rl(*(a if a is None else OntId(a).curie for a in rl)) for rl in rls) for rls in sorted(set(ouch)))) wat4 = sorted(set(tuple(orders.rl(*(a if a is None else OntId(a).curie for a in rl)) for rl in rls) for rls in sorted(set(souch)))) sigh2 = wat3 == wat4 # ok qq = orders.adj_to_nst(wat3) # XXX no, this is what is broken # well that is concerning #+end_src ** asdf #+begin_src sparql select distinct ?s ?p where { ?s ?p ilxtr:NeuronCUT . } #+end_src #+begin_src cypher :limit 10 // MATCH path = (a)-[t]-(:Class) RETURN a //MATCH path = ()-[:apinatomy:conveyingLyph]-() RETURN path // MATCH path = ()-[:TEMPRAW:protocolInvolvesInputInstance]-() RETURN path #+end_src ** heatmaps *** TODO get the numbers along the axis, so n populations *** TODO color code by process type *** TODO costimulation by location *** neupop by region # FIXME if missing :session breaks on evil =o= #+name: py-nbr-1 #+begin_src jupyter-python :session pys :noweb yes :results none :var remove=(and "sigh") <> from collections import defaultdict def get_label(region): return id_label[region] def get_labels(regions): return [get_label(region) for region in regions] d = sgc.execute(query=q_cnap, limit=99999, output='application/json') ids = [n['id'] for n in d['nodes']] blobs = [neupop_blob(id) for id in ids] id_label = {n['id']:n['lbl'] if 'lbl' in n and n['lbl'] else n['id'] for blob in blobs for n in blob['nodes']} #+end_src #+name: py-nbr-2 #+begin_src jupyter-python :session pys _ext_all = sorted(set([obj(e) for b in blobs for e in b['edges'] if pred(e, 'apinatomy:ontologyTerms')])) ext_pop = {i:set([obj(e) for e in blob['edges'] if pred(e, 'apinatomy:ontologyTerms')]) for i, blob in zip(ids, blobs)} # TODO popuation, region, process type, terminal pop_by_reg_ads_trm = [] pop_by_reg = defaultdict(list) for i, regs in ext_pop.items(): for reg in regs: pop_by_reg[reg].append(i) def key_allc(region): count = 0 for i, id in enumerate(ids): if region in ext_pop[id]: count += 1 return count _ext_allc = sorted(_ext_all, key=key_allc) def key_pop(pop): return -len(ext_pop[pop]) ids_ord = sorted(ids, key=key_pop) def key_all(region): first = None count = 0 regs = [] iths = [] for i, id in enumerate(ids_ord): if region in ext_pop[id]: regs.append(region) iths.append(i) #count += 1 # wow =+ 1 no error wat #if first is None: #first = i return iths[0], *[-i for i in iths[1:]] ext_all = sorted(_ext_all, key=key_all) n_region = len(ext_all) n_pop = len(ext_pop) header = [['neupop', *ext_all]] # TODO -> label xl = get_labels(header[0][1:]) rows = header + [[id, *[region in ext_pop[id] for region in ext_all]] for id in ids_ord] def jac(a, b): anb, aub = zip(*[(ar and br, ar or br) for ar, br in zip(a, b)]) sanb, saub = sum(anb) , sum(aub) if not sanb and not saub: return sanb # 0 elif not sanb: return saub elif not saub: return sanb else: return sanb / saub def sumjac(rows, norm=False): # actually want distance from .5 ? mat = jac_mat(rows, switch=True) #pprint(mat) return [(sum(r[:-1]) * sum(rows[r[-1] + 1][1:]) if norm else 1, r[-1]) for i, r in enumerate(mat)] def sumjac_norm(rows): return sumjac(rows, norm=True) def jac_mat(rows, switch=False, reverse=False): asdf = [] for i, (_, *rowa) in enumerate(rows[1:]): jacr = [] for j, (_, *rowb) in enumerate(rows[1:]): jci = jac(rowa, rowb) if switch: jacr.append(jci) else: jacr.append((jci, j)) if switch: jacr.append(i) asdf.append(jacr) else: minimized = [i for j, i in sorted(jacr)][1:] # 1: to skip self minimized.append(i) asdf.append(minimized) return asdf def jmc(rows): return jac_mat(rows, switch=True) def jmcr(rows): # XXX broken return jac_mat(rows, switch=True, reverse=True) def jac_sigh(rows): sigh = jmc(rows) return [(np.std(s[:-1]), np.mean(s[:-1]), s[-1]) for s in sigh] def jac_sigh(rows): sigh = jmc(rows) #return [(np.std(s[:-1]), np.mean(s[:-1]), s[-1]) for s in sigh] return [(*[((x - .5) ** 2) ** .5 for x in s[:-1]], s[-1]) for s in sigh] def resort(rows, sortf, reverse=False): asdf_ord = sorted(sortf(rows), reverse=not reverse) # don't think too hard about it ind_rank = {j:i for i, (*_, j) in enumerate(asdf_ord)} def srt(row): ind = rows.index(row) if ind == 0: return 0 else: return ind_rank[ind - 1] return sorted(rows, key=srt) def sumthm(rows): return [[-sum(row[1:]), i] for i, row in enumerate(rows[1:])] def sumth(rows): return [[sum(row[1:]), i] for i, row in enumerate(rows[1:])] def blank(rows): return [[*row[1:], i] for i, row in enumerate(rows[1:])] def sumoth(rows): crank = [sum(col) for col in list(zip(*rows[1:]))[1:]] return [[* #[crank[j] if c and crank[j] == max([crank[x] for x, v in enumerate(row[1:]) if v]) else 0 [crank[j] if c else 0 for j, c in enumerate(row[1:])], i] for i, row in enumerate(rows[1:])] def sumothm(rows): crank = [sum(col) for col in list(zip(*rows[1:]))[1:]] return [[* #[crank[j] if c and crank[j] == max([crank[x] for x, v in enumerate(row[1:]) if v]) else 0 [-crank[j] if c else 0 for j, c in enumerate(row[1:])], i] for i, row in enumerate(rows[1:])] def maxp(rows): crank = [sum(col) for col in list(zip(*rows[1:]))[1:]] return [[ sorted([crank[j] if c else 0 for j, c in enumerate(row[1:])])[0], ,*[-_ for _ in sorted([crank[j] if c else 0 for j, c in enumerate(row[1:])])[1:]] , i] for i, row in enumerate(rows[1:])] def jacb(rows): a = [row[1:] for row in rows[1:]] aT = list(zip(*a)) # FIXME symmetry rd = [[jac(r1, r2) for r2 in a] for r1 in a] cd = [[jac(c1, c2) for c2 in aT] for c1 in aT] #pprint(rd) #pprint(cd) # output is a 4d matrix, from rc -> to rc dist = np.zeros((len(rd), len(cd), len(rd), len(cd))) for i, row_dists in enumerate(rd): for k, row_dist in enumerate(row_dists): for j, col_dists in enumerate(cd): for l, col_dist in enumerate(col_dists): dist[i, j, k, l] = (row_dist ** 2 + col_dist ** 2) ** .5 #pprint(dist) return dist rows = resort(rows, sumth) rows = list(zip(*resort(list(zip(*rows)), blank, reverse=True))) rows = resort(rows, jmc) if False: import seaborn seaborn.set(rc={'figure.figsize':(50, 50)}) #seaborn.set(rc={'figure.figsize':(5, 5)}) axes = seaborn.heatmap( [r[1:] for r in rows[1:]], xticklabels=xl, yticklabels=[r[0] for r in rows[1:]], cbar=False, square=True, ) # axes.get_figure().savefig('heatmap-pop-reg-test.svg') #+end_src #+begin_src jupyter-python :session pys import csv csv_path = 'heatmap-pop-reg.csv' with open(csv_path, 'wt') as f: csv.writer(f).writerows(rows) #+end_src **** generate npo representation of apinatomy population location phenotypes undifferentiated NPO representation that matches the heatmap above run the blocks in the section above first #+begin_src jupyter-python :session pys #len(blobs) #pprint(id_label) #pprint(blobs[0]) sorted([[a, *sorted(b)] for a, b in ext_pop.items()]) #+end_src #+name: py-nbr-3 #+begin_src jupyter-python :session pys from neurondm import Neuron, Phenotype, EntailedPhenotype, Config from pyontutils.namespaces import ilxtr, owl, skos, rdfs config = Config('apinatomy-locations') neurons = [Neuron(Phenotype(id), *(EntailedPhenotype(loc, ilxtr.hasLocationPhenotype) for loc in sorted(locs)), id_=id) for id, locs in ext_pop.items()] config.write() to_mod = [(s, skos.altLabel, o) for s, p, o in config._written_graph if p == rdfs.label] to_remove = [t for t in config._written_graph if t[1] in (owl.equivalentClass, ilxtr.genLabel, ilxtr.localLabel, ilxtr.simpleLabel, ilxtr.simpleLocalLabel, rdfs.label, skos.prefLabel)] [config._written_graph.remove(t) for t in to_remove] [config._written_graph.add(t) for t in to_mod] config._written_graph.write() config.write_python() #+end_src #+begin_src jupyter-python :noweb yes :session pys :var remove=(and "sigh") <> <> <> #+end_src *** region by region * SciGraph cypher queries These can be tested against the execute endpoint as well (if the SciGraph server is running the patch to align the behavior). ** sigh #+begin_src cypher #+end_src #+begin_src cypher :limit 999 // :results drawer // :var hello="there" match (o:Ontology{iri: "http://uri.interlex.org/sparc/ontologies/ilx_0793177"}) <-[:isDefinedBy]-(t) // this shit is fucked ... those labels should be in sparc community terms because it is being loaded ... nah just the known FMA -> ILX change and use case issue return t // (o:Ontology{iri: "https://cassava.ucsd.edu/sparc/ontologies/published/N:organization:618e8dd9-f8d2-4dc4-9abb-c6aaab2e78a0"}) #+end_src #+RESULTS: | id | label | |----+-------| ** neru *** neru-7 Switch over to =apinat:inheritedOntologyTerms=. #+name: cypher-neru-7-helper #+begin_src cypher :noweb yes :results drawer :limit 99999999 :exports none <> #+end_src #+header: :limit 999999 :file ./images/neru-7-keast-6.graphml :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-7 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK , (neugrp) -[:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, link, lyph, a, c, d OPTIONAL MATCH layer_ext = (lyph) <-[d*1]-(layer)-[:apinatomy:cloneOf*0..1]->()-[:apinatomy:inheritedOntologyTerms]->() WITH neugrp, link, lyph, a, c, d, layer_ext OPTIONAL MATCH more = (lyph) -[:apinatomy:layerIn|apinatomy:endsIn|apinatomy:fasciculatesIn|apinatomy:internalIn|apinatomy:cloneOf*1..]->() -[:apinatomy:ontologyTerms|apinatomy:inheritedOntologyTerms]->() WITH neugrp, link, lyph, a, c, d, layer_ext, more // there is a difference here because the previous match does not require lyphs to have external ids MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) , p2 = (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() , (cl) -[x:apinatomy:inheritedOntologyTerms*0..1]->() // use apinatomy:next to extract ordering information , (link) -[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) // publications WITH neugrp, a, c, d, e, f, g,h,i, p2, x, layer_ext, more OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Reference"}) // cannot be curied, dynamic endpoints will not expand it RETURN a, null as b, c, d, e, f, g,h,i, path, p2, x, layer_ext, more UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->() -[d:apinatomy:ontologyTerms*0..1]->(region) , p2 = (lyph) -[:apinatomy:conveys]->(soma_link) -[:apinatomy:source|apinatomy:target]->(soma_node) -[:apinatomy:sourceOf]->(chain_link) , (chain_link) -[:apinatomy:levelIn]->(chain) , (soma_node) -[:apinatomy:rootOf]->(chain) WITH lyph, a, b, c, d, p2 OPTIONAL MATCH more = (lyph) -[:apinatomy:layerIn|apinatomy:endsIn|apinatomy:fasciculatesIn|apinatomy:internalIn|apinatomy:cloneOf*1..]->() -[:apinatomy:ontologyTerms|apinatomy:inheritedOntologyTerms]->() RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path, p2, null as x, null as layer_ext, more #+end_src *** neru-6 The only difference between 5 and 6 is that 6 also traverses apinat:nextChainStartLevels # #+header: :var neupop_id="ilxtr:neuron-type-aacar-12" #+name: cypher-neru-6-helper #+begin_src cypher :noweb yes :results drawer :limit 99999999 :exports none <> #+end_src #+header: :limit 999999 :file ./images/neru-6-aacar-12.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-aacar-12" #+name: cypher-neru-6 #+begin_src cypher :noweb yes <> -[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() <> #+end_src #+RESULTS: cypher-neru-6 [[file:./images/neru-6-aacar-12.svg]] *** neru-5 **** query # #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-5-helper #+begin_src cypher :noweb yes :results drawer :limit 99999999 :exports none <> #+end_src # #+header: :results drawer :limit 99999999 :exports none #+header: :limit 999999 :file ./images/neru-5-keast-6.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-5 #+begin_src cypher :noweb yes <> -[f:apinatomy:next*0..]->() <> #+end_src #+RESULTS: cypher-neru-5 [[file:./images/neru-5-keast-6.svg]] #+name: cypher-neru-5/6-common-1 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK , (neugrp) -[:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, link, lyph, a, c, d OPTIONAL MATCH layer_ext = (lyph) <-[d*1]-(layer)-[:apinatomy:cloneOf*0..1]->()-[:apinatomy:inheritedExternal]->() WITH neugrp, link, lyph, a, c, d, layer_ext OPTIONAL MATCH more = (lyph) -[:apinatomy:layerIn|apinatomy:endsIn|apinatomy:fasciculatesIn|apinatomy:internalIn|apinatomy:cloneOf*1..]->() -[:apinatomy:ontologyTerms|apinatomy:inheritedExternal]->() WITH neugrp, link, lyph, a, c, d, layer_ext, more // there is a difference here because the previous match does not require lyphs to have external ids MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) , p2 = (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() , (cl) -[x:apinatomy:inheritedExternal*0..1]->() // use apinatomy:next to extract ordering information , (link) #+end_src #+name: cypher-neru-5/6-common-2 #+begin_src cypher -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) // publications WITH neugrp, a, c, d, e, f, g,h,i, p2, x, layer_ext, more OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Reference"}) // cannot be curied, dynamic endpoints will not expand it RETURN a, null as b, c, d, e, f, g,h,i, path, p2, x, layer_ext, more UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->() -[d:apinatomy:ontologyTerms*0..1]->(region) , p2 = (lyph) -[:apinatomy:conveys]->(soma_link) -[:apinatomy:source|apinatomy:target]->(soma_node) -[:apinatomy:sourceOf]->(chain_link) , (chain_link) -[:apinatomy:levelIn]->(chain) , (soma_node) -[:apinatomy:rootOf]->(chain) WITH lyph, a, b, c, d, p2 OPTIONAL MATCH more = (lyph) -[:apinatomy:layerIn|apinatomy:endsIn|apinatomy:fasciculatesIn|apinatomy:internalIn|apinatomy:cloneOf*1..]->() -[:apinatomy:ontologyTerms|apinatomy:inheritedExternal]->() RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path, p2, null as x, null as layer_ext, more #+end_src *** neru-4 :PROPERTIES: :CUSTOM_ID: neru-4 :END: #+name: cypher-neru-4-helper #+begin_src cypher :noweb yes :results drawer :limit 99999999 :exports none <> #+end_src # #+header: :results drawer :limit 99999999 :exports none #+header: :limit 999999 :file ./images/neru-4.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-5" #+name: cypher-neru-4 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK , (neugrp) -[:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, link, lyph, a, c, d OPTIONAL MATCH layer_ext = (lyph) <-[d*1]-(layer)-[:apinatomy:cloneOf]->()-[:apinatomy:inheritedOntologyTerms]->() WITH neugrp, link, lyph, a, c, d, layer_ext // there is a difference here because the previous match does not require lyphs to have external ids MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) , p2 = (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() , (cl) -[x:apinatomy:inheritedOntologyTerms*0..1]->() // use apinatomy:next to extract ordering information , (link) -[f:apinatomy:next*0..]->() -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) // publications WITH neugrp, a, c, d, e, f, g,h,i, p2, x, layer_ext OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Publication"}) // cannot be curied, dynamic endpoints will not expand it RETURN a, null as b, c, d, e, f, g,h,i, path, p2, x, layer_ext UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->() -[d:apinatomy:ontologyTerms*0..1]->(region) , p2 = (lyph) -[:apinatomy:conveys]->(soma_link) -[:apinatomy:source|apinatomy:target]->(soma_node) -[:apinatomy:sourceOf]->(chain_link) , (chain_link) -[:apinatomy:levelIn]->(chain) , (soma_node) -[:apinatomy:rootOf]->(chain) RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path, p2, null as x, null as layer_ext #+end_src [[file:./images/neru-4.svg]] *** neru-3 #+name: cypher-neru-3-helper #+begin_src cypher :noweb yes :results drawer :limit 99999999 :exports none <> #+end_src # #+header: :results table :limit 1 #+header: :limit 999999 :file ./images/neru-3.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-5" #+name: cypher-neru-3 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK // publications WITH neugrp, a OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Publication"}) // cannot be curied, dynamic endpoints will not expand it WITH neugrp, a, path MATCH (neugrp) -[b:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, link, lyph, a, b, c, d, path // MATCH vs , not all things that match as lyphs have externals MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) // use apinatomy:next to extract ordering information WITH neugrp, link, a, b, c, d, e, path MATCH p2 = (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() WITH neugrp, link, a, b, c, d, e, path, p2, cl MATCH (cl) -[x:apinatomy:inheritedOntologyTerms*0..1]->() WITH neugrp, link, a, b, c, d, e, path, p2, x MATCH (link) -[f:apinatomy:next*0..]->() //-[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() // FIXME these should be collapsing into a single relationship -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) RETURN a, b, c, d, e, f, g,h,i, path, p2, x UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->() -[d:apinatomy:ontologyTerms*0..1]->(region) // this variant shows the dead end lyphs that correspond to the fasciculatesIn links above //-[c:apinatomy:internalIn*0..1]->() //-[d:apinatomy:ontologyTerms*0..1]->(region) RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path, null as p2, null as x #+end_src [[file:./images/neru-3.svg]] *** neru-2 # #+header: :results drawer :limit 1 #+header: :limit 999999 :file ./images/neru-2.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-2 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK // publications WITH neugrp, a OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Publication"}) // cannot be curied, dynamic endpoints will not expand it WITH neugrp, a, path MATCH (neugrp) -[b:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, link, lyph, a, b, c, d, path MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) // use apinatomy:next to extract ordering information WITH neugrp, link, a, b, c, d, e, path MATCH (link) -[f:apinatomy:next*0..]->() //-[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() // FIXME these should be collapsing into a single relationship -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) RETURN a, b, c, d, e, f, g,h,i, path UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->(e) // e is a hack to get columns to match -[d:apinatomy:ontologyTerms*0..1]->(region) // this variant shows the dead end lyphs that correspond to the fasciculatesIn links above //-[c:apinatomy:internalIn*0..1]->(e) //-[d:apinatomy:ontologyTerms*0..1]->(region) RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path #+end_src #+RESULTS: cypher-neru-2 [[file:./images/neru-2.svg]] # #+header: :limit 999 :results drawer # #+header: :limit 9999 :results table #+header: :limit 999999 :file ./images/neru-debug.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-debug #+begin_src cypher MATCH path = (neupop:Class{iri: $neupop_id}) -[:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) -[:apinatomy:links]->() -[:apinatomy:next*0..]->() // -[:apinatomy:nextChainStartLevels*0..]-() //-[:apinatomy:prevChainEndLevels*0..]-() -[:apinatomy:levelIn*0..]->() RETURN path #+end_src #+RESULTS: cypher-neru-debug [[file:./images/neru-debug.svg]] *** neru-1 # #+header: :results drawer :limit 1 #+header: :limit 999999 :file ./images/neru-1.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-6" #+name: cypher-neru-1 #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK // publications WITH neugrp, a OPTIONAL MATCH path = (neugrp) -[:apinatomy:references]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Publication"}) // cannot be curied, dynamic endpoints will not expand it WITH neugrp, a, path MATCH (neugrp) -[b:apinatomy:links]->(link) -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH lyph, a, b, c, d, path MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) RETURN a, b, c, d, e, path UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) -[c:apinatomy:internalIn]->(e) // e is a hack to get columns to match -[d:apinatomy:ontologyTerms*0..1]->(region) // this variant shows the dead end lyphs that correspond to the fasciculatesIn links above //-[c:apinatomy:internalIn*0..1]->(e) //-[d:apinatomy:ontologyTerms*0..1]->(region) return a, b, c, d, null AS e, null AS path #+end_src #+RESULTS: cypher-neru-1 [[file:./images/neru-1.svg]] *** all populations #+name: cy-neru-all-pop #+header: :limit 9999 #+begin_src cypher OPTIONAL MATCH (start:Ontology) <-[:isDefinedBy]-(graph:NamedIndividual) -[:type]->({iri: "https://apinatomy.org/uris/elements/Graph"}) , (start) <-[:isDefinedBy]-(external:Class) -[:subClassOf*]->(:Class {iri: "http://uri.interlex.org/tgbugs/uris/readable/NeuronEBM"}) return external #+end_src *** neru populations #+name: desc-cypher-apinat-model-populations List all neuron populations that appear in some ApiNATOMY model. #+header: :limit 99999 #+name: cypher-apinat-model-populations #+begin_src cypher MATCH (start:Ontology) <-[:isDefinedBy]-(external:Class) -[:subClassOf*]->(:Class {iri: "http://uri.interlex.org/tgbugs/uris/readable/NeuronEBM"}) // FIXME , (start:Ontology) <-[:apinat:hasGraph]-(graph:Class {iri: ""}) RETURN external #+end_src *** neru model populations Given an ApiNATOMY model id return the identifiers for the neuron populations that are present in the model. #+header: :var model_id="https://apinatomy.org/uris/models/keast-bladder" :limit 99 #+begin_src cypher MATCH (start:Ontology {iri: $model_id}) <-[:isDefinedBy]-(external:Class) -[:subClassOf*]->(:Class {iri: "http://uri.interlex.org/tgbugs/uris/readable/NeuronEBM"}) // FIXME RETURN external #+end_src *** neru model populations and references #+name: desc-cypher-apinat-model-pops-and-refs Given an ApiNATOMY model id return the identifiers for the neuron populations that are present in the model and the identifiers for references that provide supporting evidence. Publications and populations can be distingished by checking whether their meta type field is NamedIndividual or Class. # #+header: :results drawer #+header: :var model_id="https://apinatomy.org/uris/models/keast-bladder" :limit 99 :results drawer #+name: cypher-apinat-model-pops-and-refs #+begin_src cypher MATCH (start:Ontology {iri: $model_id}) <-[:isDefinedBy]-(external:Class) -[:subClassOf*]->(:Class {iri: "http://uri.interlex.org/tgbugs/uris/readable/NeuronEBM"}) // FIXME , (external) -[e:type]->() RETURN e UNION OPTIONAL MATCH (start:Ontology {iri: $model_id}) <-[:isDefinedBy]-(graph:NamedIndividual) -[:type]->({iri: "https://apinatomy.org/uris/elements/Graph"}) // elements don't have a superclass right now , (graph) -[:apinatomy:references]->(pub) -[e:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Reference"}) RETURN e #+end_src *** TODO neru regions projected to #+begin_src cypher #+end_src *** TODO neru regions dendrited to *** TODO neru regions with processes from region contains some process part of some neuron population #+begin_src cypher MATCH (region) -[:apinatomy:annotates]->(lyph) <-[:apinatomy:lyphs]- (neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) RETURN region #+end_src *** neru projects to *** neru neurites to # FIXME this seems not quite right? # TODO dot ignore directionality in layout for certain edges e.g. apinat:topology # #+header: :results drawer :limit 1 #+header: :limit 999999 :file ./images/neru-projects.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-11" #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) -[:apinatomy:lyphs]->(end_lyph) -[t:apinatomy:topology]->(top) WHERE top.iri IN ["https://apinatomy.org/uris/readable/BAG", "https://apinatomy.org/uris/readable/BAG2"] WITH neugrp, end_lyph, t MATCH (type) // FIXME we need more information in the models <-[x:apinatomy:inheritedOntologyTerms*0..1]-(end_lyph) -[a:apinatomy:conveys]->(link) -[b:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[c:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph WITH neugrp, lyph, a,b,c,t,x MATCH (lyph) -[e:apinatomy:ontologyTerms]->(region) RETURN e, a,b,c,t,x #+end_src *** neru population projects to *** neru populations projecting to Given an anatomical region return a list of neuron types that project to that region. # FIXME TODO need to also be able to query layers i.e. rexed lamina vii #+header: :limit 999999 :file ./images/neru-axons-bag.svg :results file :exports both #+header: :var region_id="UBERON:0001989" :note vagus nerve #+header: :var type_id="SAO:280355188" :note regional part of axon #+name: cypher-neru-axons-bag #+begin_src cypher :noweb yes <> #+end_src *** neru populations with axons in Given an anatomical region return a list of neuron types with axons that are located in that region. # TODO compare with an NPO based query #+header: :limit 999999 :file ./images/neru-axons.svg :results file :exports both #+header: :var region_id="UBERON:0001759" :note vagus nerve #+header: :var type_id="SAO:280355188" :note regional part of axon #+name: cypher-neru-axons #+begin_src cypher :noweb yes <> RETURN e, neupop, neugrp #+end_src #+RESULTS: cypher-neru-axons [[file:./images/neru-axons.svg]] *** neru populations dendriting to Given an anatomical region return a list of neuron types that have dendrite terminals in that region. #+header: :limit 999999 :file ./images/neru-dendrites-bag.svg :results file :exports both #+header: :var region_id="UBERON:0001989" :note vagus nerve #+header: :var type_id="SAO:420754792" :note regional part of dendrite #+name: cypher-neru-dendrites-bag #+begin_src cypher :noweb yes <> #+end_src #+RESULTS: cypher-neru-dendrites-bag [[file:./images/neru-dendrites-bag.svg]] *** neru populations with dendrites in Given an anatomical region return a list of neuron types with dendrites that are located in that region. # TODO compare with an NPO based query #+header: :limit 999999 :file ./images/neru-dendrites.svg :results file :exports both #+header: :var region_id="UBERON:0001759" :note vagus nerve #+header: :var type_id="SAO:420754792" :note regional part of dendrite #+name: cypher-neru-dendrites #+begin_src cypher :noweb yes <> RETURN e, neupop, neugrp #+end_src # #+call: does not work here because we can't override a bunch of the other settings #+RESULTS: cypher-neru-dendrites [[file:./images/neru-dendrites.svg]] *** TODO neru populations with neurites in *** neru populations with processes in :PROPERTIES: :CUSTOM_ID: neru-populations-with-processes-in :END: Given an anatomical region return a list of neuron types with processes that are located in that region. # NOTE have to include :Class otherwise neupop-[annoates*0..1]->neugrp # will match neugrp which we do not want # FIXME still not quite right because now we neupop is no longer optional #+name: cypher-neru-processes-base #+begin_src cypher :eval never MATCH (neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) -[:apinatomy:links]->(link) -[:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) -[:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:ontologyTerms*0..1]->(region:Class{iri: $region_id}) WITH neugrp OPTIONAL MATCH (neupop:Class) -[e:apinatomy:annotates*0..1]->(neugrp) #+end_src #+name: cypher-neru-processes-somas #+begin_src cypher :eval never // somas MATCH (neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) -[:apinatomy:lyphs]->(lyph) -[:apinatomy:internalIn]->() -[:apinatomy:ontologyTerms*0..1]->(region:Class{iri: $region_id}) WITH neugrp OPTIONAL MATCH (neupop:Class) -[e:apinatomy:annotates*0..1]->(neugrp) #+end_src TODO Need to expand =region_id= using the Uberon partonomy to answer more generic queries. # #+header: :var region_id="UBERON:0018683" :note splanchnic nerve # #+header: :var region_id="UBERON:0035769" :note mesenteric ganglion # #+header: :results drawer :limit 10 # #+header: :results table :limit 10 #+header: :limit 999999 :file ./images/neru-processes.svg :results file :exports both #+header: :var region_id="UBERON:0001759" :note vagus nerve #+name: cypher-neru-processes #+begin_src cypher :noweb yes // dendrites and axons <> RETURN e, neupop, neugrp UNION <> RETURN e, neupop, neugrp #+end_src #+RESULTS: cypher-neru-processes [[file:./images/neru-processes.svg]] #+call: cypher-neru-processes(region_id="UBERON:0005453") :results table #+call: cypher-neru-processes(region_id="UBERON:0006490") :results table #+name: cypher-neru-processes-pop-only #+begin_src cypher :noweb yes <> RETURN neupop UNION <> RETURN neupop #+end_src #+call: cypher-neru-processes-pop-only(region_id="UBERON:0005453") :results table #+call: cypher-neru-processes-pop-only(region_id="UBERON:0006490") :results table Helper blocks for more specialized queries. Filter by process =type_id=, where =type_id= could be the ontology identifier for axon or dendrite. The =type_id= has to match the conventions used in ApiNATOMY models. #+caption: process type helper #+name: cypher-neru-process-type #+begin_src cypher :noweb yes :eval never <> WITH e, neupop, neugrp, link MATCH (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:inheritedOntologyTerms]->(:Class {iri: $type_id}) #+end_src Filter processes based on their topology. For example, this is used to select processes with bag topology that correspond to axon and dendrite terminals. #+caption: terminal type helper #+name: cypher-neru-terminal-type #+begin_src cypher :noweb yes :eval never <> WITH e, neupop, neugrp, cl MATCH (cl) -[:apinatomy:topology]-(top) WHERE top.iri IN ["https://apinatomy.org/uris/readable/BAG", "https://apinatomy.org/uris/readable/BAG2"] RETURN e, neupop, neugrp #+end_src *** TODO neru populations by phenotype *** TODO neru phenotype by population ** existing *** sparc **** organParts #+name: desc-organ-parts Get the parts list for an organ including nerves and blood vessels #+header: :var id=(or) #+name: cyres-organ-parts #+begin_src cypher // depth of 6 captures everything, 5 is too shallow, 40 is WAY too deep MATCH path = (start:Class{iri: "${id}"}) <-[:subClassOf|ilxtr:includedForSPARCUnder|fma:regional_part_of|fma:constitutional_part_of|fma:related_part_of*0..6]-(part) <-[:fma:arterial_supply_of|fma:nerve_supply_of|fma:venous_drainage_of|fma:continuous_with*0..1]-(sup) <-[:subClassOf|fma:constitutional_part_of|fma:branch|fma:tributary|fma:branch_of*0..1]-(a_bit_more) RETURN path UNION // for this query UNION seems to be MUCH faster than using WITH MATCH path = (start:Class{iri: "${id}"}) // this one does not need to be inverted ? except for the INCOMING flag <-[:fma:arterial_supply_of|fma:venous_drainage_of]-(vessel) <-[:fma:branch|fma:tributary]-(more_vessel) <-[:fma:branch|fma:tributary|fma:regional_part]-(even_more_vessel) RETURN path #+end_src # heart test query #+call: cyres-organ-parts(id="FMA:7088", limit=1) :results table **** parcellationArtifacts #+name: cyres-parcellation-artifacts #+begin_src cypher MATCH path = (artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path #+end_src **** parcellationArtifacts/{species-id} #+header: :var species-id=(or) #+name: cyres-parcellation-artifacts-species-id #+begin_src cypher MATCH path = (artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"}) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path #+end_src #+call: cyres-parcellation-artifacts-species-id(species-id="NCBITaxon:9606") **** artifactRoots/{artifact-id} #+header: :var artifact-id=(or) #+name: cyres-artifact-roots-artifact-id #+begin_src cypher MATCH path = (root) -[:ilxtr:isDefinedBy]->(a)<-[:subClassOf*0..2] -(artifact:Class{iri: "${artifact-id}"}) RETURN path #+end_src **** artifactLabels/{artifact-id} #+header: :var artifact-id=(or) #+name: cyres-artifact-labels-artifact-id #+begin_src cypher MATCH path = (label) -[:subClassOf]->(root) -[:ilxtr:isDefinedBy]->(a)<-[:subClassOf*0..2] -(artifact:Class{iri: "${artifact-id}"}) WHERE label.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path #+end_src **** rootLabels/{root-id} #+header: :var root-id=(or) #+name: cyres-root-labels-root-id #+begin_src cypher MATCH (label)-[:subClassOf]->(root:Class{iri: "${root-id}"}) , path = (label)-[relation*0..1]-(maybe) WHERE NONE (r in relation WHERE type(r) IN ["isDefinedBy", "subClassOf", "filler"]) AND NOT (label.iri =~ ".*_:.*") AND NOT (maybe.iri =~ ".*_:.*") AND label.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path #+end_src **** parcellationRoots #+name: cyres-parcellation-roots #+begin_src cypher MATCH path = (artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path UNION MATCH path = (root) -[:ilxtr:isDefinedBy]->(artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species) RETURN path #+end_src **** parcellationRoots/{species-id} #+header: :var species-id=(or) #+name: cyres-parcellation-roots-species-id #+begin_src cypher MATCH path = (artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"}) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" return path UNION MATCH path = (root) -[:ilxtr:isDefinedBy]->(artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"}) RETURN path #+end_src #+call: cyres-parcellation-roots-species-id(species-id="NCBITaxon:9606") **** parcellationRoots/{species-id}/{region-id} #+header: :var species-id=(or) #+header: :var region-id=(or) #+name: cyres-parcellation-roots-species-id-region-id #+begin_src cypher MATCH (region:Class{iri: "${region-id}"}) <-[:ilxtr:isDefinedInRegion]- (parent) -[:ilxtr:isDefinedInTaxon]-> (species:Class{iri: "${species-id}"}) WITH parent MATCH path = (artifact) -[:subClassOf*0..2]->(parent) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path UNION MATCH (region:Class{iri: "${region-id}"}) <-[:ilxtr:isDefinedInRegion]- (parent) -[:ilxtr:isDefinedInTaxon]-> (species:Class{iri: "${species-id}"}) WITH parent MATCH path = (root) -[:ilxtr:isDefinedBy]->(artifact) -[:subClassOf*0..2]->(parent) RETURN path #+end_src **** parcellationRootsFMA/{species-id}/{fma-id} #+header: :var species-id=(or) #+header: :var region-id=(or) #+name: cyres-parcellation-roots-fma-species-id-region-id #+begin_src cypher MATCH (fma:Class{iri: "${fma-id}"}) WITH "FMA:" + toString(fma.`http://purl.org/sig/ont/fma/FMAID`) AS curie MATCH (region) -[:subClassOf*]->(start:Class{iri: "http://purl.obolibrary.org/obo/UBERON_0001062"}) WHERE any(x IN region.`http://www.geneontology.org/formats/oboInOwl#hasDbXref` WHERE x =~ curie) WITH region MATCH (region) <-[:ilxtr:isDefinedInRegion]- (parent) -[:ilxtr:isDefinedInTaxon]-> (species:Class{iri: "${species-id}"}) WITH parent MATCH path = (artifact) -[:subClassOf*0..2]->(parent) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path UNION MATCH (fma:Class{iri: "${fma-id}"}) WITH "FMA:" + toString(fma.`http://purl.org/sig/ont/fma/FMAID`) AS curie MATCH (region) -[:subClassOf*]->(start:Class{iri: "http://purl.obolibrary.org/obo/UBERON_0001062"}) WHERE any(x IN region.`http://www.geneontology.org/formats/oboInOwl#hasDbXref` WHERE x =~ curie) WITH region MATCH (region) <-[:ilxtr:isDefinedInRegion]- (parent) -[:ilxtr:isDefinedInTaxon]-> (species:Class{iri: "${species-id}"}) WITH parent MATCH path = (root) -[:ilxtr:isDefinedBy]->(artifact) -[:subClassOf*0..2]->(parent) RETURN path #+end_src **** parcellationGraph #+name: cyres-parcellation-graph #+begin_src cypher MATCH path = (artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species) WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing" return path UNION MATCH path = (maybe) -[relation*0..1]-(label) -[:subClassOf]->(root) -[:ilxtr:isDefinedBy]->(artifact) -[:subClassOf*0..2]->(parent) -[:ilxtr:isDefinedInTaxon]->(species) WHERE NONE (r in relation WHERE type(r) IN ["isDefinedBy", "subClassOf", "filler"]) AND NOT (label.iri =~ ".*_:.*") AND NOT (maybe.iri =~ ".*_:.*") AND label.iri <> "http://www.w3.org/2002/07/owl#Nothing" RETURN path #+end_src **** organList # TODO generate from the canonical organ list above #+name: cyres-organ-list #+begin_src cypher MATCH (n) WHERE n.iri IN [ "http://purl.org/sig/ont/fma/fma7195", // lung "http://purl.org/sig/ont/fma/fma7088", // heart "http://purl.org/sig/ont/fma/fma7197", // liver "http://purl.org/sig/ont/fma/fma7198", // pancreas "http://purl.org/sig/ont/fma/fma7203", // kidney "http://purl.org/sig/ont/fma/fma7148", // stomach "http://purl.org/sig/ont/fma/fma7196", // spleen "http://purl.org/sig/ont/fma/fma14543", // colon "http://purl.org/sig/ont/fma/fma7201", // large intestine "http://purl.org/sig/ont/fma/fma7200", // small intestine "http://purl.org/sig/ont/fma/fma7199", // intestine "http://purl.org/sig/ont/fma/fma15900", // urinary bladder "http://purl.org/sig/ont/fma/fma45659", // lower urinary tract "http://purl.org/sig/ont/fma/fma7157", // nervous system "http://purl.org/sig/ont/fma/fma9903", // peripheral nervous system "http://purl.org/sig/ont/fma/fma9906", // sympathetic nervous system "http://purl.org/sig/ont/fma/fma7647", // spinal cord "http://purl.org/sig/ont/fma/fma50801", // brain "http://purl.org/sig/ont/fma/fma5889", // autonomic ganglion "http://purl.org/sig/ont/fma/fma19667", // urethra "http://purl.org/sig/ont/fma/fma7131", // esophagus "http://uri.interlex.org/base/ilx_0793921" // REVA root ] RETURN n #+end_src **** speciesList #+name: cyres-species-list #+begin_src cypher MATCH (n) WHERE n.iri IN [ "http://purl.obolibrary.org/obo/NCBITaxon_9378", // Suncus murinus "http://purl.obolibrary.org/obo/NCBITaxon_9606", // Homo sapiens "http://purl.obolibrary.org/obo/NCBITaxon_9685", // Felis catus "http://purl.obolibrary.org/obo/NCBITaxon_9823", // Sus scrofa "http://purl.obolibrary.org/obo/NCBITaxon_10090", // Mus musculus "http://purl.obolibrary.org/obo/NCBITaxon_10116" // Rattus norvegicus ] RETURN n #+end_src **** sparc community terms #+name: cyres-sparc-community-terms #+begin_src cypher :limit 10 MATCH (t)-[:isDefinedBy]->(graph:Ontology{iri: "http://uri.interlex.org/sparc/ontologies/community-terms"}) RETURN t #+end_src **** anatomyPhenotypes #+name: desc-anatomy-phenotypes Return phenotypes that inhere in some part of an anatomical entity. # #+header: :var id="UBERON:0001556" #+header: :var id="UBERON:0000948" #+name: cyres-anatomy-phenotypes #+begin_src cypher :limit 100 MATCH (anatomical_entity:Class{iri: $id}) <-[part_of:subClassOf|BFO:0000050|RO:0002433*0..40]-(subclass_part_ctmo) <-[inheres_in:RO:0000052|RO:0002314!]-(intersection_of_quality_and_anatomy) // inheres in (anon intersection of) <-[has_process_part:BFO:0000051]-() // has part (process) <-[:subClassOf*0..]-(phenotype) // phenotype and all subclasses WHERE // filter out partOf/hasPart cases that induce circularity ALL(e IN part_of WHERE NOT EXISTS(e.owlType) OR e.owlType = "subClassOf" OR e.owlType = "operand") RETURN phenotype #+end_src **** phenotypeAnatomy #+name: desc-phenotype-anatomy Return anatomical entities associated with a given phenotype. this is super slow and scigraph does not support value arrays for queries right now so will have to work through how to implement that # id='("HP:0010883" "HP:0033734" "HP:0033735") #+header: :var id="HP:0010883" #+name: cyres-phenotype-anatomy #+begin_src cypher :limit 100 MATCH (anatomical_entity:Class) <-[part_of:BFO:0000050|RO:0002433*0..4]- (subclass_part_ctmo) <-[inheres_in:RO:0000052|RO:0002314!]-(intersection_of_quality_and_anatomy) // inheres in (anon intersection of) <-[has_process_part:BFO:0000051]-() // has part (process) <-[:subClassOf*0..]-(phenotype:Class{iri: $id}) // phenotype and all subclasses WHERE phenotype.iri IN $id RETURN part_of #+end_src **** direct hpo count #+header: :var id="UBERON:0001062" #+name: cyres-anatomy-phenotypes-stats #+begin_src cypher :limit 100 MATCH (anatomical_entity:Class{iri: $id}) <-[part_of:subClassOf*0..40]-(subclass_part_ctmo) <-[inheres_in:RO:0000052|RO:0002314!]-(intersection_of_quality_and_anatomy) // inheres in (anon intersection of) <-[has_process_part:BFO:0000051]-(direct_phen) // has part (process) WHERE // filter out partOf/hasPart cases that induce circularity ALL(e IN part_of WHERE NOT EXISTS(e.owlType) OR e.owlType = "subClassOf" OR e.owlType = "operand") // RETURN count(distinct direct_phen) // RETURN count(distinct subclass_part_ctmo) RETURN subclass_part_ctmo #+end_src distinct direct phenotypes 3638 #+begin_example +-----------------------------+ | count(distinct direct_phen) | +-----------------------------+ | 3658 | +-----------------------------+ #+end_example #+begin_example +------------------------------------+ | count(distinct subclass_part_ctmo) | +------------------------------------+ | 1056 | +------------------------------------+ #+end_example **** hpo count XXX need cypher normal json results so we can use count #+begin_src cypher :limit 20 :var start="HP:0000001" MATCH (c)-[:subClassOf*0..]->(b:Class{iri: $start}) RETURN c #+end_src *** shortestSimple # FIXME TODO make sure this actuall works as expected, I think it will? #+header: :var start_id=(or) #+header: :var end_id=(or) #+header: :var max_depth=(or) #+header: :var relationship=(or) #+name: cyres-shortest-simple #+begin_src cypher MATCH (start:Class{iri: '${start_id}'}) WITH start MATCH (end:Class{iri: '${end_id}'}) WITH start, end MATCH path = shortestPath((start)-[:${relationship}*..${max_depth}]->(end)) RETURN path #+end_src *** neurons **** connectivity #+header: :var start_id=(or) #+name: cyres-neurons-connectivity #+begin_src cypher MATCH (blank)- [entrytype:ilxtr:hasSomaLocatedIn|ilxtr:hasAxonLocatedIn|ilxtr:hasDendriteLocatedIn|ilxtr:hasPresynapticTerminalsIn] ->(location:Class{iri: '${start_id}'}) WITH location, entrytype, blank MATCH (phenotype)<-[predicate]-(blank)<-[:equivalentClass]-(neuron) WHERE NOT (phenotype.iri =~ ".*_:.*") // RETURN phenotype, (phenotype)-[predicate]-(neuron) as e // WITH location, predicate, phenotype, neuron RETURN location, entrytype, neuron, predicate, phenotype #+end_src **** connectedRegions #+header: :var start_id=(or) #+name: cyres-neurons-connected-regions #+begin_src cypher MATCH (blank)- [entrytype:ilxtr:hasSomaLocatedIn|ilxtr:hasAxonLocatedIn|ilxtr:hasDendriteLocatedIn|ilxtr:hasPresynapticTerminalsIn] ->(location:Class{iri: '${start_id}'}) WITH entrytype, blank MATCH (phenotype)<-[:${target_predicate}]-(blank) // WHERE NOT (phenotype.iri =~ ".*_:.*") RETURN phenotype #+end_src *** apinat **** bundles/{start-id} #+header: :var start-id=(or) #+name: cyres-apinat-bundles-start-id #+begin_src cypher MATCH path1 = (start:Class{iri: "${start-id}"}) -[:apinatomy:annotates]->(start_housing) -[:apinatomy:subtypes*0..1]->() -[:apinatomy:clones*0..1]->(layer_or_end) -[:apinatomy:layers*0..1]->() -[:apinatomy:bundles]->(linkStart) -[:apinatomy:prevChainEndLevels|apinatomy:prev|apinatomy:source*1..]->(link) -[:apinatomy:targetOf|apinatomy:sourceOf]->(linkSoma) // axon or dendrite root -[:apinatomy:conveyingLyph]->() -[:apinatomy:supertype*0..1]->(soma:NamedIndividual) -[:apinatomy:ontologyTerms]->(c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) WITH path1, link OPTIONAL MATCH path2 = (link) -[:apinatomy:fasciculatesIn|apinatomy:endsIn]->(layer_or_end) -[:apinatomy:layerIn*0..1]->(end) -[:apinatomy:ontologyTerms]->(external) RETURN path1, path2 #+end_src **** old-bundles/{start-id} #+header: :var start-id=(or) #+name: cyres-apinat-old-bundles-start-id #+begin_src cypher MATCH path1 = (start:Class{iri: '${start-id}'}) -[:apinatomy:annotates]->(start_housing) -[:apinatomy:bundlesChains]->(chain) -[:apinatomy:root]->(root) -[:apinatomy:internalIn]->(layer_or_end) # this hits a cycle back to start_housing -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(layer_or_end_external) WITH path1, root, layer_or_end AS layer OPTIONAL MATCH path2 = (layer) -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external) WITH path1, path2, root MATCH path3 = (root) // in the layer case this hits an additional lyph <-[:apinatomy:target|apinatomy:source]-(link) <-[:apinatomy:conveys]-(soma) <-[:apinatomy:annotates]-(soma_NLX) RETURN path1, path2, path3 #+end_src **** somas #+name: cyres-apinat-somas #+begin_src cypher MATCH (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) RETURN soma #+end_src #+call: cyres-apinat-somas() :limit 9999 **** housing-lyphs #+name: cyres-apinat-housing-lyphs #+begin_src cypher MATCH path = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(somaLink) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(root) // axon or dendrite root -[:apinatomy:controlNodes|apinatomy:rootOf*1..2]->(chain) // axon or dendrite tree -[:apinatomy:housingLyphs]->(housing) // list of lyphs housing the trees -[:apinatomy:ontologyTerms*0..1]->(external) // external ids for the housing lyphs WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL RETURN path #+end_src **** housing-lyphs/{start-id} #+header: :var start-id=(or) #+name: cyres-apinat-housing-lyphs-start-id #+begin_src cypher MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(somaLink) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(root) // axon or dendrite root -[:apinatomy:internalIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(layer_or_end_external:Class{iri: '${start-id}'}) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, root MATCH path2 = (root) -[:apinatomy:controlNodes|apinatomy:rootOf*1..2]->(chain) // axon or dendrite tree -[:apinatomy:housingLyphs]->(housing) // list of lyphs housing the trees -[:apinatomy:ontologyTerms*0..1]->(external) // external ids for the housing lyphs RETURN path1, path2 UNION MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(somaLink) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(root) // axon or dendrite root -[:apinatomy:internalIn]->(layer) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external:Class{iri: '${start-id}'}) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, root MATCH path2 = (root) -[:apinatomy:rootOf]->(chain) // axon or dendrite tree -[:apinatomy:housingLyphs]->(housing) // list of lyphs housing the trees -[:apinatomy:ontologyTerms*0..1]->(external) // external ids for the housing lyphs RETURN path1, path2 #+end_src **** soma-processes # #+header: :results table :limit 1 #+header: :file ./images/soma-processes.svg :results file :limit 99999 #+name: cyres-apinat-soma-processes #+begin_src cypher MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(linkSoma) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(nodeRoot) // axon or dendrite root -[:apinatomy:sourceOf|apinatomy:nextChainStartLevels|apinatomy:next*1..]->(link) // sourceOf is first and only once -[:apinatomy:fasciculatesIn|apinatomy:endsIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(external) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, nodeRoot, layer_or_end AS layer OPTIONAL MATCH path2 = (layer) // if we were in a layer, get the containing lyph as well -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external) WITH path1, path2, nodeRoot MATCH path3 = (nodeRoot) // extract chain for axon vs dendrite -[:apinatomy:rootOf]->(chain) RETURN path1, path2, path3 #+end_src #+RESULTS: cyres-apinat-soma-processes [[file:./images/soma-processes.svg]] A sparql version of the query (work in progress). #+name: sparql-soma-processes #+begin_src sparql :var limit="99" SELECT DISTINCT ?c ?soma ?linkSoma ?nodeRoot ?link ?layer_or_end ?cloned ?supertype ?external_st ?external_loe ?external_end_housing WHERE { VALUES ?c { NLX:154731 } ?c rdf:type owl:Class . ?c apinatomy:annotates ?soma . ?soma rdf:type owl:NamedIndividual . ?soma apinatomy:conveys ?linkSoma . ?linkSoma apinatomy:target | apinatomy:source ?nodeRoot . ?nodeRoot apinatomy:rootOf ?chain . ?nodeRoot apinatomy:sourceOf | apinatomy:nextChainStartLevels | apinatomy:next+ ?link . ?link apinatomy:fasciculatesIn | apinatomy:endsIn ?layer_or_end . optional { ?layer_or_end apinatomy:cloneOf* ?cloned . } # optional optional { ?cloned apinatomy:supertype* ?supertype . } # optional ?supertype apinatomy:ontologyTerms ?external_st . ?layer_or_end apinatomy:ontologyTerms ?external_loe . optional { ?layer_or_end apinatomy:layerIn ?end_housing . } # optional optional { ?end_housing apinatomy:ontologyTerms ?external_end_housing . } # optional } limit ?limit #+end_src **** soma-processes/{start-id} #+header: :file ./images/soma-processes-id.svg :results file :limit 99999 #+header: :var start-id=(or) #+name: cyres-apinat-soma-processes-start-id #+begin_src cypher MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(linkSoma) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(nodeRoot) // axon or dendrite root -[:apinatomy:internalIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:layerIn*0..1]->(layerSoma) // don't need to see both layer and housing for soma -[:apinatomy:ontologyTerms]->(externalEndSoma:Class{iri: '${start-id}'}) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, nodeRoot MATCH path3 = (chain) <-[:apinatomy:rootOf]-(nodeRoot) -[:apinatomy:sourceOf|apinatomy:nextChainStartLevels|apinatomy:next*1..]->(link) -[:apinatomy:fasciculatesIn|apinatomy:endsIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(external) WITH path1, path3, nodeRoot, layer_or_end AS layer OPTIONAL MATCH path2 = (layer) // if we were in a layer, get the containing lyph as well -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external) RETURN path1, path2, path3 #+end_src #+call: cyres-apinat-soma-processes-start-id(start-id="UBERON:0006448") **** weird-soma-processes/{process-id} #+header: :var process-id=(or) #+name: cyres-apinat-weird-soma-processes-process-id #+begin_src cypher MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(linkSoma) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(nodeRoot) // axon or dendrite root -[:apinatomy:sourceOf|apinatomy:nextChainStartLevels|apinatomy:next*1..]->(link) // sourceOf is first and only once -[:apinatomy:fasciculatesIn|apinatomy:endsIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(external:Class{iri: '${process-id}'}) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, nodeRoot, layer_or_end AS layer OPTIONAL MATCH path2 = (layer) // if we were in a layer, get the containing lyph as well -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external) WITH path1, path2, nodeRoot MATCH path3 = (nodeRoot) // extract chain for axon vs dendrite -[:apinatomy:rootOf]->(chain) RETURN path1, path2, path3 UNION MATCH path1 = (c:Class{iri: "http://uri.neuinfo.org/nif/nifstd/nlx_154731"}) -[:apinatomy:annotates]->(soma:NamedIndividual) // soma lyph -[:apinatomy:conveys]->(linkSoma) // link connecting soma to axon and dendrite -[:apinatomy:target|apinatomy:source]->(nodeRoot) // axon or dendrite root -[:apinatomy:sourceOf|apinatomy:nextChainStartLevels|apinatomy:next*1..]->(link) // sourceOf is first and only once -[:apinatomy:fasciculatesIn|apinatomy:endsIn]->(layer_or_end) -[:apinatomy:cloneOf*0..1]->() -[:apinatomy:supertype*0..1]->() -[:apinatomy:ontologyTerms]->(external) WHERE soma.`https://apinatomy.org/uris/readable/generated` IS NULL WITH path1, nodeRoot, layer_or_end AS layer MATCH path2 = (layer) // if we were in a layer, get the containing lyph as well -[:apinatomy:layerIn]->(end_housing) -[:apinatomy:ontologyTerms]->(end_housing_external:Class{iri: '${process-id}'}) WITH path1, path2, nodeRoot MATCH path3 = (nodeRoot) // extract chain for axon vs dendrite -[:apinatomy:rootOf]->(chain) RETURN path1, path2, path3 #+end_src ** yaml file Example template. #+begin_src yaml cypherResources: - path: operations: &name-ops - summary: <> parameters: - name: some-id description: does something paramType: query: &name | <> #+end_src #+name: cypher-resources #+begin_src yaml :noweb yes :tangle ../resources/scigraph/cypher-resources.yaml cypherResources: - path: /dynamic/prod/sparc/phenotypeAnatomy/{id} operations: &phenotypeAnatomy-ops - summary: <> parameters: - name: id description: HPO id of the phenotype to search from paramType: path query: &phenotypeAnatomy | <> - path: /dynamic/test/sparc/phenotypeAnatomy/{id} operations: *phenotypeAnatomy-ops query: *phenotypeAnatomy - path: /dynamic/prod/sparc/anatomyPhenotypes/{id} operations: &anatomyPhenotypes-ops - summary: <> parameters: - name: id description: uberon id of the anatomical entity to search from paramType: path query: &anatomyPhenotypes | <> - path: /dynamic/test/sparc/anatomyPhenotypes/{id} operations: *anatomyPhenotypes-ops query: *anatomyPhenotypes - path: /dynamic/prod/sparc/organParts/{id} operations: &organParts-ops - summary: <> parameters: - name: id description: ontology id of the organ paramType: path query: &organParts | <> - path: /dynamic/test/sparc/organParts/{id} operations: *organParts-ops query: *organParts - path: /dynamic/prod/sparc/parcellationArtifacts operations: - summary: Get the graph of all parcellation artifacts for all species query: | <> - path: /dynamic/prod/sparc/parcellationArtifacts/{species-id} operations: - summary: Get the graph of all parcellation artifacts for a single species parameters: - name: species-id description: ontology id of the species paramType: path query: | <> - path: /dynamic/prod/sparc/artifactRoots/{artifact-id} operations: - summary: Get the graph of all parcellation label roots for a single artifact WARNING this can return no results parameters: - name: artifact-id description: ontology id of the parcellation artifact paramType: path query: | <> - path: /dynamic/prod/sparc/artifactLabels/{artifact-id} operations: - summary: Get the graph of all parcellation labels for a single artifact WARNING this can return no results parameters: - name: artifact-id description: ontology id of the parcellation artifact paramType: path query: | <> - path: /dynamic/prod/sparc/rootLabels/{root-id} operations: &rootLabes-ops - summary: Get the list of all parcellation labels for a single label root parameters: - name: root-id description: ontology id of the parcellation label root paramType: path query: &rootLabels | <> - path: /dynamic/test/sparc/rootLabels/{root-id} operations: *rootLabes-ops query: *rootLabels - path: /dynamic/prod/sparc/parcellationRoots operations: - summary: Get the graph of all parcellation label roots for all species query: | <> - path: /dynamic/prod/sparc/parcellationRoots/{species-id} operations: - summary: Get the graph of all parcellation label roots for a single species parameters: - name: species-id description: ontology id of the species paramType: path query: | <> - path: /dynamic/prod/sparc/parcellationRoots/{species-id}/{region-id} operations: - summary: Get the graph of all parcellation label roots for a single species and anatomical region parameters: - name: species-id description: ontology id of the species paramType: path - name: region-id description: ontology id of the anatomical region paramType: path query: | <> - path: /dynamic/prod/sparc/parcellationRootsFMA/{species-id}/{fma-id} operations: &parcellationRootsFMA-ops - summary: Get the graph of all parcellation label roots for a single species and anatomical region parameters: - name: species-id description: ontology id of the species paramType: path - name: fma-id description: ontology id of the anatomical region paramType: path query: &parcellationRootsFMA | <> - path: /dynamic/test/sparc/parcellationRootsFMA/{species-id}/{fma-id} operations: *parcellationRootsFMA-ops query: *parcellationRootsFMA - path: /dynamic/prod/sparc/parcellationGraph operations: - summary: Get the graph of all parcellation labels for all species query: | <> - path: /dynamic/prod/sparc/organList operations: &organList-ops - summary: Get the list of all FMA organ identifiers relevant to SPARC query: &organList | <> - path: /dynamic/test/sparc/organList operations: *organList-ops query: *organList - path: /dynamic/prod/sparc/speciesList operations: &speciesList-ops - summary: Get the list of all NCBITaxon species identifiers relevant to SPARC query: &speciesList | <> - path: /dynamic/test/sparc/speciesList operations: *speciesList-ops query: *speciesList - path: /dynamic/shortestSimple query: | <> operations: - summary: Get the shortest path between two IDs parameters: - name: start_id description: The starting node (ex UBERON:0005751) paramType: query - name: end_id description: The ending node (ex UBERON:0001255) paramType: query - name: max_depth description: the maximum depth to traverse paramType: query - name: relationship description: The property to traverse (ex subClassOf or subClassOf|partOf|isA) paramType: query required: false - path: /dynamic/neurons/connectivity query: | <> operations: - summary: Get connected anatomical regions by neuron type parameters: - name: start_id description: The starting location (eg UBERON:0001759) paramType: query - path: /dynamic/neurons/connectedRegions query: | <> operations: - summary: Get connected anatomical regions by starting location and target relationship parameters: - name: start_id description: The starting location (eg UBERON:0001759) paramType: query - name: target_predicate description: The predicate for the type of connectivity (eg ilxtr:hasPresynapticTerminalsIn) paramType: query required: false - path: /dynamic/demos/apinat/bundles/{start-id} operations: - summary: Return the paths to somas from an anatomical region (aka connected-somas) parameters: - name: start-id description: ontology id of the starting point paramType: path query: | <> - path: /dynamic/demos/apinat/old-bundles/{start-id} operations: - summary: Return the paths to somas from an anatomical region (aka connected-somas) parameters: - name: start-id description: ontology id of the starting point paramType: path query: | <> - path: /dynamic/demos/apinat/somas operations: - summary: List all the somas for a given graph (TODO on the given graph) query: | <> - path: /dynamic/demos/apinat/housing-lyphs operations: - summary: List all the housing lyphs (neuronal processes) for all starting points. query: | <> - path: /dynamic/demos/apinat/housing-lyphs/{start-id} operations: - summary: List all the housing lyphs for a starting point. parameters: - name: start-id description: ontology id of the starting point paramType: path query: | <> - path: /dynamic/demos/apinat/soma-processes operations: - summary: List all the neuronal processes for all somas. query: | <> - path: /dynamic/demos/apinat/soma-processes/{start-id} operations: - summary: List all the neuronal processes for somas located in start-id. parameters: - name: start-id description: ontology id of the starting point paramType: path query: | <> - path: /dynamic/demos/apinat/weird-soma-processes/{process-id} operations: - summary: List all the neuronal processes for somas where some processes is in process-id. parameters: - name: process-id description: ontology id of the starting point paramType: path query: | <> - path: /dynamic/demos/apinat/neru-1/{neupop-id} operations: &neru-ops - summary: Return the housing regions and publications for neurulated groups. parameters: - name: neupop-id description: neuron population identifier paramType: path query: | <> - path: /dynamic/demos/apinat/neru-2/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/neru-3/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/neru-4/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/neru-5/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/neru-6/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/neru-7/{neupop_id} operations: *neru-ops query: | <> - path: /dynamic/demos/apinat/graphList operations: - summary: <> query: | <> - path: /dynamic/demos/apinat/modelList operations: - summary: <> query: | <> - path: /dynamic/demos/apinat/modelPopulationsReferences/{model_id} operations: - summary: <> parameters: - name: model_id description: the identifier for an ApiNATOMY model paramType: path query: | <> - path: /dynamic/prod/npo/hasTaxon/{id} operations: - summary: <> parameters: - name: id description: the identifier of a neuron type paramType: path query: | <> #+end_src * NPO competency queries ** npo species #+name: desc-npo-taxon Return any taxon associated with a neuron type. # :results drawer #+header: :var id="ilxtr:neuron-type-keast-5" #+name: npo-taxon #+begin_src cypher :limit 9999 MATCH (neupop:Class{iri: $id}) -[dimension:ilxtr:hasInstanceInSpecies!]->(taxon) WHERE NOT EXISTS(dimension.owlType) OR dimension.owlType = "subClassOf" OR dimension.owlType = "operand" RETURN taxon #+end_src ** npo phenotypes # :results drawer #+begin_src cypher MATCH (neupop) -[dimension:ilxtr:hasPhenotype!]->(phenotype) WHERE NOT EXISTS(dimension.owlType) OR dimension.owlType = "subClassOf" OR dimension.owlType = "operand" RETURN phenotype #+end_src #+begin_src sparql select distinct ?p (count(distinct ?neuron) as ?count) where { ?p rdfs:subPropertyOf* ilxtr:hasPhenotype . ?neuron (rdfs:subClassOf|(owl:equivalentClass/owl:intersectionOf/(rdf:rest|rdf:first)*)) [ owl:onProperty ?p ] . ?neuron rdfs:subClassOf* ?sckan_neuron . values ?sckan_neuron { ilxtr:NeuronSparcNlp ilxtr:NeuronApinatSimple } } group by ?p order by desc(?count) #+end_src ** npo locations TODO in order for this to work we have to be able to collapse the graph or customize the return value so we get dimension ae pairs # :results drawer #+begin_src cypher :limit 999 MATCH (neupop) -[dimension:ilxtr:hasLocationPhenotype!]->(phenotype) -[:property]->(prop:ObjectProperty{iri: "BFO:0000050"}) , (phenotype)-[:filler]->(ae) WHERE NOT EXISTS(dimension.owlType) OR dimension.owlType = "subClassOf" OR dimension.owlType = "operand" RETURN ae #+end_src ** npo partial orders # XXX performance note # major performance hit/pathology if common is not duplicated? # it was including the filter in the common bit instead of the unioned bits # likewise putting the layer owl:Class in common instead of in the unioned bits # leads to a massive slowdown, as a matter of fact as does making region_1 and # region_2 common apparently Extract the adjacency list directly. #+name: sparql-npo-query-adj-list #+begin_src sparql select distinct ?s ?region_1 ?layer_1 ?region_2 ?layer_2 where { # common ?s ilxtr:neuronPartialOrder ?o . ?o (rdf:rest|rdf:first)* ?r1 . ?r1 (rdf:rest|rdf:first)* ?r2 . { # region region ?region_1 a owl:Class . ?region_2 a owl:Class . ?r1 rdf:first ?region_1 . ?r2 rdf:first ?region_2 . filter (?mediator = ?r1) # draw only from the same partial order ?mediator rdf:first ?region_1 . # car ?mediator rdf:rest+/rdf:first/rdf:first ?region_2 . # caadr } union { # region layer region ?region_1 a owl:Class . ?layer_1 a owl:Class . ?region_2 a owl:Class . ?r1 rdf:first [ ?region_1 ?layer_1 ] . ?r2 rdf:first ?region_2 . filter (?mediator = ?r1) # draw only from the same partial order ?mediator rdf:first [ ?region_1 ?layer_1 ] . # car ?mediator rdf:rest+/rdf:first/rdf:first ?region_2 . # caadr } union { # region region layer ?region_1 a owl:Class . ?region_2 a owl:Class . ?layer_2 a owl:Class . ?r1 rdf:first ?region_1 . ?r2 rdf:first [ ?region_2 ?layer_2 ] . filter (?mediator = ?r1) # draw only from the same partial order ?mediator rdf:first ?region_1 . # car ?mediator rdf:rest+/rdf:first/rdf:first [ ?region_2 ?layer_2 ] . # caadr } union { # region layer region layer ?region_1 a owl:Class . ?layer_1 a owl:Class . ?region_2 a owl:Class . ?layer_2 a owl:Class . ?r1 rdf:first [ ?region_1 ?layer_1 ] . ?r2 rdf:first [ ?region_2 ?layer_2 ] . filter (?mediator = ?r1) # draw only from the same partial order ?mediator rdf:first [ ?region_1 ?layer_1 ] . # car ?mediator rdf:rest+/rdf:first/rdf:first [ ?region_2 ?layer_2 ] . # caadr } } order by ?s ?region_1 ?layer_1 ?region_2 ?layer_2 limit 900 #+end_src *** old notes :noexport: Can't use cypher atm because owlapi doesn't know what to do with nested lists. The same issue forced us to use pyontutils/rdflib to merge npo.ttl. #+begin_src cypher :limit 9999 match path = //(Class:{iri: "mmset2:1"}) (s)-[:ilxtr:neuronPartialOrder]->(blank) -[:rdf:rest|rdf:first*0..100]->(hrm) return blank, hrm #+end_src Potential solution is to reserialize the nested list to output with something other than rdf:first and rdf:rest so that owlapi will parse it as blanknodes and allow it to load. The following seems to work and owlapi will preserve the nesting. #+begin_src ttl @prefix : . :asdf a owl:Class ; rdfs:label "AAAAAAAAAAAAAAAAAAAAAAA" ; :neuronPartialOrder [ :first :a ; :rest [ :first :b ; :rest [ :first :c ] ] ] . #+end_src SPARQL works with a bit of a dance to ensure that each individual pair is extracted. To reconstruct the nested list tree structure start from nil and cons up iirc. #+name: sparql-npo-query-raw-partial-order #+begin_src sparql select distinct ?s ?r ?v where { VALUES ?s { mmset1:1 } ?s ilxtr:neuronPartialOrder ?o . ?o (rdf:rest|rdf:first)* ?r . ?r rdf:rest|rdf:first ?v . } order by ?s ?r ?v limit 900 #+end_src #+begin_src python :noweb yes import io import csv import requests from urllib.parse import quote as url_quote blazegraph_endpoint = 'http://localhost:9999/blazegraph/sparql' def procq(res): _, (str_count,) = res return int(str_count) def query(query, *, endpoint=blazegraph_endpoint, **kwargs): qq = url_quote(query, safe='') url = f'{endpoint}?query={qq}' headers = {'Accept': 'text/csv'} resp = requests.get(url, headers=headers) return list(csv.reader(io.StringIO(resp.text))) q = """ <> """ out = query(q) mms1_1 = [o for o in out if o[0].endswith('mmset1/1')] ends = [] for _, f, r in mms1_1: # TODO actually finish this if r.endswith('#nil'): ends.append(f) return mms1_1 #+end_src * ApiNATOMY competency queries ** wbrcm ontology terms All ontology terms currently used by the whole body reference connectivity model. #+name: cyres-wbrcm-classes #+begin_src cypher :limit 9999 MATCH (term:Class)-[:isDefinedBy]-(ont:Ontology{iri: "https://apinatomy.org/uris/models/wbrcm"}) RETURN term #+end_src #+begin_src jupyter-python :session pys :noweb yes :results none from pyontutils.utils import Async, deferred q = """ <> """ res = sgc.execute(q, limit=99999, output='application/json') ilxn = [n for n in res['nodes'] if n['id'].startswith('ILX:')] out = Async()(deferred(IlxTerm)(i['id']) for i in ilxn) sus = [o for o in out if 'ilxtr:hasExistingId' in o.predicates and not isinstance(o.predicates['ilxtr:hasExistingId'], tuple)] csvstr = '\n'.join([','.join((s.iri, s.label)) for s in sus]) with open('/tmp/sus-wbrcm-ilx-terms-2023-02-01.csv', 'wt') as f: f.write(csvstr) #+end_src ** expected counts per model Expected number of somas and neupops. | model-id | neupops | somas | |-------------------+---------+-------| | ard-arm-cardiac | 12 | 41 | | bolser-lewis | 29 | 29 | | bronchomotor | 6 | 19 | | keast-bladder | 20 | 34 | | sawg-distal-colon | 17 | 23 | | sawg-stomach | 14 | 14 | *** somas somas >= neupops The number of somas for distinct populations in a given model. *** populations the number of neuron populations as defined by the neurulator that have an ontology identifier *** neuron part per region per model | model-id | diag abbrev | external | somas | axons | axon term | dend | dend term | |-------------------+-------------+----------+-------+-------+-----------+------+-----------| | bolser-lewis | SCG | | 17 | | | | | | keast-bladder | | | | | | | | | bronchomotor | | | | | | | | | ard-arm-cardiac | | | | | | | | | sawg-distal-colon | | | | | | | | | sawg-stomach | | | | | | | | ** expected locations use NPO as a top down constraint on the locations of somas etc. *** somas could do this by population or generically *** population process location soma-processes can also be checked using NPO but not needed for simple cases | model-id | neupop | diag abbrev | external | |--------------+--------+-------------+----------| | bolser-lewis | q | PN | | | bolser-lewis | q | C4 | | | bolser-lewis | q | PHRNIC | | | bolser-lewis | q | DIAPHRAGM | | *** location process populations bundles NPO here as well | model-id | diag abbrev | external | neupop | |--------------+-------------+----------+---------| | bolser-lewis | VAGUS | | 9 total | ** cross model *** expect populations from models to have processes in common location #+name: region-populations #+begin_src sparql select distinct ?external (str(?el) as ?label) #?p ?model #?region #?link #?neru # ?seed (replace(str(?neru), "^.+-([A-Za-z0-9]+)$", "$1") as ?neuron_number) #?dyn ?neupop where { values ?external { UBERON:0006457 UBERON:0001894 UBERON:0005453 UBERON:0018683 } ?external a owl:Class ; apinatomy:annotates ?region ; rdfs:label ?el . ?region a elements:Lyph . ?model a elements:Graph ; apinatomy:lyphs ?region . ?link ( apinatomy:fasciculatesIn | apinatomy:endsIn | apinatomy:layerIn | apinatomy:internalIn )+ ?region . ?neru apinatomy:links ?link ; apinatomy:description ?dyn ; a elements:Group . filter contains(str(?dyn), "dynamic") optional { ?neru apinatomy:ontologyTerms ?neupop . } optional { ?seed apinatomy:seedIn ?neru . } # seedIn sort of works but misses cases where a dynamic group was created with a seed } order by str(?external) str(?model) xsd:integer(?neuron_number) #+end_src Expected. # FIXME the hline breaks with uberon somehow or for some reason? was # doing (- 8 14) and getting -6 somehow the width was too narrow and # broke `org-table--align-field' | external | diag abbrev | model-id | neupop | |----------------+--------------+-------------------+-------------------| | UBERON:0006457 | T1 | bolser-lewis | 1 2 3 6 7 | | UBERON:0006457 | T1 | keast-bladder | 20 | | UBERON:0001894 | DIENC | bolser-lewis | 1 26 | | UBERON:0001894 | Diencephalon | keast-bladder | 13 14 15 16 17 18 | | UBERON:0005453 | IMG | keast-bladder | 3 6 7 11 | | UBERON:0005453 | IMG | sawg-distal-colon | B D F G H Q | | UBERON:0018683 | LumSplN | keast-bladder | 6 7 11 | | UBERON:0018683 | LumSplN | sawg-distal-colon | B | *** vagus OWL DL query #+begin_src owldl hasLocationPhenotype some ('part of' some 'vagus nerve') hasLocationPhenotype some ('part of' some 'vagus nerve nucleus') hasLocationPhenotype some ('part of' some 'vagus nerve' or 'part of' some 'vagus nerve nucleus') #+end_src #+begin_src cypher // filter out things that project to the vagus nerve not that start in the vagus nerve or something like that (neupop)-[:ilxtr:hasLocationPhenotype]->(:Class{iri: UBERON:0001759}) (neupop)-[:ilxtr:hasAxonPresynapticElementIn]->(axon_locations) (neupop)-[:ilxtr:hasSensorySubcellularElementIn]->(dendrite_locations) #+end_src *** visualize all populations that have some process in the IMG Images of nerus that have some process in the IMG, from =keast-bladder= and =sawg-distal-colon=. ** kg queries #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-5") :results table drawer #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-5") :file ./images/neru-3-ntk-5-wat.svg #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-11") :file ./images/neru-3-ntk-11.svg #+call: neru-simplified(path="./images/neru-simplified-ntk-11.svg", json-string=python-neru-helper(result=cypher-neru-helper(neupop_id="ilxtr:neuron-type-keast-11"))) TODO point people to the query that returns a list of all neuron populations and all populations + papers per model #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-9") :file ./images/neru-3-ntk-9.svg #+call: neru-simplified(path="./images/neru-simplified-ntk-9.svg", json-string=python-neru-helper(result=cypher-neru-helper(neupop_id="ilxtr:neuron-type-keast-9"))) #+call: cypher-neru-debug(neupop_id="ilxtr:neuron-type-keast-2") :file ./images/debug-2.svg #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-2") :file ./images/neru-3-ntk-2.svg #+call: neru-simplified(path="./images/neru-simplified-ntk-2.svg", json-string=python-neru-helper(result=cypher-neru-3-helper(neupop_id="ilxtr:neuron-type-keast-2"))) 5 is going to be the easiest #+call: cypher-neru-debug(neupop_id="ilxtr:neuron-type-keast-5") :file ./images/debug-5.svg #+call: cypher-neru-3(neupop_id="ilxtr:neuron-type-keast-5") :file ./images/neru-3-ntk-5.svg #+call: neru-simplified(path="./images/neru-simplified-ntk-5.svg", json-string=python-neru-helper(result=cypher-neru-3-helper(neupop_id="ilxtr:neuron-type-keast-5"))) *** neuron type keast 5 projects to #+begin_src cypher RETURN region #+end_src Expected. | external | label | |----------------+-----------------| | UBERON:0016508 | pelvic ganglion | *** img processes query Input | UBERON:0005453 | inferior mesenteric ganglion | Expect | ilxtr:neuron-type-keast-3 | | ilxtr:neuron-type-keast-6 | | ilxtr:neuron-type-keast-7 | | ilxtr:neuron-type-keast-11 | | ilxtr:neuron-type-sdcol-b | | ilxtr:neuron-type-sdcol-d | | ilxtr:neuron-type-sdcol-f | | ilxtr:neuron-type-sdcol-g | | ilxtr:neuron-type-sdcol-h | | ilxtr:neuron-type-sdcol-q | #+call: cypher-neru-processes-pop-only(region_id="UBERON:0005453") :results table :note inferior mesenteric ganglion * Simple blaze simple sckan queries over blazegraph https://github.com/smtifahim/Loading-Simple-SCKAN/tree/main/sckan-to-simple-sckan ** inserts :PROPERTIES: :header-args:sparql: :url http://localhost:9999/blazegraph/namespace/kb/sparql :header-args: :eval never :END: #+begin_src sparql :noweb yes insert { ?s ?np ?o } <> #+end_src ** queries #+begin_src sparql #select (count(*) as ?c) { select distinct ?s ?o where { #?s nposimtest:hasSomaLocatedIn ?o ?s nposimtest:hasDendriteLocatedIn ?o } order by ?s ?o #} #+end_src #+begin_src sparql :noweb yes PREFIX nposimtest: SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: simple-sckan-load-1 #+begin_src sparql :noweb yes #PREFIX nposimtest: select distinct ?s ?np ?o <> order by ?s ?np ?o limit 5000 #+end_src # TODO add expansion over equivalentClass #+name: simple-sckan-load-1-where #+begin_src sparql where { { values (?p ?np) { (ilxtr:hasAxonPresynapticElementIn nposimtest:hasAxonPresynapticElementIn) (ilxtr:hasSomaLocatedIn nposimtest:hasSomaLocatedIn) #(ilxtr:hasSomaLocatedIn nposimtest:hasAxonLocatedIn) # add inferred axon locations (decided to exclude) (ilxtr:hasAxonLocatedIn nposimtest:hasAxonLocatedIn) (ilxtr:hasDendriteLocatedIn nposimtest:hasDendriteLocatedIn) (ilxtr:hasAxonSensorySubcellularElementIn nposimtest:hasAxonSensorySubcellularElementIn) #(ilxtr:hasAxonPresynapticElementIn ilxtr:hasAxonTerminalLocation) #(ilxtr:hasSomaLocatedIn ilxtr:hasSomaLocation) #(ilxtr:hasAxonLocatedIn ilxtr:hasAxonLocation) #(ilxtr:hasDendriteLocatedIn ilxtr:hasDendriteLocation) #(ilxtr:hasAxonSensorySubcellularElementIn ilxtr:hasAxonSensoryLocation) } ?s owl:equivalentClass [ rdf:type owl:Class ; owl:intersectionOf ?bn0 ] . ?bn0 rdf:rest*/rdf:first ilxtr:NeuronApinatSimple . ?bn0 rdf:rest*/rdf:first [ rdf:type owl:Restriction ; owl:onProperty ?p ; owl:someValuesFrom [ a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?o ] ] } union { values (?p ?np) { (ilxtr:hasForwardConnectionPhenotype nposimtest:hasForwardConnectionPhenotype) (ilxtr:hasFunctionalCircuitRolePhenotype nposimtest:hasFunctionalCircuitRolePhenotype) } ?s owl:equivalentClass [ rdf:type owl:Class ; owl:intersectionOf ?bn0 ] . ?bn0 rdf:rest*/rdf:first ilxtr:NeuronApinatSimple . ?bn0 rdf:rest*/rdf:first [ rdf:type owl:Restriction ; owl:onProperty ?p ; owl:someValuesFrom ?o ] }} #+end_src ** hackathon 2023 *** inserts :PROPERTIES: :header-args:sparql: :url http://localhost:9889/blazegraph/namespace/kb/sparql :header-args: :eval never :END: If you are running a local instance of blazegraph go to the update tab. For example at http://localhost:9999/blazegraph/#update. Under the =Type= dropdown select =RDF Data= and under the =Format= dropdown select =Turtle=. Download =simple-sckan-properties.ttl= linked below to a convenient location and then select it to upload. https://raw.githubusercontent.com/smtifahim/Loading-Simple-SCKAN/main/sckan-to-simple-sckan/input_ttl/simple-sckan-properties.ttl The switch the type to =SPARQL Update= and run the insert statements below (the corresponding queries are below). If on production requires port forwarding from aws-stardog =LocalForward 9889 localhost:9999=. Direct execution doesn't seem to be working right now via =ob-sparql=. #+begin_src sparql :noweb yes INSERT {?neuron_type ?npo_simple_prop ?object} <> #+end_src #+begin_src sparql :noweb yes INSERT { ?sub_region ilxtr:isPartOf ?super_region } <> #+end_src *** queries from https://github.com/smtifahim/Loading-Simple-SCKAN/blob/main/sckan-to-simple-sckan/sparql-query/simple-sckan-constructs.rq #+name: simple-sckan-load-2-where #+begin_src sparql :eval never WHERE { VALUES (?npo_prop ?npo_simple_prop) { # mapping properties for locational phenotypes (ilxtr:hasAxonPresynapticElementIn ilxtr:hasAxonTerminalLocation) (ilxtr:hasSomaLocatedIn ilxtr:hasSomaLocation) (ilxtr:hasSomaLocatedInLayer ilxtr:hasSomaLocation) (ilxtr:hasAxonLocatedIn ilxtr:hasAxonLocation) (ilxtr:hasDendriteLocatedIn ilxtr:hasDendriteLocation) (ilxtr:hasAxonSensorySubcellularElementIn ilxtr:hasAxonSensoryLocation) # treat all locational phenotype properties above as hasConnectedLocation in NPO-Simple/Simple SCKAN (ilxtr:hasAxonPresynapticElementIn ilxtr:hasConnectedLocation) (ilxtr:hasSomaLocatedInLayer ilxtr:hasConnectedLocation) (ilxtr:hasSomaLocatedIn ilxtr:hasConnectedLocation) (ilxtr:hasAxonLocatedIn ilxtr:hasConnectedLocation) (ilxtr:hasDendriteLocatedIn ilxtr:hasConnectedLocation) (ilxtr:hasAxonSensorySubcellularElementIn ilxtr:hasConnectedLocation) # mapping properties for other phenotypes (ilxtr:hasForwardConnectionPhenotype ilxtr:hasForwardConnection) (ilxtr:hasFunctionalCircuitRolePhenotype ilxtr:hasFunctionalCircuitRole) (ilxtr:hasAnatomicalSystemPhenotype ilxtr:hasNeuronalPhenotype) #changed from ilxtr:hasPhenotype to ilxtr:hasAnatomicalSystemPhenotype (ilxtr:hasProjectionPhenotype ilxtr:hasProjection) (ilxtr:hasCircuitRolePhenotype ilxtr:hasCircuitRole) (ilxtr:hasInstanceInTaxon ilxtr:isObservedInSpecies) (ilxtr:hasBiologicalSex ilxtr:hasPhenotypicSex) } # For the neuron types with locational phenotypes specified withing the intersections of the equivalent axioms. { ?neuron_type a owl:Class; (owl:equivalentClass | rdfs:subClassOf) [ rdf:type owl:Class ; owl:intersectionOf ?bn0 ] . ?bn0 rdf:rest*/rdf:first [ rdf:type owl:Restriction ; owl:onProperty ?npo_prop ; owl:someValuesFrom [ a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?object ] ] . } UNION # For the neuron types with locational phenotype axioms as super classes e.g., http://uri.neuinfo.org/nif/nifstd/nlx_cell_20081201 { ?neuron_type a owl:Class; (rdfs:subClassOf) [ rdf:type owl:Restriction ; owl:onProperty ?npo_prop ; owl:someValuesFrom [rdf:type owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?object ] ] . } UNION # For neuron types with other phenotypes specified within the intersections of the eqivalent axioms. { ?neuron_type a owl:Class; (owl:equivalentClass | rdfs:subClassOf) [ rdf:type owl:Class ; owl:intersectionOf ?bn0 ] . ?bn0 rdf:rest*/rdf:first [ rdf:type owl:Restriction ; owl:onProperty ?npo_prop ; owl:someValuesFrom ?object ] } UNION # For neuron types with other phenotypes axioms specified as superclasses. { ?neuron_type a owl:Class; (rdfs:subClassOf) [ rdf:type owl:Restriction ; owl:onProperty ?npo_prop ; owl:someValuesFrom ?object ] } FILTER (!isBLANK(?object)) } #+end_src #+name: simple-sckan-uberon-where #+begin_src sparql # Select DISTINCT ?sub_region ?sub_region_label ?super_region ?super_region_label WHERE { # Filter (?super_region_label = 'pancreas') ?super_region rdfs:subClassOf+ . #subclass of 'anatomical entity' ?sub_region rdfs:subClassOf+ . ?sub_region rdfs:subClassOf+ [rdf:type owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?super_region]. # ?sub_region ilxtr:isPartOf+ ?super_region. ?sub_region rdfs:label ?sub_region_label. ?super_region rdfs:label ?super_region_label. Filter (!REGEX(str(?sub_region), "CL_")) #exclude CL classes Filter (!REGEX(str(?super_region), "CL_")) #exclude CL classes # FILTER (?sub_region != ?super_region) } #+end_src ** owl restriction over transitive properties issues sigh [[https://ceur-ws.org/Vol-749/paper19.pdf][Subqueries in SPARQL]] #+begin_src sparql :eval yes #PREFIX partOf: #PREFIX owl: #PREFIX TEMP: #PREFIX rdfs: insert { ?region TEMP:partOf ?region2 } where { ?region rdfs:subClassOf ?rest . ?rest a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?region2 . } #+end_src *** sigh #+begin_src sparql select ?region (str(?rl) as ?label) where { #?region (rdfs:subClassOf|TEMP:partOf)* UBERON:0001016 . #?region (rdfs:subClassOf|TEMP:partOf)* UBERON:0000010 . # FIXME peripheral nervous system partonomy is utterly broken ??? #?region TEMP:partOf+ UBERON:0000010 . optional { ?region rdfs:label ?rl . } } limit 99 #+end_src #+begin_src sparql select ?region #TEMP:partOf ?region2 where { ?region rdfs:subClassOf ?rest . ?rest a owl:Restriction ; owl:onProperty partOf: ; owl:someValuesFrom ?region2 . } limit 10 #+end_src * Sanity checks Other queries run against various representations of the data. ** JSON #+name: &jq-count-datasets : jq -c '.datasets | length' #+name: &jq-count-path-metadata : jq -c '[paths | select(.[-1] == "path_metadata")] | length' #+begin_src bash :noweb yes function path-metadata-coverage () { local PATH_EXPORT_JSON=$1 local COUNT_T=$(<<&jq-count-datasets()>> "${PATH_EXPORT_JSON}") local COUNT_PM=$(<<&jq-count-path-metadata()>> "${PATH_EXPORT_JSON}") awk -v t=${COUNT_T} -v pm=${COUNT_PM} 'BEGIN { print ( pm / t ) }' } #+end_src * General queries General metadata and housekeeping queries. ** List all loaded ontologies #+begin_src sparql SELECT ?s WHERE { ?s a owl:Ontology } #+end_src #+begin_src cypher :limit 9999 MATCH (o:Ontology) RETURN o #+end_src ** predicates #+name: predicates-all #+begin_src sparql select distinct ?p ?l where { ?s ?p ?o . optional { ?p rdfs:label ?l . } } order by ?p #+end_src #+name: predicates-version #+begin_src sparql select ?s ?p ?o where { values ?p { prov:startedAtTime prov:wasGeneratedBy dc:date owl:versionInfo TEMP:TimestampExportStart } ?s ?p ?o . } order by desc(str(?o)) #+end_src ** versions Useful version information is not present in all ontology files at the moment. *** embedded load provenance record :PROPERTIES: :CUSTOM_ID: embedded-load-provenance-record :END: #+name: versions-sparql #+begin_src sparql SELECT ?p ?o WHERE { build:prov ?p ?o . } #+end_src #+name: versions-cypher #+begin_src cypher :results drawer MATCH (p)-[i:build:id]-(), (p)-[e]-() RETURN i, e #+end_src *** curation-export.ttl #+begin_src sparql select ?s ?tes ?vi where { ?s TEMP:TimestampExportStart ?tes ; owl:versionInfo ?vi . } #+end_src *** protcur.ttl #+begin_src sparql select distinct ?o where { owl:versionInfo ?o } #+end_src *** apinat models :PROPERTIES: :CUSTOM_ID: apinat-models :END: From [[cypher-apinat-graphs]] now includes the external stable model id in the results as well #+begin_src cypher :results drawer MATCH ({iri: "https://apinatomy.org/uris/elements/Graph"})<-[:type]-(g)<-[e:apinatomy:hasGraph]-(o:Ontology) RETURN g, e, o #+end_src * Use cases ** Connectivity dashboard *** organs :PROPERTIES: :CREATED: [2021-08-06 Fri 13:10] :END: # FIXME looking for the ya' or ya" evil commands, I know I've used them before # reval maybe? nope `url-unhex-string-at-point' `evil-inner-double-quote' # "with escape \" yeah? " # org doesn't have strings but evil works #+begin_src elisp :results none :exports none (defun org-babel-execute:ttl (body params) "Return the verbatim BODY of the ttl. We can probably cook up an alternate version of this which would expand into triples using arrays or something like that." body) #+end_src #+name: py-ttl-subjects #+begin_src python :noweb yes :var input=(and (fboundp 'orgstrap--with-block) (orgstrap--with-block "ttl-organs" body)) :results code :wrap src ttl # py-safe-block from pyontutils.core import OntGraph g = OntGraph().parse(data=input, format='ttl') #return [[g.namespace_manager._qhrm(_)] for _ in sorted(set(g.subjects()))] return ' '.join([g.namespace_manager._qhrm(_) for _ in sorted(set(g.subjects()))]) #+end_src #+name: ttl-organs #+begin_src ttl @prefix l: . @prefix e: . @prefix FMA: . @prefix UBERON: . # tissue UBERON:0001013 l: "adipose tissue"; e: FMA:20110 . # regions UBERON:0002298 l: "brainstem"; e: FMA:79876 . UBERON:0001016 l: "nervous system"; e: FMA:7157 . UBERON:0000010 l: "peripheral nervous system"; e: FMA:9903 . UBERON:0000013 l: "sympathetic nervous system"; e: FMA:9906 . UBERON:0002005 l: "enteric nervous system"; e: FMA:66070 . # TODO cardiovascular system # e.g. for blood pressure # TODO cardiopulmonary system # organs UBERON:0000955 l: "brain"; e: FMA:50801 . UBERON:0001155 l: "colon"; e: FMA:14543 . UBERON:0002110 l: "gallbladder"; e: FMA:7202 . UBERON:0000948 l: "heart"; e: FMA:7088 . UBERON:0000160 l: "intestine"; e: FMA:7199 . UBERON:0002113 l: "kidney"; e: FMA:7203 . UBERON:0000059 l: "large intestine"; e: FMA:7201 . UBERON:0002107 l: "liver"; e: FMA:7197 . UBERON:0001556 l: "lower urinary tract"; e: FMA:45659 . UBERON:0002048 l: "lung"; e: FMA:68877 . UBERON:0001630 l: "muscle organ"; e: FMA:5022 . UBERON:0001264 l: "pancreas"; e: FMA:7198 . UBERON:0002097 l: "skin of body"; e: FMA:7163 . UBERON:0002108 l: "small intestine"; e: FMA:7200 . UBERON:0002240 l: "spinal cord"; e: FMA:7647 . UBERON:0002106 l: "spleen"; e: FMA:7196 . UBERON:0000945 l: "stomach"; e: FMA:7148 . UBERON:0001255 l: "urinary bladder"; e: FMA:15900 . # granular UBERON:0000057 l: "urethra"; e: FMA:19667 . UBERON:0001043 l: "esophagus"; e: FMA:7131 . #+end_src *** nerves #+name: ttl-nerves #+begin_src ttl @prefix l: . @prefix e: . @prefix FMA: . @prefix UBERON: . # XXX sciatic nerve is missing from this list # not actually cranial UBERON:0002019 l: "accessory XI nerve"; e: FMA:6720 . # missing from the larger list # nerves missing from the larger list UBERON:0001646 l: "abducens nerve"; e: FMA:50867 . UBERON:0001650 l: "hypoglossal nerve"; e: FMA:50871 . UBERON:0001579 l: "olfactory nerve"; e: FMA:46787 . UBERON:0001644 l: "trochlear nerve"; e: FMA:50865 . UBERON:0003723 l: "vestibulocochlear nerve"; e: FMA:50869 . # the larger list UBERON:0034728 l: "autonomic nerve" . UBERON:0009009 l: "carotid sinus nerve" . UBERON:0009675 l: "chorda tympani branch of facial nerve" . UBERON:0019198 l: "dorsal nerve of clitoris" . UBERON:0019197 l: "dorsal nerve of penis" . UBERON:0010380 l: "enteric nerve" . UBERON:0010406 l: "cholinergic enteric nerve" . UBERON:0001647 l: "facial nerve"; e: FMA:50868 . UBERON:0001649 l: "glossopharyngeal nerve"; e: FMA:50870 . UBERON:0001643 l: "oculomotor nerve"; e: FMA:50864 . UBERON:0002924 l: "terminal nerve" . UBERON:0001645 l: "trigeminal nerve"; e: FMA:50866 . UBERON:0001759 l: "vagus nerve"; e: FMA:5731 . # TODO vagus nerve branches UBERON:0018680 l: "greater splanchnic nerve" . UBERON:0003438 l: "iris nerve" . UBERON:0011096 l: "lacrimal nerve" . UBERON:0035642 l: "laryngeal nerve" . UBERON:0011766 l: "left recurrent laryngeal nerve" . UBERON:0011767 l: "right recurrent laryngeal nerve" . UBERON:0003716 l: "recurrent laryngeal nerve" . UBERON:0011326 l: "superior laryngeal nerve" . UBERON:3010764 l: "laryngeus ventralis" . UBERON:0001964 l: "least splanchnic nerve" . UBERON:0018681 l: "lesser splanchnic nerve" . UBERON:0003721 l: "lingual nerve" . UBERON:0022301 l: "long ciliary nerve" . UBERON:0018683 l: "lumbar splanchnic nerve" . UBERON:0000377 l: "maxillary nerve" . UBERON:0036143 l: "meningeal branch of mandibular nerve" . UBERON:0017641 l: "meningeal branch of spinal nerve" . UBERON:0022300 l: "nasociliary nerve" . UBERON:0008810 l: "nasopalatine nerve" . UBERON:0035650 l: "nerve of clitoris" . UBERON:0035649 l: "nerve of penis" . UBERON:0015162 l: "superior branch of oculomotor nerve" . UBERON:0018675 l: "pelvic splanchnic nerve" . UBERON:0011391 l: "perineal nerve" . UBERON:0001884 l: "phrenic nerve" . UBERON:0034725 l: "pterygopalatine nerve" . UBERON:0011390 l: "pudendal nerve" . UBERON:0009625 l: "sacral nerve" . UBERON:0018684 l: "sacral splanchnic nerve" . UBERON:0022302 l: "short ciliary nerve" . UBERON:0003715 l: "splanchnic nerve" . UBERON:0018679 l: "thoracic splanchnic nerve" . UBERON:0001323 l: "tibial nerve" . UBERON:0036216 l: "tympanic nerve" . UBERON:0018412 l: "vidian nerve" . # cervical nerve UBERON:0000962 l: "nerve of cervical vertebra"; e: FMA:5859 . #+end_src *** plexi #+begin_src ttl UBERON:0002439 l: "myenteric nerve plexus"; e: FMA:63252 . #+end_src distributed ganglion that has not ensheathed there may be significant variablity between individuals in whether a plexius is fully ganglionated/ensheathed the issue is that from the perspective the cell populations, they are actually the same population regardless of whether they are plexi or ganglia maybe need to get these to converge onto the neuron populations so that we can merge the two **** TODO consult with SAWG about these :PROPERTIES: :CREATED: [2021-09-17 Fri 14:33] :END: *** ganglia :PROPERTIES: :CREATED: [2021-09-17 Fri 14:29] :END: #+name: ttl-ganglia #+begin_src ttl @prefix l: . @prefix e: . @prefix syn: . @prefix FMA: . @prefix UBERON: . UBERON:0001808 l: "parasympathetic ganglion" . UBERON:0035776 l: "accessory ciliary ganglion" . UBERON:0001805 l: "autonomic ganglion"; e: FMA:5889 . UBERON:0014463 l: "cardiac ganglion" . UBERON:0002262 l: "celiac ganglion" . UBERON:0035783 l: "ganglion of ciliary nerve" . UBERON:0001701 l: "glossopharyngeal ganglion" . UBERON:0005360 l: "inferior glossopharyngeal IX ganglion" . UBERON:0013500 l: "glossopharyngeal-vagus IX-X ganglion complex" . UBERON:0035769 l: "mesenteric ganglion" . UBERON:0005479 l: "superior mesenteric ganglion" . UBERON:0005453 l: "inferior mesenteric ganglion" . UBERON:0001989 l: "superior cervical ganglion" . UBERON:0001990 l: "middle cervical ganglion" . UBERON:0002440 l: "inferior cervical ganglion" . UBERON:0003963 l: "otic ganglion" . UBERON:0001807 l: "paravertebral ganglion" . UBERON:0016508 l: "pelvic ganglion" . UBERON:0003964 l: "prevertebral ganglion" . UBERON:0003962 l: "pterygopalatine ganglion" . UBERON:0005407 l: "sublingual ganglion" . UBERON:0002059 l: "submandibular ganglion" . UBERON:0001806 l: "sympathetic ganglion" . UBERON:0005362 l: "vagus X ganglion" . UBERON:0005364 l: "superior vagus X ganglion" . UBERON:0005363 l: "inferior vagus X ganglion"; syn: "nodose ganglion" . UBERON:0000408 l: "vertebral ganglion" . UBERON:0002441 l: "cervicothoracic ganglion"; e: FMA:6469; syn: "stellate ganglion" . #+end_src **** TODO add synonyms :PROPERTIES: :CREATED: [2021-09-17 Fri 14:33] :END: *** neuron population by organ #+name: organ-subjects #+call: py-ttl-subjects(input=(orgstrap--with-block "ttl-organs" body)) :cache yes #+name: ganglia-subjects #+call: py-ttl-subjects(input=(orgstrap--with-block "ttl-ganglia" body)) :cache yes #+name: nerve-subjects #+call: py-ttl-subjects(input=(orgstrap--with-block "ttl-nerves" body)) :cache yes # FIXME somehow selecting only predicates here produces numerical results only !? #+name: ongrep #+header: :exports code #+begin_src sparql :noweb yes :var limit="99" :file ./reports/organ-nerve-ganglia.csv :results file select distinct ?organ_start ?label (count(distinct(?ele)) as ?elements) #?elements ?model #?ele #?type # ?sp #?s #?op_wat #?p #?o where { values ?organ_start { <> <> <> } ?organ_start rdfs:label ?sl . bind(str(?sl) as ?label) # FIXME TODO traverse partonomy optional { values ?type { elements:Lyph elements:Group elements:Material elements:Chain } ?organ ( partOf: | rdfs:subClassOf )* ?organ_start . #?organ apinatomy:annotates ?ele . ?ele apinatomy:ontologyTerms ?organ . ?ele a ?type . ?model ( apinatomy:lyphs | apinatomy:chains | apinatomy:groups | apinatomy:materials ) ?ele . ?model a elements:Graph . #?ele apinatomy:inheritedOntologyTerms ?organ . #?o ?p ?q . } } group by ?organ_start ?label ?model order by ?organ_start #order by ?type ?organ ?model #limit ?limit #+end_src #+begin_src elisp :results none :exports none (ow-babel-eval "ongrep") #+end_src #+RESULTS: ongrep [[file:./reports/organ-nerve-ganglia.csv]] https://docs.google.com/spreadsheets/d/1pgprwTr4bvAaex8cNLeoRLUgt0VU5tilbWi4BCWF1JE/edit#gid=219324374 =organ-nerve-ganglia= # TODO auto populate results #+begin_src sparql select distinct ?part_start (str(?sl) as ?start_label) where { ?part_start rdfs:subClassOf+/owl:someValuesFrom+ UBERON:0001255 . ?part_start rdfs:label ?sl . } #+end_src the nested version here is massively slow #+begin_src sparql :var limit="200" select distinct ?part (str(?l) as ?label) where { values ?part_0 { UBERON:0001255 } #?part_1 rdfs:label ?l1 . ?part_1 rdfs:subClassOf ?bn0 . ?bn0 a owl:Restriction . ?bn0 owl:onProperty partOf: . ?bn0 owl:someValuesFrom ?part_0 . optional { #?part_2 rdfs:label ?l2 . ?part_2 rdfs:subClassOf ?bn1 . ?bn1 a owl:Restriction . ?bn1 owl:onProperty partOf: . ?bn1 owl:someValuesFrom ?part_1 . optional { #?part_3 rdfs:label ?l3 . ?part_3 rdfs:subClassOf ?bn2 . ?bn2 a owl:Restriction . ?bn2 owl:onProperty partOf: . ?bn2 owl:someValuesFrom ?part_2 . } } #optional { #?part_4 rdfs:label ?l4 . #?part_4 rdfs:subClassOf ?bn3 . #?bn3 a owl:Restriction . #?bn3 owl:onProperty partOf: . #?bn3 owl:someValuesFrom ?part_3 . #} ?part a owl:Class . ?part rdfs:label ?l . filter ( ?part = ?part_0 || ?part = ?part_1 || ?part = ?part_2 || ?part = ?part_3 ) #( || ?part = ?part_4 ) } limit ?limit #+end_src #+begin_src sparql select distinct ?part_1 where { values ?part_0 { UBERON:0009958 } ?part_1 rdfs:label ?l . ?part_1 rdfs:subClassOf ?bn0 . ?bn0 a owl:Restriction . ?bn0 owl:onProperty partOf: . ?bn0 owl:someValuesFrom ?part_0 . } #+end_src #+begin_src sparql select distinct ?sigh (str(?l) as ?label) #?sigx #(str(?lx) as ?labx) where { ?sigh rdfs:subClassOf+/owl:someValuesFrom+ UBERON:0001255 . # consider also RO:0002433 usually go together ?sigh rdfs:label ?l . # FIXME somehow male and female urethra are still being pulled in :/ #filter ( ?sigh != UBERON:0000057 ) #filter not exists { ?sigh rdfs:subClassOf/owl:someValuesFrom UBERON:0000057 . } ?sigh rdfs:subClassOf/owl:onProperty partOf: . #?sigx rdfs:subClassOf ?bn . #?bn a owl:Restriction . #?bn owl:onProperty partOf: . #?bn owl:someValuesFrom ?sigh . #?sigx rdfs:label ?lx . filter not exists { ?sigh rdfs:subClassOf/owl:onProperty . } filter not exists { ?sigh rdfs:subClassOf/owl:onProperty . } filter not exists { ?sigh rdfs:subClassOf/owl:onProperty BFO:0000051 . } filter not exists { ?sigh rdfs:subClassOf/owl:onProperty RO:0002150 . } filter not exists { ?sigh rdfs:subClassOf/owl:onProperty RO:0002221 . } filter not exists { ?sigh rdfs:subClassOf/owl:onProperty RO:0002178 . } } order by ?label #+end_src #+begin_src sparql select distinct ?part ?prop (str(?l) as ?label) ?part_start (str(?sl) as ?start_label) where { values ?wat { UBERON:0001255 } # FIXME this is still completely broken because sparql and # transitive queries over over owl restrictions are ... problematic ?part_start rdfs:subClassOf+/owl:someValuesFrom+ ?wat . filter ( ?prop = partOf: ) ?part_start rdfs:label ?sl . ?part_start rdfs:subClassOf ?bny . ?bny owl:onProperty ?prop . ?part rdfs:label ?l . ?part rdfs:subClassOf ?bn0 . ?bn0 a owl:Restriction . ?bn0 owl:onProperty partOf: . ?bn0 owl:someValuesFrom ?part_start . } order by ?start_label #+end_src #+name: ongrep-table #+call: ongrep() :results table #+name: ongrep-push #+begin_src python :var data=ongrep-table() :results drawer from sparcur.sheets import Reports class ONGRep: _data = data class options: preview = False to_sheets = True @Reports.makeReportSheet('organ_start', sheet_name='organ-nerve-ganglia') def populate(self, ext=None): return self._data, 'organ-nerve-ganglia coverage report' t = ONGRep() #t.populate() return t._data #+end_src #+begin_src elisp :results none :exports none (ow-babel-eval "ongrep-push") #+end_src *** neuron population by nerve *** neuron population by ganglion *** devel #+begin_src jupyter-python :session pys3 1 + 2 #+end_src #+RESULTS: : 3 # @prefix ILX: . #+begin_src jupyter-python :session pys2 from pyontutils.core import OntTerm asdf = ['ILX:0727875', 'ILX:0727396', 'ILX:0727235', 'ILX:0736783', 'ILX:0725331', 'ILX:0724284', 'ILX:0732483', 'ILX:0725803', 'ILX:0723837', 'ILX:0737036', 'ILX:0725086', 'ILX:0736097', 'ILX:0733375', 'ILX:0730739', 'ILX:0734588', 'ILX:0728741', 'ILX:0728157', 'ILX:0724431', 'ILX:0728322', 'ILX:0486534', 'ILX:0731053', 'ILX:0734339', 'ILX:0731969', 'ILX:0726449', 'ILX:0734582', 'ILX:0731914', 'ILX:0729870', 'ILX:0728987', 'ILX:0736712', 'ILX:0735649', 'ILX:0730231', 'ILX:0725969', 'ILX:0725552', 'ILX:0729045', 'ILX:0732611', 'ILX:0724152', 'ILX:0724140', 'ILX:0736057', 'ILX:0726733', 'ILX:0735212', 'ILX:0726145', 'ILX:0736880', 'ILX:0732740', 'ILX:0730942', 'ILX:0736020', 'ILX:0733193', 'ILX:0733995', 'ILX:0503992', 'ILX:0734328', 'ILX:0724764', 'ILX:0729794', 'ILX:0734607', 'ILX:0727602', 'ILX:0735024', 'ILX:0725520', 'ILX:0728778', 'ILX:0726312', 'ILX:0733021', 'ILX:0732970', 'ILX:0725326', 'ILX:0725956', 'ILX:0726454', 'ILX:0734766', 'ILX:0733700', 'ILX:0733004', 'ILX:0732328', 'ILX:0735011', 'ILX:0734057', 'ILX:0730509', 'ILX:0727725', 'ILX:0730966', 'ILX:0729052', 'ILX:0736358', 'ILX:0727970', 'ILX:0736369'] qq = [OntTerm(a) for a in asdf] #+end_src #+begin_src jupyter-python :session pys2 [(repr(_), _('ilxtr:hasIlxPreferredId')[0].curie) for _ in qq] #+end_src ** ApiNATOMY *** sparql extract ApiNATOMY partial orders for use in NPO start of a query that is similar to [[neru-7]] but allows direct extraction of partial orders using sparql instead of needing to do an extended cypher load, this can probably be simplified significantly by deriving the partial order using only links and then finding the housing region/layer for each link see also [[region-populations]] #+name: sparql-apinat-partial-orders #+begin_src sparql select distinct ?pop #?link #?region #?link1 #?link2 #?l1 ?region1 ?term_layer1 #?l2 ?region2 ?term_layer2 where { #?pop rdfs:subClassOf+ ilxtr:Neuron . ?pop apinatomy:annotates ?ngrp . ?ngrp apinatomy:description ?dyn . filter contains(str(?dyn), "dynamic") { ?ngrp apinatomy:lyphs ?lyph . ?lyph a elements:Lyph . { ?lyph apinatomy:internalIn ?housing_lyph . } union { ?lyph apinatomy:internalIn ?housing_layer . ?housing_layer apinatomy:layerIn ?housing_lyph . ?housing_layer apinatomy:ontologyTerms ?term_layer1 } ?housing_lyph apinatomy:conveys ?s_link0 . ?housing_lyph apinatomy:ontologyTerms ?region1 . ?lyph apinatomy:conveys ?soma_link . #?soma_link apinatomy:source/apinatomy:targetOf|apinatomy:target/apinatomy:sourceOf ?soma_next . # XXX this doesn't work, because the apinatomy representation has explicit directionality when working with node/link graphs so we use rootOf which is bad because it assumes a chain, which is an abstraction that probably shouldn't be used for queries, but whatever ?soma_link apinatomy:source|apinatomy:target ?soma_node . ?soma_node apinatomy:rootOf ?some_chain . ?soma_node apinatomy:sourceOf|apinatomy:targetOf ?soma_next_link . ?some_chain apinatomy:levels ?soma_next_link . ?soma_next_link a elements:Link . ?soma_next_link apinatomy:conveyingLyph ?soma_next_lyph . { ?soma_next_lyph apinatomy:internalIn ?snx_housing_lyph . } union { ?soma_next_lyph apinatomy:internalIn ?snx_housing_layer . ?snx_housing_layer apinatomy:layerIn ?snx_housing_lyph . ?snx_housing_layer apinatomy:ontologyTerms ?term_layer2 } ?snx_housing_lyph apinatomy:conveys ?s_link3 . ?snx_housing_lyph apinatomy:ontologyTerms ?region2 . } union { ?ngrp apinatomy:links ?link . ?link a elements:Link . #?link (apinatomy:fasciculatesIn|apinatomy:endsIn)* ?lyph_or_layer . #?lyph_or_layer apinatomy:layerIn* ?lyph . #?lyph apinatomy:conveys* ?some_other_link . #?lyph apinatomy:ontologyTerms ?region . #?link apinatomy:conveyingLyph ?cl . #?cl apinatomy:topology ?cl_topo ; #apinatomy:interitedOntologyTerms* ?cl_iot . ?link (apinatomy:next|apinatomy:nextChainStartLevels)* ?link1 . #?link1 apinatomy:target+ ?node1 . #?node1 apinatomy:rootOf+ ?chain1 . #?chain1 apinatomy:levels+ ?link2 . #?ngrp apinatomy:links ?b3 . # this line doesn't work quite the same way it does in cypher because it implies ?b3 = ?link filter (?l1 = ?link1) ?l1 apinatomy:next|apinatomy:nextChainStartLevels ?l2 . ?l1 a elements:Link . { ?l1 apinatomy:fasciculatesIn|apinatomy:endsIn ?lyph1 . ?lyph1 apinatomy:conveys ?some_other_link1 ; apinatomy:ontologyTerms ?region1 . } union { ?l1 apinatomy:fasciculatesIn|apinatomy:endsIn ?layer1 . ?layer1 apinatomy:layerIn ?lyph1 . ?layer1 apinatomy:ontologyTerms ?term_layer1 . ?lyph1 apinatomy:conveys ?some_other_link1 ; apinatomy:ontologyTerms ?region1 . } ?l2 a elements:Link . { ?l2 apinatomy:fasciculatesIn|apinatomy:endsIn ?lyph2 . ?lyph2 apinatomy:conveys ?some_other_link2 ; apinatomy:ontologyTerms ?region2 . } union { ?l2 apinatomy:fasciculatesIn|apinatomy:endsIn ?layer2 . ?layer2 apinatomy:layerIn ?lyph2 . ?layer2 apinatomy:ontologyTerms ?term_layer2 . ?lyph2 apinatomy:conveys ?some_other_link2 ; apinatomy:ontologyTerms ?region2 . } #union # don't run this it will be a disaster #{ #?lyph apinatomy:internalIn ?housing_lyph . #?housing_lyph apinatomy:ontologyTerms ?region1 . # FIXME this is surely wrong #} # TODO need soma links #apinatomy:fasciculatesIn|apinatomy:endsIn ?lyph_or_layer1 . #?lyph_or_layer1 apinatomy:layerIn* ?lyph1 . #?lyph1 apinatomy:conveys* ?some_other_link1 . #?lyph1 apinatomy:ontologyTerms ?region1 . #?l2 a elements:Link ; #(apinatomy:fasciculatesIn|apinatomy:endsIn)? ?lyph_or_layer2 . #?lyph_or_layer2 apinatomy:layerIn* ?lyph2 . #?lyph2 apinatomy:conveys* ?some_other_link2 . #?lyph2 apinatomy:ontologyTerms ?region2 . } } order by str(?pop) #limit 99 #+end_src #+header: :depends py-query-helper #+begin_src jupyter-python :session pys :noweb yes q_sn7 = """ <> """ q_sn7_out = query(q_sn7) pops = set(r[0] for r in q_sn7_out[1:]) # XXX clearly missing some populations from the list such as aacar-10v aacar-14 etc. #print(sorted(pops)) #+end_src *** Coverage of FMA by the TOO map. Unclaimed regions from FMA/UBERON in the TOO map Define the TOO map as the covering set of terms. It might not actually be, but that is how we will treat it. Probably want to avoid the immaterial entities. Try to come up with a basis set from FMA as well. If there are regional hierarchies that have been missed we will see them. *** Summary statistics **** debug # fuck everything about this #+begin_src sparql SELECT distinct ?o WHERE { ?o a elements:Graph . } order by str(?o) #+end_src #+begin_src sparql select distinct ?graph ?lyphs ?label WHERE { # ?model apinatomy:hasGraph ?graph # TODO broken conversion to literal instead of uri at the moment # sadly it seems that no one has managed to write an optimization that converts # into this form when querying multiple predicates in the same expression { ?graph a elements:Graph ; rdfs:label ?label . { select ?graph (count(distinct(?o)) as ?lyphs ) where { ?graph apinatomy:lyphs ?o . } group by ?graph } } union { { select (count(distinct(?graph_)) as ?graph ) where { ?graph_ a elements:Graph } } bind("Total unique" as ?label) { select (count(distinct(?o)) as ?lyphs ) where { ?graph_ apinatomy:lyphs ?o . } } } } #+end_src **** Dashboard :PROPERTIES: :CUSTOM_ID: apinat-dashboard :END: # TODO configure header args for development vs production #+begin_src elisp :results none :exports none (ow-babel-eval "apinat-dashboard-model-summary") (ow-babel-eval "apinat-dashboard-overview") (ow-babel-eval "sparql-apinat-prefixes") #+end_src #+RESULTS: apinat-dashboard-model-summary | label | graph | lyphs | lyphs_input | externals | publications | nerus | neupops | neupops_pat | somas | |------------------------------------------------------------------------+-------------------------+-------+-------------+-----------+--------------+-------+---------+-------------+-------| | ApiNATOMY model of the stomach | sstom:sawg-stomach | 668 | 37 | 77 | 8 | 14 | 14 | 14 | 14 | | Ardell Armour Cardiac Model | aacar:ard-arm-cardiac | 1827 | 137 | 161 | 2 | 17 | 17 | 17 | 41 | | Bolser-Lewis Model of the Physiology of the Superior Cervical Ganglion | bolew:bolser-lewis | 1151 | 107 | 141 | 239 | 29 | 29 | 29 | 29 | | Keast ApiNATOMY model of bladder innervation | kblad:keast-bladder | 2394 | 139 | 174 | 30 | 21 | 20 | 20 | 35 | | SAWG ApiNATOMY model of the descending colon | sdcol:sawg-distal-colon | 1066 | 89 | 135 | 5 | 18 | 18 | 18 | 24 | | SPARC Bronchomotor Flatmap | bromo:bronchomotor | 623 | 144 | 187 | 6 | 6 | 6 | 6 | 19 | | pancreas model | pancr:pancreas | 452 | 17 | 529 | 1 | 5 | 5 | 5 | 11 | | ApiNATOMY model of the spleen | splen:spleen | 580 | 47 | 103 | 5 | 5 | 5 | 5 | 8 | | Total unique | 8 | 8761 | 717 | 823 | 296 | 115 | 114 | 114 | 181 | #+RESULTS: apinat-dashboard-overview | element | count | |-----------------+-------| | models | 8 | | models scigraph | 8 | | lyphs | 8761 | | lyphs input | 717 | | externals | 583 | | publications | 296 | | nerus | 115 | | neupops | 114 | | neupops pattern | 114 | # TODO links to a way to view the terms per ontology if possible #+RESULTS: sparql-apinat-prefixes | prefix | count | |---------+-------| | nlx | 1 | | CL | 3 | | GO | 5 | | NCIT | 5 | | CHEBI | 11 | | sao | 11 | | fma | 15 | | tgbugs | 114 | | ilx | 179 | | UBERON | 239 | | :SUM: | 583 | | :TOTAL: | 583 | #+header: :var n-sparql-apinat-graphs=n-sparql-apinat-graphs() #+header: :var cypher-apinat-models=cypher-apinat-models() #+header: :var n-sparql-apinat-lyphs=n-sparql-apinat-lyphs() #+header: :var n-sparql-apinat-lyphs-input=n-sparql-apinat-lyphs-input() #+header: :var n-sparql-apinat-external=n-sparql-apinat-external() #+header: :var n-sparql-apinat-publications=n-sparql-apinat-publications() #+header: :var n-apinat-nerus=n-apinat-nerus() #+header: :var n-apinat-neupops=n-apinat-neupops() #+header: :var n-apinat-neupops-pat=n-apinat-neupops-pat() #+name: apinat-dashboard-overview #+begin_src elisp :exports results (let ((models (caar n-sparql-apinat-graphs)) (models-cypher (length cypher-apinat-models)) (lyphs (caar n-sparql-apinat-lyphs)) (lyphs-input (caar n-sparql-apinat-lyphs-input)) (externals (caar n-sparql-apinat-external)) (publications (caar n-sparql-apinat-publications)) (nerus (caar n-apinat-nerus)) (neupops (caar n-apinat-neupops)) (neupops-pat (caar n-apinat-neupops-pat))) (list (list "element" "count") 'hline (list "models" models) (list "models scigraph" models-cypher) (list "lyphs" lyphs) (list "lyphs input" lyphs-input) (list "externals" externals) (list "publications" publications) (list "nerus" nerus) (list "neupops" neupops) (list "neupops pattern" neupops-pat) )) #+end_src #+name: apinat-dashboard-model-summary #+begin_src sparql :noweb no-export select distinct ?label ?graph #?g ?lyphs ?lyphs_input #?links #?nodes #?chains #?coalescences ?externals ?publications #?groups ?nerus ?neupops ?neupops_pat ?somas <> #+end_src # TODO add the presence of the schematic svg and pdf to the dashboard # so we need to ingest the state of the repo during export # TODO dois for the published models # TODO open the folder in git # TODO open a linke to the ttl file # TODO open a link to the list of publications -> zenodo record # have to union over the aggregated group by results and the total # separately and then we can get the table to work correctly #+name: apinat-model-summary-where #+begin_src sparql :eval never WHERE { # ?model apinatomy:hasGraph ?graph # TODO broken conversion to literal instead of uri at the moment # sadly it seems that no one has managed to write an optimization that converts # into this form when querying multiple predicates in the same expression { ?graph a elements:Graph ; rdfs:label ?l . bind(str(?l) as ?label) # avoid issues with graphs loaded multiple times { select ?graph (count(distinct(?o)) as ?lyphs ) where { ?graph apinatomy:lyphs ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?lyphs_input ) where { ?graph apinatomy:lyphs ?o . filter not exists { ?o apinatomy:isTemplate true . } filter not exists { ?o apinatomy:generated true . } } group by ?graph } { select ?graph (count(distinct(?o)) as ?links ) where { ?graph apinatomy:links ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?nodes ) where { ?graph apinatomy:nodes ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?chains ) where { ?graph apinatomy:chains ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?coalescences) where { ?graph apinatomy:coalescences ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?externals ) where { ?graph apinatomy:ontologyTerms ?o . } group by ?graph } optional { select ?graph (count(distinct(?o)) as ?publications) where { ?graph apinatomy:references ?o . } group by ?graph } { select ?graph (count(distinct(?o)) as ?groups ) where { ?graph apinatomy:groups ?o . } group by ?graph } optional { select ?graph (count(distinct(?o)) as ?nerus ) where { ?graph apinatomy:groups ?o . ?o apinatomy:description ?d . filter(contains(str(?d), "dynamic")) } group by ?graph } optional { select ?graph (count(distinct(?o)) as ?neupops ) where { ?graph apinatomy:ontologyTerms ?o . ?o rdfs:subClassOf+ ilxtr:NeuronEBM . } group by ?graph } optional { select ?graph (count(distinct(?o)) as ?neupops_pat ) where { ?graph apinatomy:ontologyTerms ?o . filter contains(str(?o), "/neuron-type-") } group by ?graph } optional { select ?graph (count(distinct(?o)) as ?somas ) where { ?graph apinatomy:lyphs ?o . ?o apinatomy:ontologyTerms NLX:154731 . } group by ?graph } } union { { select (count(distinct(?graph_)) as ?graph ) where { ?graph_ a elements:Graph } } bind("Total unique" as ?label) { select (count(distinct(?o)) as ?lyphs ) where { ?graph_ apinatomy:lyphs ?o . } } { select (count(distinct(?o)) as ?lyphs_input ) where { ?graph_ apinatomy:lyphs ?o . filter not exists { ?o apinatomy:isTemplate true . } filter not exists { ?o apinatomy:generated true . } } } { select (count(distinct(?o)) as ?links ) where { ?graph_ apinatomy:links ?o . } } { select (count(distinct(?o)) as ?nodes ) where { ?graph_ apinatomy:nodes ?o . } } { select (count(distinct(?o)) as ?chains ) where { ?graph_ apinatomy:chains ?o . } } { select (count(distinct(?o)) as ?coalescences) where { ?graph_ apinatomy:coalescences ?o . } } { select (count(distinct(?o)) as ?externals ) where { ?graph_ apinatomy:ontologyTerms ?o . } } { select (count(distinct(?o)) as ?publications) where { ?graph_ apinatomy:references ?o . } } { select (count(distinct(?o)) as ?groups ) where { ?graph_ apinatomy:groups ?o . } } { select (count(distinct(?o)) as ?nerus ) where { ?graph_ apinatomy:groups ?o . ?o apinatomy:description ?d . filter(contains(str(?d), "dynamic")) } } optional { select (count(distinct(?o)) as ?neupops ) where { ?graph_ apinatomy:ontologyTerms ?o . ?o rdfs:subClassOf+ ilxtr:NeuronEBM . } } optional { select (count(distinct(?o)) as ?neupops_pat ) where { ?graph_ apinatomy:ontologyTerms ?o . filter contains(str(?o), "/neuron-type-") } } optional { select (count(distinct(?o)) as ?somas ) where { ?graph_ apinatomy:lyphs ?o . ?o apinatomy:ontologyTerms NLX:154731 . } } } } #+end_src **** Queries # aka dashboard queries ***** ApiNATOMY sourced ****** models #+name: n-sparql-apinat-graphs #+begin_src sparql :noweb no-export SELECT (COUNT(*) as ?count) { <> } #+end_src #+name: sparql-apinat-graphs #+begin_src sparql SELECT DISTINCT (?s as ?id) (str(?l) as ?label) WHERE { ?s a elements:Graph . ?s rdfs:label ?l. } #+end_src #+name: sparql-apinat-models #+begin_src sparql SELECT DISTINCT ?o (str(?l) as ?label) (str(?v) as ?version) WHERE { ?o a owl:Ontology ; rdfs:label ?l ; apinatomy:hasGraph ?g . ?g a elements:Graph . ?g apinatomy:version ?v . } #+end_src # FIXME we need a way to issue cypher queries that can return # something other than the graph results so that we can match # sparql unfortunately that is a larger engineering undertaking the # requires modifying scigraph again #+name: desc-cypher-apinat-graphs Return ApiNATOMY Graph resources and their associated Ontology resource. #+name: cypher-apinat-graphs #+begin_src cypher MATCH ({iri: "https://apinatomy.org/uris/elements/Graph"})<-[:type]-(g)<-[e:apinatomy:hasGraph]-(o:Ontology) RETURN g, e, o #+end_src #+name: desc-cypher-apinat-models Return the list of all ApiNATOMY models in the database. #+name: cypher-apinat-models #+begin_src cypher MATCH ({iri: "https://apinatomy.org/uris/elements/Graph"}) <-[:type]-(g)-[:isDefinedBy]->(o:Ontology) RETURN o #+end_src ****** number of lyphs #+name: n-sparql-apinat-lyphs #+begin_src sparql SELECT (COUNT(DISTINCT ?s) as ?total_lyphs) WHERE { ?s a elements:Lyph . } #+end_src #+RESULTS: n-sparql-apinat-lyphs | total_lyphs | |-------------| | 8162 | generated vs input s? rdf:type element:Lyph #+name: n-sparql-apinat-lyphs-input #+begin_src sparql :var limit="200" SELECT DISTINCT (COUNT(DISTINCT ?s) as ?input_lyphs) #?s #?p #?o WHERE { ?s a elements:Lyph . #?s ?p ?o . FILTER NOT EXISTS { ?s apinatomy:isTemplate true . } FILTER NOT EXISTS { ?s apinatomy:generated true . } #FILTER ( ! ( ?p = apinatomy:isTemplate && ?o = true ) ) #FILTER ( ! ( ?p = apinatomy:generated && ?o = true ) ) #?s apinatomy:generated ?o . } LIMIT ?limit #+end_src #+RESULTS: n-sparql-apinat-lyphs-input | input_lyphs | |-------------| | 742 | ****** publications referenced apinatomy:references average number of publications per unit? (for now no) will also want the full listing of publications select count distinct o? select distinct o? s? apinat:publication o? #+name: n-sparql-apinat-publications #+begin_src sparql SELECT DISTINCT (COUNT(DISTINCT ?pub) as ?publications) WHERE { ?s apinatomy:references ?pub . } #+end_src #+RESULTS: n-sparql-apinat-publications | publications | |--------------| | 293 | ****** TODO species both model level and lyph level ****** terms employed in annotation count of apinatomy:ontologyTerms by prefix UBERON, GO, CHEBI, etc. full listing of terms as well # sadly noweb is way faster for solving this problem than trying to do the right thing >_< #+name: apinat-search-prefixes : "UBERON" "EMAPA" "fma" "CHEBI" "GO" "sao" "CL" "nlx" "ilx" "tgbugs" "NCBITaxon" "NCIT" "pubmed" "doi" "ncit" #+name: sparql-apinat-prefixes #+begin_src sparql :noweb yes SELECT ?prefix (COUNT(DISTINCT ?s) AS ?count) WHERE { { VALUES ?prefix { <> } ?s a elements:OntologyTerm . FILTER CONTAINS(str(?s), ?prefix) } UNION { SELECT (":SUM:" AS ?prefix) ?s { VALUES ?pre { <> } ?s a elements:OntologyTerm . FILTER CONTAINS(str(?s), ?pre) } } UNION { BIND(":TOTAL:" AS ?prefix) { SELECT ?s WHERE { ?s a elements:OntologyTerm . } } } } GROUP BY ?prefix ORDER BY ?count #+end_src #+name: n-sparql-apinat-external #+begin_src sparql SELECT (COUNT(DISTINCT(?s)) as ?count) WHERE { ?s a elements:OntologyTerm . } #+end_src ******* external issues publications appearing as external ids, unmapped prefixes etc. FIXME where are these coming from? #+begin_src sparql :var limit="500" SELECT DISTINCT ?l ?s WHERE { ?s a elements:OntologyTerm . ?l ?p ?s . FILTER(CONTAINS(str(?s), "doi") || CONTAINS(str(?s), "pubmed") || CONTAINS(str(?s), "ncit")) } ORDER BY ?l ?s LIMIT ?limit #+end_src ****** Number of neurulated groups Total neuron populations including those that are unidentified or are in error # TODO by model #+name: n-apinat-nerus #+begin_src sparql :noweb yes SELECT (COUNT(*) as ?count) { <> } #+end_src #+RESULTS: n-apinat-nerus | count | |-------| | 117 | #+name: apinat-nerus #+begin_src sparql SELECT DISTINCT ?group (str(?l) as ?label) WHERE { ?group a elements:Group . ?group apinatomy:description ?d filter(contains(str(?d), "dynamic")) ?group rdfs:label ?l . } order by ?group #+end_src ****** Number of neuron populations with external ids and correct subClassOf. #+name: n-apinat-neupops #+begin_src sparql :noweb yes SELECT (COUNT(*) as ?count) { <> } #+end_src #+RESULTS: n-apinat-neupops | count | |-------| | 117 | #+name: apinat-neupops #+begin_src sparql SELECT DISTINCT ?neupop (str(?pl) as ?preferred_label) (str(?l) as ?label) WHERE { ?neupop a elements:OntologyTerm . ?neupop rdfs:subClassOf+ ilxtr:NeuronEBM . OPTIONAL { ?neupop skos:prefLabel ?pl . } OPTIONAL { ?neupop rdfs:label ?l . } } #+end_src ****** Number of neuron populations with external ids that match the =neuron-type= pattern. #+name: n-apinat-neupops-pat #+begin_src sparql :noweb yes SELECT (COUNT(*) as ?count) { <> } #+end_src #+RESULTS: n-apinat-neupops-pat | count | |-------| | 117 | #+name: apinat-neupops-pat #+begin_src sparql SELECT DISTINCT ?neupop (str(?pl) as ?preferred_label) (str(?l) as ?label) WHERE { ?neupop a elements:OntologyTerm . FILTER CONTAINS(str(?neupop), "/neuron-type-") OPTIONAL { ?neupop skos:prefLabel ?pl . } OPTIONAL { ?neupop rdfs:label ?l . } } #+end_src ***** NPO sourced queries Keast Bolser Lewis First pass NLP output ****** location experimental #+begin_src cypher :limit 99 :results drawer :wrap src json :var neupop_id="ilxtr:neuron-type-keast-2" MATCH (neuron:Class{iri: "http://uri.neuinfo.org/nif/nifstd/sao1417703748"})<-[:subClassOf*1..]- (neupop) //(neupop:Class{iri: $neupop_id}) -[e:ilxtr:hasLocationPhenotype!]->(blank) -[q]->(more) //-[q:BFO:0000050]->(more) RETURN e, q #+end_src ****** phenotypes for neuron #+name: npo-basic-phenotypes #+begin_src cypher :limit 99 :results drawer :wrap src json :var neupop_id="ilxtr:neuron-type-keast-2" MATCH (neupop:Class{iri: $neupop_id})-[e:ilxtr:hasPhenotype!]->(phenotype) RETURN e #+end_src #+begin_src jupyter-python :session pys :noweb yes from pprint import pprint from pyontutils.scigraph import Cypher, Vocabulary sgc = Cypher() query = """ <> """ def get_phenotypes(neupop_id): d = sgc.execute(query=query, limit=99999, output='application/json', neupop_id=neupop_id) good = [e for e in d['edges'] if 'meta' in e and e['meta']['owlType'] == ['subClassOf'] and not e['obj'].startswith('_:')] return good pprint(get_phenotypes('ilxtr:neuron-type-keast-1')) #+end_src ****** number of neuron populations aka neuron types # TODO load NPO, and we have to use robot to reason the NPO graph #+begin_src sparql SELECT DISTINCT ?s WHERE { ?s rdfs:subClassOf+ SAO:1813327414 . # NOTE this counts cells } #+end_src ****** basic connectivity ******* python #+begin_src jupyter-python :session pys from collections import defaultdict from pprint import pprint from neurondm.compiled.common_usage_types import * neurons = config.neurons() #pprint(neurons) #pprint(dir(neurons[0])) # pprint(neurons[0].edges) #pprint([n for n in neurons if ilxtr.hasSomaLocatedIn in n.edges][0]) #pprint([n for n in neurons if ilxtr.hasAxonLocatedIn in n.edges][0]) #pprint([n for n in neurons if ilxtr.hasAxonPresynapticElementIn in n.edges][0]) #pprint([n for n in neurons if ilxtr.hasDendriteLocatedIn in n.edges][0]) x = defaultdict(list) for n in neurons: for somar in [pe.p for pe in n.pes if pe.e == ilxtr.hasSomaLocatedIn]: for axonr in [pe.p for pe in n.pes if pe.e in (ilxtr.hasAxonPresynapticElementIn, ilxtr.hasProjectionPhenotype)]: # via may be incorrect here if an axon location applies only to one collateral for a terminal # this is why we need the partial order x[somar].append(axonr) pprint(dict(x)) # via axon pprint([n for n in neurons if ilxtr.hasAxonLocatedIn in n.edges][:1]) # axon terminal in apinatomy # region A is axonally forward connect to B forward here means soma -> axon terminal pprint([n for n in neurons if ilxtr.hasProjectionPhenotype in n.edges][:1]) pprint([n for n in neurons if ilxtr.hasAxonPresynapticElementIn in n.edges][:1]) # soma pprint([n for n in neurons if ilxtr.hasSomaLocatedIn in n.edges][:1]) pprint([n for n in neurons if ilxtr.hasSomaLocatedInLayer in n.edges][:1]) # via dendrite pprint([n for n in neurons if ilxtr.hasDendriteLocatedIn in n.edges][:1]) # dendrite terminal for sensory neurons in apinatomy # region A is dendritically forward connect to B forward here means dendrite terminal -> soma pprint([n for n in neurons if ilxtr.hasSensorySubcellularElementIn in n.edges][:1]) pprint([n for n in neurons if ilxtr.hasForwardConnectionPhenotype in n.edges][:1]) pprint([n for n in neurons if ilxtr.hasReverseConnectionPhenotype in n.edges][:1]) #pprint([n for n in neurons if EntailedPhenotype('UBERON:0002790', 'ilxtr:hasAxonLocatedIn') in n.pes ]) #pprint([n for n in neurons if ilxtr.hasSomaLocatedIn in n.edges]) #pprint([n for n in neurons if Phenotype('UBERON:0002610', 'ilxtr:hasSomaLocatedIn') in n.pes ]) #+end_src ******* cypher #+begin_src ttl :x a owl:Class ; owl:equivalentClass [ a owl:Restriction ; owl:intersectionOf ( [ a owl:Restriction ; owl:onProperty ilxtr:hasSomaLocatedIn ; owl:someValuesFrom [ a owl:Restriction ; owl:onProperty :partOf ; owl:someValuesFrom ?my-region ; ] ; ] ; ) ] #+end_src #+begin_src cypher :limit 10 :results drawer MATCH (neuron)-[e]-> // (blank)-[:ilxtr:hasPhenotype]->(phenotype) (blanka)-[:ilxtr:hasAxonLocatedIn]->(blankb)-[edge]->(region_or_blank) //(blanka)-[:ilxtr:hasSomaLocatedIn]->(blankb)-[:BFO:0000050]->(region_or_blank) // or_blank happens if it is a union of regions i.e. a population with somas in more than one region //,(region_or_blank: Class{iri: "UBERON:0001950"}) //RETURN region_or_blank //RETURN neuron RETURN edge #+end_src #+begin_src sparql select distinct ?p ?o where { # ilxtr:neuron-type-keast-1 ?p ?o ilxtr:neuron-type-keast-1 owl:equivalentClass ?b1 . ?b1 owl:intersectionOf ?b2 . ?b2 ?unkp ?b3 . # lists ?b3 owl:onProperty ?p . ?b3 owl:someValuesFrom ?o . } #+end_src #+begin_src sparql select distinct ?neuron ?prop ?value ?prop2 ?value2 # ?p ?ox # ?p2 ?o2 # ?p3 # ?o3 ?p4 ?o4 ?p5 ?o5 ?p6 ?o6 where { #ilxtr:neuron-type-keast-1 owl:equivalentClass ?o . ?neuron a owl:Class . ?neuron ilxtr:simpleLocalLabel ?sll . # XXX hack to filter for neurons ?neuron owl:equivalentClass ?o . # ?o ?p2 ?o2 . ?o owl:intersectionOf ?list . ?list rdf:rest*/rdf:first ?elem . # FIXME at least one elem subClassOf neuron or cell ?elem a owl:Restriction . ?elem owl:onProperty ?prop . ?elem owl:someValuesFrom ?value . OPTIONAL { ?value a owl:Restriction . ?value owl:onProperty ?prop2 . ?value owl:someValuesFrom ?value2 . # ?value ?p ?ox . #OPTIONAL { #?ox ?p2 ?o2 . #?o2 a owl:Class . #} } # then do optional for location vs other types #?o3 ?p4 ?o4 . #?o4 ?p5 ?o5 . # first on property hits here #?o5 ?p6 ?o6 . # TODO list optional ??? } limit 300 #+end_src #+begin_src cypher :results drawer MATCH path = (neuron) //MATCH path = (neuron:Class{iri: "ilxtr:neuron-type-keast-1"}) -[:equivalentClass|subClassOf]->(hrm) RETURN path #+end_src ****** number of distinct phenotypes ****** number of dimensions ****** number of phenotype values per phenotype dimension ******* number of anatomical regions ******* number of species ******* number of x * Extras :noexport: ** neru #+begin_src sparql select * where { ?s rdfs:subClassOf ilxtr:NeuronNerves } #+end_src *** neru-reduced for monqiue #+header: :limit 999999 :file ./images/neru-fm.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-5" #+name: neru-fm #+begin_src cypher MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK , (neugrp) -[:apinatomy:links]->(link_start) -[b:apinatomy:endsIn*0..1]->(lyph_or_layer) //-[:apinatomy:topology*0..1]->(top) , (neugrp) -[:apinatomy:links]->(link) //<-[c:apinatomy:bundles|apinatomy:endBundles]- -[c:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]-> (lyph_or_layer) // real lyphs convey things, layers do not -[d:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph , (lyph_or_layer) // FIXME WHERE ARE MY DENDRITES MOTHER FUCKER -[z:apinatomy:cloneOf*0..1]->() -[y:apinatomy:external|apinatomy:inheritedOntologyTerms*0..1]->(layer) , (lyph) -[e:apinatomy:external]->(region) , (link) // use apinatomy:next to extract ordering information -[f:apinatomy:next*0..]->() //-[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() // FIXME these should be collapsing into a single relationship -[g:apinatomy:target*0..1]->() -[h:apinatomy:rootOf*0..1]->() -[i:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) , p2 = (link) -[cle:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() , (cl) -[x:apinatomy:inheritedOntologyTerms*0..1]->() //WHERE top.iri IN ["https://apinatomy.org/uris/readable/BAG", "https://apinatomy.org/uris/readable/BAG2"] // publications WITH neugrp, a, b, c, d, e, f, g, h, i, x, y, z // p2 //, b OPTIONAL MATCH path = (neugrp) -[:apinatomy:publications]->(pub) -[:type]->(:Class{iri: "https://apinatomy.org/uris/elements/Publication"}) // cannot be curied, dynamic endpoints will not expand it RETURN a, b, c, d, e, f, g, h, i, path, x, y, z //, p2 UNION // this part usually only returns the soma housing lyph MATCH (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK -[b:apinatomy:lyphs]->(lyph) //<-[c:apinatomy:internalLyphs]-() -[c:apinatomy:internalIn]->() -[d:apinatomy:external*0..1]->(region) // this variant shows the dead end lyphs that correspond to the fasciculatesIn links above //-[c:apinatomy:internalIn*0..1]->() //-[d:apinatomy:external*0..1]->(region) RETURN a, b, c, d, null AS e, null AS f, null AS g, null AS h, null AS i, null AS path, null as x, null as y, null as z//, null as p2 #+end_src *** neru-explore # #+header: :results table :limit 1 #+header: :limit 999999 :file ./images/neru-4.svg :results file :exports both #+header: :var neupop_id="ilxtr:neuron-type-keast-5" #+name: cypher-neru-exp #+begin_src cypher MATCH p1 = (neupop:Class{iri: $neupop_id}) -[a:apinatomy:annotates]->(neugrp:NamedIndividual{`https://apinatomy.org/uris/readable/description`: "dynamic"}) // FIXME HACK , p2 = (neugrp) -[:apinatomy:links]->(link) -[:apinatomy:fasciculatesIn|apinatomy:endsIn*0..1]->(lyph_or_layer) // real lyphs convey things, layers do not -[:apinatomy:layerIn*0..1]->(lyph) -[:apinatomy:conveys*0..1]->() // make sure we are at a real lyph , p3 = (lyph) -[e:apinatomy:external]->(region) , p4 = (link) // use apinatomy:next to extract ordering information -[:apinatomy:next*0..]->() //-[f:apinatomy:next|apinatomy:nextChainStartLevels*0..]->() // FIXME these should be collapsing into a single relationship -[:apinatomy:target*0..1]->() -[:apinatomy:rootOf*0..1]->() -[:apinatomy:levels*0..1]->() <-[:apinatomy:links]-(neugrp) , p5 = (link) -[:apinatomy:conveyingLyph]->(cl) -[:apinatomy:topology]->() , p6 = (cl) -[:apinatomy:inheritedOntologyTerms*0..1]->() //, //p7 = (layer) //-[:apinatomy:layerIn:*0..1]->(lyph) // FIXME this is wrong it will bull in unrelated layers //, //p8 = (link) // TODO need a layer for th elinks too I think // XXX it turns out that neru-3 already has all the information we need????? RETURN p1, p2, p3, p4, p5, p6 #+end_src * Bootstrap :noexport: :PROPERTIES: :visibility: folded :END: # TODO consider automatically displaying the edit src buffer # in another window when the cursor is present and switching ????? # TODO need to extract my rdf related stuff out of init.el so that the uris compact # TODO use the context menus branch to make right click context sensitive in buffer #+name: orgstrap #+begin_src elisp :results none :exports none :lexical yes :noweb yes (defvar ow-do-packages-emacs t "Install Emacs packages.") (defvar ow-do-config-emacs t "Run code that modifies the Emacs configuration.") (setq org-agenda-file-menu-enabled nil) ; SIGH (unless (symbol-function 'org-assert-version) ;; sigh (defmacro org-assert-version () 't)) (when ow-do-config-emacs (setq inhibit-startup-screen t)) ;; FIXME somehow need to mkdir images, unfortunately mkdirp doesn't work for files ;; only for tangling ... maybe we should add it so that it works for :file results as well? ;; TODO ;;(defun orgstrap---advise-sparql-execute-query (&rest args) ;; (compactify-current-buffer default-curies)) ;;(advice-add #'sparql-execute-query :after #'orgstrap---advise-sparql-execute-query) <> (when ow-do-packages-emacs (ow-enable-use-package nil '(vterm zmq));) (let ((gt26 (>= emacs-major-version 26))) (let ((no-byte-compile t)) (ow-use-packages (org ;;:load-path "~/git/NOFORK/org-mode/lisp/" :mode ("\\.org\\'" . org-mode) :bind ("" . ow-babel-eval-closest-block) :init (defvar org-babel-tangle-lang-exts nil) ; XXX temp fix for bad init in ob-python.el and others (org-babel-do-load-languages 'org-babel-load-languages `((cypher . t) (sparql . t) (shell . t) (python . t) ,(when gt26 '(jupyter . t))))))) (ow-use-packages vterm csv-mode rainbow-delimiters orgstrap (when gt26 jupyter) (cypher-mode :init (defface cypher-pattern-face '((t :foreground "DeepPink" :background unspecified :bold t)) "Face for pattern struct." :group 'cypher-faces)) sparql-mode ob-cypher))) ;; somehow this gets around lexical scope FIXME no not really have to ;; modify the elvs (defun fix-ocbe-queries () ; FIXME LOL yeah name collisions DO happen and YES this is why I implemented `defvar-local' (setq-local org-confirm-babel-evaluate (lambda (lang body) ;;(message "%S" body) (not (or (member lang '("cypher" "sparql")) (and (string= lang "python") ; XXX THIS IS TO MAKE AUDITING EASIER YOU SHOULD AUDIT ALL safe-block declarations like this (string-prefix-p "# py-safe-block" body)) (and (string= lang "elisp") (string= body "(string-trim (replace-regexp-in-string \"\\n\" \"\" paragraph))"))))))) ;; run `fix-ocbe-queries' after a possible call to `ow-enable-use-package' since it can ;; unbind `org-confirm-babel-evaluate' (fix-ocbe-queries) (unless (fboundp #'ob-cypher/scigraph/query) (reval 'sha256 '06f8c20452b414792e9bbbad0c26b24d67f2098ba6c172543e0d1456f4e05f00 "https://raw.githubusercontent.com/tgbugs/ob-cypher/e4815bb45f3f009b58dd71dde30e9d232c76ae84/ob-cypher.el")) (unless (fboundp #'org-babel-sparql--table-replace-curies) (reval 'sha256 '62bdbaf3d54f16b5019715f1dd175ecda8b37de420d14bcb8a469ef6820c5386 "https://raw.githubusercontent.com/tgbugs/sparql-mode/62ee958fe5abb1212a351025abce522e53ef1fae/ob-sparql.el")) (defun json->svg-file (json-string path) ; FIXME `defun-local' may not work with `ow-babel-eval' (let* ((tmp (org-babel-temp-file "cypher-dot-")) (dot (ob-cypher/scigraph/json-to-dot json-string)) (cmd (cond ((string= (file-name-extension path) "gml") (format "gv2gml %s -o %s" tmp path)) ((string= (file-name-extension path) "graphml") (format "dot2graphml %s %s" tmp path)) (t (format (concat "dot " "-Efontname='Dejavu Sans Mono' " "-Nfontname='Dejavu Sans Mono' " "-Grankdir=LR " "-T%s -o %s %s") (file-name-extension path) path tmp))))) (with-temp-file tmp (insert dot)) (org-babel-eval cmd "") path)) (defun literal (string) ; can't use `defun-local' due to loading via `find-file-noselect' "Utility function for sparql :vars that need to be escaped." (prin1-to-string string)) ;; see orgware.org for a longer note on noweb and empty lines (defun ow---strip-empty-lines () (save-excursion (goto-char (point-min)) (while (re-search-forward "^ +$" nil t) (replace-match "")))) (add-hook 'org-babel-tangle-body-hook #'ow---strip-empty-lines) ;; support for passing scigraph api keys via envars/secrets file ;; envars are here for convenience but should never be used in ;; practice mounting the secrets file is way more secure (unless (fboundp 'get-scicrunch-api-key) (defun get-scicrunch-api-key () (or (getenv "SCIGRAPH_API_KEY") (getenv "SCICRUNCH_API_KEY") (oa-path :scicrunch :api :key)))) ;; temporary backport of fixes for ol-man behavior until a new version of org-mode is released (require 'ol-man) (defun org-man-open (path _) "Visit the manpage on PATH. PATH should be a topic that can be thrown at the man command. If PATH contains extra ::STRING which will use `occur' to search matched strings in man buffer." (string-match "\\(.*?\\)\\(?:::\\(.*\\)\\)?$" path) (let* ((command (match-string 1 path)) (search (match-string 2 path)) (buffer (funcall org-man-command command))) (when search (with-current-buffer buffer (goto-char (point-min)) (unless (search-forward search nil t) (let ((process (get-buffer-process buffer))) (while (process-live-p process) (accept-process-output process))) (goto-char (point-min)) (search-forward search)) (forward-line -1) (let ((point (point))) (let ((window (get-buffer-window buffer))) (set-window-point window point) (set-window-start window point))))))) <> <> ;; command line interface (when noninteractive (ow-cli-gen ((edit) (visit) (file) (find-file) (tangle) (run) ; blockname (list) (blocks) (test) (config) (query) (neurons) (datasets) (protocols) (report) (organs) (apinat)) (cond ((or visit edit file find-file) (ow-find-file-new-process (buffer-file-name))) (tangle (let (enable-local-eval) ;; this pattern is required when tangling to avoid infinite loops (revert-buffer nil t nil) (setq-local find-file-literally nil)) (fix-ocbe-queries) (org-babel-tangle)) (report (when apinat (report-apinat)) (when organs (report-apinat)) ) (list (cond (blocks (let (blocks (lmax 0)) (org-babel-map-executables nil (let* ((elem (nth 1 (org-element-at-point))) (name (cl-getf elem :name)) (lang (cl-getf elem :language)) ; TODO #+call: (ll (length lang)) ) (when (> ll lmax) (setq lmax ll)) (when (and name (not (member name '("orgstrap" "orgstrap-shebang")))) (setq blocks (cons (list lang ll name) blocks))))) (setq lmax (1+ lmax)) (let ((padded (cl-loop for (l . (ll . (n . _))) in blocks collect (format "%s%s%s" l (make-string (- lmax ll) ?\s) n)))) (message "\n:blocks\n%s\n" (string-join (sort padded #'string<) "\n"))))))) (run (let ((blocks (cdr (member "run" argv)))) (message ":blocks %s" blocks) (cl-loop for block in blocks unless (member block '("orgstrap" "orgstrap-shebang")) ; no recurse ;; TODO FIXME we don't error on block name does not exist? ;; TODO forward output to stdout or something if an option is set? do (ow-babel-exec block nil 'error-on-fail)))) (test (cond (config (test-config)) (query (when neurons (test-neurons)) (when datasets (test-datasets)) (when protocols (test-protocols)) ))) ))) ;; note that we had to remove the call to `org-set-startup-visibility' ;; from the elvs in order to get this to work (when enable-local-eval ; FIXME HACK how to know when this was called ;; by the elvs? we don't want this running on a manual trigger (ignore-errors ; silence `org-fold-core-region' missing SPEC error (ow-hide-section-0-blocks)) (when ow-do-config-emacs (ow--rainy-day) (add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode) (ow-enable-config-familiar-1 'global))) ;; if we make it all the way through the block make sure that we don't ;; run the orgstrap elvs again so that that ocbe doesn't get klobbered (setq-local enable-local-eval nil) #+end_src #+name: reports #+begin_src elisp (defun report-apinat () (message "TODO apinat report") ) (defun report-organs () (message "TODO organs report") ) #+end_src #+name: tests #+begin_src elisp (defun test-config () (message "TODO test config") (ow-babel-eval "versions-sparql") (org-babel-goto-named-result "versions-sparql") (let ((start (point))) (org-forward-element) (message "%s" (buffer-substring-no-properties start (point)))) (ow-babel-eval "versions-cypher") (org-babel-goto-named-result "versions-cypher") (let ((start (point))) (org-forward-element) (message "%s" (buffer-substring-no-properties start (point)))) ) (defun test-neurons () (message "TODO test neurons") ) (defun test-datasets () (message "TODO test datasets") ) (defun test-protocols () (message "TODO test protocols") ) #+end_src #+name: reval-setup #+begin_src elisp ;; minimal reval (unless (featurep 'reval) (defvar reval-cache-directory (concat user-emacs-directory "reval/cache/")) (defun reval-minimal (cypher checksum path-or-url &rest alternates) "Simplified and compact implementation of reval." (let* (done (o url-handler-mode) (csn (symbol-name checksum)) (cache-path (concat reval-cache-directory (substring csn 0 2) "/" csn "-" (file-name-nondirectory path-or-url)))) (url-handler-mode) (unwind-protect (cl-loop for path-or-url in (cons cache-path (cons path-or-url alternates)) do (when (file-exists-p path-or-url) (let* ((buffer (find-file-noselect path-or-url)) (buffer-checksum (intern (secure-hash cypher buffer)))) (if (eq buffer-checksum checksum) (progn (unless (string= path-or-url cache-path) (let ((parent-path (file-name-directory cache-path)) make-backup-files) (unless (file-directory-p parent-path) (make-directory parent-path t)) (with-current-buffer buffer (write-file cache-path)))) (eval-buffer buffer) (setq done t)) (kill-buffer buffer) ; kill so cannot accidentally evaled (error "reval: checksum mismatch! %s" path-or-url)))) until done) (unless o (url-handler-mode 0))))) (defalias 'reval #'reval-minimal) (reval 'sha256 '3620321396c967395913ff19ce507555acb92335b0545e4bd05ec0e673a0b33b "https://raw.githubusercontent.com/tgbugs/orgstrap/300b1d5518af53d76d950097bcbcd7046cfa2285/reval.el")) (let ((ghost "https://raw.githubusercontent.com/tgbugs/orgstrap/")) (unless (featurep 'ow) (reval 'sha256 'b5f27e2ca406874307debdd311cd47f73b2ade2fd73b8c8f9834e1c724dc7053 ;;"~/git/orgstrap/ow.el" (concat ghost "b9fcad308e10ab2a0d4bf752dc510bb278bba689" "/ow.el"))) (unless (featurep 'blazegraph) (reval 'sha256 '8f54a319227ee6d9ca457ad77be955ba6b1a98a36564dbda61fa6892192afd51 ;;"~/git/orgstrap/services/blazegraph.el" (concat ghost "abb93f698d3cfeeea607856bec98ae1d6cfe39c9" "/services/blazegraph.el")))) #+end_src Tangle helper for bare paragraphs. #+name: nonl #+begin_src elisp :exports none :results value :var paragraph="" (string-trim (replace-regexp-in-string "\n" "" paragraph)) #+end_src ** Local Variables :ARCHIVE: # close powershell comment #> # Local Variables: # org-adapt-indentation: nil # org-edit-src-content-indentation: 0 # org-hide-emphasis-markers: t # eval: (progn (setq-local orgstrap-min-org-version "8.2.10") (let ((a (org-version)) (n orgstrap-min-org-version)) (or (fboundp #'orgstrap--confirm-eval) (not n) (string< n a) (string= n a) (error "Your Org is too old! %s < %s" a n))) (defun orgstrap-norm-func--dprp-1-0 (body) (let ((p (read (concat "(progn\n" body "\n)"))) (m '(defun defun-local defmacro defvar defvar-local defconst defcustom)) print-quoted print-length print-level) (cl-labels ((f (b) (cl-loop for e in b when (listp e) do (or (and (memq (car e) m) (let ((n (nthcdr 4 e))) (and (stringp (nth 3 e)) (or (cl-subseq m 3) n) (f n) (or (setcdr (cddr e) n) t)))) (f e))) p)) (prin1-to-string (f p))))) (unless (boundp 'orgstrap-norm-func) (defvar-local orgstrap-norm-func orgstrap-norm-func-name)) (defun orgstrap-norm-embd (body) (funcall orgstrap-norm-func body)) (unless (fboundp #'orgstrap-norm) (defalias 'orgstrap-norm #'orgstrap-norm-embd)) (defun orgstrap-org-src-coderef-regexp (_fmt &optional label) (let ((fmt org-coderef-label-format)) (format "\\([:blank:]*\\(%s\\)[:blank:]*\\)$" (replace-regexp-in-string "%s" (if label (regexp-quote label) "\\([-a-zA-Z0-9_][-a-zA-Z0-9_ ]*\\)") (regexp-quote fmt) nil t)))) (unless (fboundp #'org-src-coderef-regexp) (defalias 'org-src-coderef-regexp #'orgstrap-org-src-coderef-regexp)) (defun orgstrap--expand-body (info) (let ((coderef (nth 6 info)) (expand (if (org-babel-noweb-p (nth 2 info) :eval) (org-babel-expand-noweb-references info) (nth 1 info)))) (if (not coderef) expand (replace-regexp-in-string (org-src-coderef-regexp coderef) "" expand nil nil 1)))) (defun orgstrap--confirm-eval-portable (lang _body) (not (and (member lang '("elisp" "emacs-lisp")) (let* ((body (orgstrap--expand-body (org-babel-get-src-block-info))) (body-normalized (orgstrap-norm body)) (content-checksum (intern (secure-hash orgstrap-cypher body-normalized)))) (eq orgstrap-block-checksum content-checksum))))) (unless (fboundp #'orgstrap--confirm-eval) (defalias 'orgstrap--confirm-eval #'orgstrap--confirm-eval-portable)) (let (enable-local-eval) (vc-find-file-hook)) (let ((ocbe org-confirm-babel-evaluate) (obs (org-babel-find-named-block "orgstrap"))) (if obs (unwind-protect (save-excursion (setq-local orgstrap-norm-func orgstrap-norm-func-name) (setq-local org-confirm-babel-evaluate #'orgstrap--confirm-eval) (goto-char obs) (org-babel-execute-src-block)) (when (eq org-confirm-babel-evaluate #'orgstrap--confirm-eval) (setq-local org-confirm-babel-evaluate ocbe)) (ignore-errors (org-set-visibility-according-to-property))) (warn "No orgstrap block.")))) # End: