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)
A framework based on tornado for easier development, scaling up and maintenance

turbo 中文文档 Turbo is a framework for fast building web site and RESTFul api, based on tornado. Easily scale up and maintain Rapid development for RESTF

133 Dec 06, 2022
Py2neo is a client library and toolkit for working with Neo4j from within Python

Py2neo Py2neo is a client library and toolkit for working with Neo4j from within Python applications. The library supports both Bolt and HTTP and prov

py2neo.org 1.2k Jan 02, 2023
a small, expressive orm -- supports postgresql, mysql and sqlite

peewee Peewee is a simple and small ORM. It has few (but expressive) concepts, making it easy to learn and intuitive to use. a small, expressive ORM p

Charles Leifer 9.7k Dec 30, 2022
Pystackql - Python wrapper for StackQL

pystackql - Python Library for StackQL Python wrapper for StackQL Usage from pys

StackQL Studios 6 Jul 01, 2022
Pure Python MySQL Client

PyMySQL Table of Contents Requirements Installation Documentation Example Resources License This package contains a pure-Python MySQL client library,

PyMySQL 7.2k Jan 09, 2023
A simple Python tool to transfer data from MySQL to SQLite 3.

MySQL to SQLite3 A simple Python tool to transfer data from MySQL to SQLite 3. This is the long overdue complimentary tool to my SQLite3 to MySQL. It

Klemen Tusar 126 Jan 03, 2023
Sample code to extract data directly from the NetApp AIQUM MySQL Database

This sample code shows how to connect to the AIQUM Database and pull user quota details from it. AIQUM Requirements: 1. AIQUM 9.7 or higher. 2. An

1 Nov 08, 2021
A simple python package that perform SQL Server Source Control and Auto Deployment.

deploydb Deploy your database objects automatically when the git branch is updated. Production-ready! ⚙️ Easy-to-use 🔨 Customizable 🔧 Installation I

Mert Güvençli 10 Dec 07, 2022
A CRUD and REST api with mongodb atlas.

Movies_api A CRUD and REST api with mongodb atlas. Setup First import all the python dependencies in your virtual environment or globally by the follo

Pratyush Kongalla 0 Nov 09, 2022
Pure-python PostgreSQL driver

pg-purepy pg-purepy is a pure-Python PostgreSQL wrapper based on the anyio library. A lot of this library was inspired by the pg8000 library. Credits

Lura Skye 11 May 23, 2022
A pandas-like deferred expression system, with first-class SQL support

Ibis: Python data analysis framework for Hadoop and SQL engines Service Status Documentation Conda packages PyPI Azure Coverage Ibis is a toolbox to b

Ibis Project 2.3k Jan 06, 2023
A Python DB-API and SQLAlchemy dialect to Google Spreasheets

Note: shillelagh is a drop-in replacement for gsheets-db-api, with many additional features. You should use it instead. If you're using SQLAlchemy all

Beto Dealmeida 185 Jan 01, 2023
Asynchronous Python client for InfluxDB

aioinflux Asynchronous Python client for InfluxDB. Built on top of aiohttp and asyncio. Aioinflux is an alternative to the official InfluxDB Python cl

Gustavo Bezerra 159 Dec 27, 2022
MariaDB connector using python and flask

MariaDB connector using python and flask This should work with flask and to be deployed on docker. Setting up stuff 1. Docker build and run docker bui

Bayangmbe Mounmo 1 Jan 11, 2022
Dlsite-doujin-renamer - Dlsite doujin renamer tool with python

dlsite-doujin-renamer Features 支持深度查找带有 RJ 号的文件夹 支持手动选择文件夹或拖拽文件夹到软件窗口 支持在 config

111 Jan 02, 2023
DataStax Python Driver for Apache Cassandra

DataStax Driver for Apache Cassandra A modern, feature-rich and highly-tunable Python client library for Apache Cassandra (2.1+) and DataStax Enterpri

DataStax 1.3k Dec 25, 2022
#crypto #cipher #encode #decode #hash

🌹 CYPHER TOOLS 🌹 Written by TMRSWRR Version 1.0.0 All in one tools for CRYPTOLOGY. Instagram: Capture the Root 🖼️ Screenshots 🖼️ 📹 How to use 📹

50 Dec 23, 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
google-cloud-bigtable Apache-2google-cloud-bigtable (🥈31 · ⭐ 3.5K) - Google Cloud Bigtable API client library. Apache-2

Python Client for Google Cloud Bigtable Google Cloud Bigtable is Google's NoSQL Big Data database service. It's the same database that powers many cor

Google APIs 39 Dec 03, 2022
Query multiple mongoDB database collections easily

leakscoop Perform queries across multiple MongoDB databases and collections, where the field names and the field content structure in each database ma

bagel 5 Jun 24, 2021