Find graph motifs using intuitive notation

Overview

d o t m o t i f

Find graph motifs using intuitive notation

PyPI Codecov


DotMotif is a library that identifies subgraphs or motifs in a large graph. It looks like this:

# Look for all motifs of the form,

# Neuron A excites B:
A -> B [type = "excitatory"]
# ...and B inhibits C:
B -> C [type = "inhibitory"]

Or like this:

TwitterInfluencer(person) {
    # An influencer has more than a million
    # followers and is verified.
    person.followers > 1000000
    person.verified = true
}

InfluencerAwkward(person1, person2) {
    # Two people who are both influencers...
    TwitterInfluencer(person1)
    TwitterInfluencer(person2)
    # ...where one follows the other, but...
    person1 -> person2
    # ...the other doesn't follow back
    person2 !> person1
}

# Search for all awkward twitter influencer
# relationships in the dataset:
InfluencerAwkward(X, Y)

Get Started

To follow along in an interactive Binder without installing anything, launch a Jupyter Notebook here:

Binder

If you have DotMotif, a NetworkX graph, and a curious mind, you already have everything you need to start using DotMotif:

from dotmotif import Motif, GrandIsoExecutor

executor = GrandIsoExecutor(graph=my_networkx_graph)

triangle = Motif("""
A -> B
B -> C
C -> A
""")

results = executor.find(triangle)

Parameters

You can also pass optional parameters into the constructor for the dotmotif object. Those arguments are:

Argument Type, Default Behavior
ignore_direction bool: False Whether to disregard direction when generating the database query
limit int: None A limit (if any) to impose on the query results
enforce_inequality bool: False Whether to enforce inequality; in other words, whether two nodes should be permitted to be aliases for the same node. For example, in A->B->C; if A!=C, then set to True
exclude_automorphisms bool: False Whether to return only a single example for each detected automorphism. See more in the documentation

For more details on how to write a query, see Getting Started.


Citing

If this tool is helpful to your research, please consider citing it with:

# https://doi.org/10.1038/s41598-021-91025-5
@article{Matelsky_Motifs_2021, 
    title={{DotMotif: an open-source tool for connectome subgraph isomorphism search and graph queries}},
    volume={11}, 
    ISSN={2045-2322}, 
    url={http://dx.doi.org/10.1038/s41598-021-91025-5}, 
    DOI={10.1038/s41598-021-91025-5}, 
    number={1}, 
    journal={Scientific Reports}, 
    publisher={Springer Science and Business Media LLC}, 
    author={Matelsky, Jordan K. and Reilly, Elizabeth P. and Johnson, Erik C. and Stiso, Jennifer and Bassett, Danielle S. and Wester, Brock A. and Gray-Roncal, William},
    year={2021}, 
    month={Jun}
}
Comments
  • Neuprint Executor - Labeling Edges by ROI

    Neuprint Executor - Labeling Edges by ROI

    Hi Jordan,

    Do you see an easy way to assign ROI labels to edges in the neuprint executor? Let's say I want to query something like this:

    A -> B [weight > 20, ROI == "CX"]
    A -> B [weight > 30, ROI == "CRE(L)"] 
    

    So basically, there are two things here—multigraphs, which you address already in the docs, and encoding edge ROIs. I wonder if that's rather a hard thing to do or not. The data should be there as neuprint-python fetch_synapse_connections returns something like this

        bodyId_pre  bodyId_post roi_pre roi_post  x_pre  y_pre  z_pre  x_post  y_post  z_post  confidence_pre  confidence_post
    0    792368888    754547386  PED(R)   PED(R)  14013  27747  19307   13992   27720   19313           0.996         0.401035
    1    792368888    612742248  PED(R)   PED(R)  14049  27681  19417   14044   27662   19408           0.921         0.881487
    2    792368888   5901225361  PED(R)   PED(R)  14049  27681  19417   14055   27653   19420
    ...
    

    According to this issue it looks like it's possible. My observation is that the physical location of a connection between two neurons is an important feature of a motif. Looking forward to hearing what you say.

    EDIT: Maybe an indirect way to support multiple edges between two nodes is by grouping edge attributes. Does something like this seem plausible. You are doing smth similar in the multigraph docs already: A -> B [synapse_count > 2]. But what exactly is synapse_count?

    A -> B [[weight >= 20, ROI == "CX"], [weight > 30, ROI == "CRE(L)"]]
    

    Best, Jakob

    enhancement cypher Neo4jExecutor NeuPrintExecutor 
    opened by jakobtroidl 9
  • Error on first query

    Error on first query

    Tried to run the query from the tutorial:

    motif = Motif("""
    # My Awesome Motif
    
    Nose_Cell -> Brain_Cell
    Brain_Cell -> Arm_Cell
    """)
    

    But got this error:

    FileNotFoundError                         Traceback (most recent call last)
    <ipython-input-1-3a88159c0a0c> in <module>
    ----> 1 import dotmotif
          2 import networkx
          3 
          4 motif = Motif("""
          5 # My Awesome Motif
    
    ~\anaconda3\lib\site-packages\dotmotif\__init__.py in <module>
         24 from networkx.algorithms import isomorphism
         25 
    ---> 26 from .parsers.v2 import ParserV2
         27 from .validators import DisagreeingEdgesValidator
         28 
    
    ~\anaconda3\lib\site-packages\dotmotif\parsers\v2\__init__.py in <module>
         11 
         12 
    ---> 13 dm_parser = Lark(open(os.path.join(os.path.dirname(__file__), "grammar.lark"), "r"))
         14 
         15 
    
    FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\xxxx\\anaconda3\\lib\\site-packages\\dotmotif\\parsers\\v2\\grammar.lark'
    
    bug parser install 
    opened by lix2k3 9
  • Filtering By Properties w/ Invalid Characters in the Name

    Filtering By Properties w/ Invalid Characters in the Name

    Hey There, I'm using dotmotif to query the neuPrint dataset and have found some of the neurons have properties that aren't accepted in the query string format e.g. 'AVLP(R)': True,

    Is there a way to still query w/ these params? I tried adding directly to the _node_constraints but that doesn't seem to work either e.g.

    motif._node_constraints['A']['AVLP(R)'] = {}
    motif._node_constraints['A']['AVLP(R)']['='] = [True]
    
    Variable `R` not defined (line 2, column 83 (offset: 156))
    "    WHERE B.status = "Traced" AND A.status = "Orphan" AND A.INP = True AND A.AVLP(R) = True"
    
    parser cypher 
    opened by simonwarchol 7
  • fix: weight edge attribute doesn't throw errors anymore (#127)

    fix: weight edge attribute doesn't throw errors anymore (#127)

    The edge attribute in the neuprint executor threw an error with the new JSON feature implementation. I also made the neuprint executor tests more rigorous.

    opened by jakobtroidl 3
  • Upgrade grandiso version to use limits and iterable

    Upgrade grandiso version to use limits and iterable

    In grandiso v1.1.0 and above, there is an optional limit argument to the find_motifs call which short-circuits motif counting if a certain number of valid mappings are found.

    Right now, NetworkX and GrandIso executors implement the dotmotif limit parameter by finding all motifs and then downselecting, which is super inefficient and lame. We could pretty substantially improve performance by supporting the GrandIso limit arg.

    A notable challenge: We perform an additional downselect after running grandiso (to double-check attribute filters). So we may need to store a list of mappings temporarily in order to backfill the results list if candidate mappings are filtered out.

    enhancement GrandIsoExecutor 
    opened by j6k4m8 2
  • Non-string ids not supported by Neo4jExecutor

    Non-string ids not supported by Neo4jExecutor

    Ingesting a NetworkX graph with integer ids results in an error: ValueError: Could not export graph: unsupported operand type(s) for +: 'int' and 'str'. It should be straightforward to handle integers, though A node can be any hashable Python object except None. Maybe just cast with repr.

    question Neo4jExecutor 
    opened by jtpdowns 2
  • Support n constraints on each edge value-operator pair

    Support n constraints on each edge value-operator pair

    Currently, the parser overwrites previous operators if it's redefined:

    A -> B [value<=5, value<=2]
    

    ...will yield a constraint operator of

    { "value": { "lte": 2.0 } }
    

    (i.e. overwriting the first rule).

    bug parser 
    opened by j6k4m8 2
  • Node- and edge-attribute support in DSL

    Node- and edge-attribute support in DSL

    Proposed syntax concepts:

    Nodes

    Inline maplike:

    Node1 { type="GABA", z<12 } -> Node2
    

    Pros:

    • Succinct

    Cons:

    • Possible duplication or conflicting attributes if map is included on multiple lines for the same node

    Postfix where-like:

    Node1 -> Node2 | Node1.type = "GABA", Node1.z < 12
    

    Pros:

    • Succinct

    Cons:

    • Possible duplication or conflicting attributes if attrs are included on multiple lines for the same node

    Footnote constraints

    Node1 -> Node2
    
    Node1.type = "GABA"
    Node1.z < 12
    

    Pros:

    • Reduces possibility of conflicting constraints
    • Clear syntax; can be standalone in its own macro

    Cons:

    • Linecount verbose
    • Decouples attributes from connectivity clauses

    Edges

    Inline maplike:

    A ->{type: "excitatory", neurotransmitter: "ACh"} B
    

    Pros:

    • Inline

    Cons:

    • Reduces clarity of language

    Postfix where-like:

    A -> B | [type: "excitatory", neurotransmitter: "ACh"]
    

    Pros:

    • Inline

    Cons:

    • Reduces clarity of language

    Infix maplike:

    A -[type: "excitatory", neurotransmitter: "ACh"]> B
    

    Pros:

    • Inline

    Cons:

    • Reduces clarity of language
    enhancement DSL 
    opened by j6k4m8 2
  • Add macro edge aliases

    Add macro edge aliases

    This adds support for complex edge constraints in macros:

    decreasing_edge_weights(a, b, c) {
        a -> b as ab
        b -> c as bc
        ab.weight > bc.weight
    }
    
    ...
    

    In increasing levels of challengingness:

    • [x] Add support for simple (edge-value) edge constraints in macros
    • [x] Add support for dynamic (edge-edge) edge constraints in macros
    • [x] Extend support for recursive calls to macros with simple constraints
    • [x] Extend support for recursive calls to macros with dynamic constraints
    • [x] Update documentation

    This fixes #110 and finishes work started in #119.

    enhancement DSL parser 
    opened by j6k4m8 1
  • Add edge aliasing and edge constraints

    Add edge aliasing and edge constraints

    This PR adds support for edge aliases (first described in #110) and comparisons between edge attributes with values and with other edges.

    This enables syntax like this:

    A -> B as ab
    B -> A as ba
    
    ab.weight > ba.weight
    
    • [x] Add support in the DSL
    • [x] Add support in the parser + transformer
    • [x] Add support in the executors:
      • [x] GrandIso
      • [x] NetworkX
      • [x] NeuPrint
      • [x] Neo4j

    I am going to push macro support in a separate PR, since this one is getting pretty lengthy already!

    enhancement DSL parser cypher Neo4jExecutor NetworkXExecutor NeuPrintExecutor GrandIsoExecutor 
    opened by j6k4m8 1
  • Add node attribute bracket syntax

    Add node attribute bracket syntax

    Adds support for "bracket" syntax for node attributes. An attribute like XYZ(ABC) or ABC DEF used to be disallowed because of illegal characters in the attribute name, particularly when using the "dot-attribute" notation:

    # broken:
    A -> B
    A.ABC DEF > 10
    

    The new syntax uses bracket-attribute notation to "escape" these names:

    # working:
    import dotmotif
    from dotmotif.executors.NeuPrintExecutor import NeuPrintExecutor
    
    HOSTNAME = "neuprint.janelia.org"
    DATASET = "hemibrain:v1.2.1"
    TOKEN = "[YOUR TOKEN HERE]"
    
    motif = dotmotif.Motif("""
    A -> B
    A['AVLP(R)'] = True
    """)
    
    E = NeuPrintExecutor(HOSTNAME, DATASET, TOKEN)
    
    E.find(motif, limit=2)
    

    Fixes #111.

    parser cypher Neo4jExecutor NeuPrintExecutor 
    opened by j6k4m8 1
  • Add Impossible Constraints validator

    Add Impossible Constraints validator

    We should be able to automatically catch things like this:

    A.type = 4
    A.type != 4
    

    Right now, we'll catch them in certain instances, but not when constraints are inherited from automorphisms (see #118). Getting smarter about this will likely improve runtime considerably.

    enhancement validator 
    opened by j6k4m8 0
  • Anonymous motif participants

    Anonymous motif participants

    Anonymous motif participants:

    A -> _hidden
    _hidden -> B
    

    Anonymous node participants in macros:

    two_hop(A, B) {
        A -> _i
        _i -> B
    }
    
    two_hop(neuron1, neuron2)
    
    
    
    enhancement DSL parser 
    opened by j6k4m8 0
Releases(v0.13.0)
asyncio (PEP 3156) Redis support

aioredis asyncio (PEP 3156) Redis client library. Features hiredis parser Yes Pure-python parser Yes Low-level & High-level APIs Yes Connections Pool

aio-libs 2.2k Jan 04, 2023
Toolkit for storing files and attachments in web applications

DEPOT - File Storage Made Easy DEPOT is a framework for easily storing and serving files in web applications on Python2.6+ and Python3.2+. DEPOT suppo

Alessandro Molina 139 Dec 25, 2022
Generate database table diagram from SQL data definition.

sql2diagram Generate database table diagram from SQL data definition. e.g. "CREATE TABLE ..." See Example below How does it works? Analyze the SQL to

django-cas-ng 1 Feb 08, 2022
MySQL database connector for Python (with Python 3 support)

mysqlclient This project is a fork of MySQLdb1. This project adds Python 3 support and fixed many bugs. PyPI: https://pypi.org/project/mysqlclient/ Gi

PyMySQL 2.2k Dec 25, 2022
Simple DDL Parser to parse SQL (HQL, TSQL, AWS Redshift, Snowflake and other dialects) ddl files to json/python dict with full information about columns: types, defaults, primary keys, etc.

Simple DDL Parser Build with ply (lex & yacc in python). A lot of samples in 'tests/. Is it Stable? Yes, library already has about 5000+ usage per day

Iuliia Volkova 95 Jan 05, 2023
Implementing basic MongoDB CRUD (Create, Read, Update, Delete) queries, using Python.

MongoDB with Python Implementing basic MongoDB CRUD (Create, Read, Update, Delete) queries, using Python. We can connect to a MongoDB database hosted

MousamSingh 4 Dec 01, 2021
Find graph motifs using intuitive notation

d o t m o t i f Find graph motifs using intuitive notation DotMotif is a library that identifies subgraphs or motifs in a large graph. It looks like t

APL BRAIN 45 Jan 02, 2023
SAP HANA Connector in pure Python

SAP HANA Database Client for Python A pure Python client for the SAP HANA Database based on the SAP HANA Database SQL Command Network Protocol. pyhdb

SAP 299 Nov 20, 2022
A tiny python web application based on Flask to set, get, expire, delete keys of Redis database easily with direct link at the browser.

First Redis Python (CRUD) A tiny python web application based on Flask to set, get, expire, delete keys of Redis database easily with direct link at t

Max Base 9 Dec 24, 2022
DBMS Mini-project: Recruitment Management System

# Hire-ME DBMS Mini-project: Recruitment Management System. 💫 ✨ Features Python + MYSQL using mysql.connector library Recruiter and Client Panel Beau

Karan Gandhi 35 Dec 23, 2022
dbd is a database prototyping tool that enables data analysts and engineers to quickly load and transform data in SQL databases.

dbd: database prototyping tool dbd is a database prototyping tool that enables data analysts and engineers to quickly load and transform data in SQL d

Zdenek Svoboda 47 Dec 07, 2022
PubMed Mapper: A Python library that map PubMed XML to Python object

pubmed-mapper: A Python Library that map PubMed XML to Python object 中文文档 1. Philosophy view UML Programmatically access PubMed article is a common ta

灵魂工具人 33 Dec 08, 2022
MySQL database connector for Python (with Python 3 support)

mysqlclient This project is a fork of MySQLdb1. This project adds Python 3 support and fixed many bugs. PyPI: https://pypi.org/project/mysqlclient/ Gi

PyMySQL 2.2k Dec 25, 2022
Anomaly detection on SQL data warehouses and databases

With CueObserve, you can run anomaly detection on data in your SQL data warehouses and databases. Getting Started Install via Docker docker run -p 300

Cuebook 171 Dec 18, 2022
PyRemoteSQL is a python SQL client that allows you to connect to your remote server with phpMyAdmin installed.

PyRemoteSQL Python MySQL remote client Basically this is a python SQL client that allows you to connect to your remote server with phpMyAdmin installe

ProbablyX 3 Nov 04, 2022
SpyQL - SQL with Python in the middle

SpyQL SQL with Python in the middle Concept SpyQL is a query language that combines: the simplicity and structure of SQL with the power and readabilit

Daniel Moura 853 Dec 30, 2022
Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions.

dataset: databases for lazy people In short, dataset makes reading and writing data in databases as simple as reading and writing JSON files. Read the

Friedrich Lindenberg 4.2k Jan 02, 2023
Google Sheets Python API v4

pygsheets - Google Spreadsheets Python API v4 A simple, intuitive library for google sheets which gets your work done. Features: Open, create, delete

Nithin Murali 1.4k Dec 31, 2022
PostgreSQL database access simplified

Queries: PostgreSQL Simplified Queries is a BSD licensed opinionated wrapper of the psycopg2 library for interacting with PostgreSQL. The popular psyc

Gavin M. Roy 251 Oct 25, 2022
A Pythonic, object-oriented interface for working with MongoDB.

PyMODM MongoDB has paused the development of PyMODM. If there are any users who want to take over and maintain this project, or if you just have quest

mongodb 345 Dec 25, 2022