Cytoscape (desktop application): select all neighbour nodes connected by edge with a given attribute - cytoscape

I have a node N and i need to get all of it's first neighbours (pretty much like Select -> Select first neighbours), however, i need only such neighbours that are connected by a specific edge type (edge with specific attribute).
In Cypher, it would look like this (in a case of the N is Tom Hanks and the edge type is ACTED_IN):
MATCH (n:Person)-[r:ACTED_IN]->(n2) WHERE n.name = "Tom Hanks" return n, r, n2

As simple as the task:
1) select node N you want to work with,
2) click Filter in side menu, then Chain card,
3) Set the following chain:
Start with: Current situation
add Node adjacency Transformer
Take nodes and add and adjacent nodes and edges, where the adjacent edges match the filter:
Edge: edge_type and contains wanted type ACTED_IN.
Works fine.

Related

Is it possible to fine tune the RETURN statement to skip edges between nodes of a particular type?

I have a query of that looks something like this:
MATCH (a:Y {uid:42})-[r]-(b:X)-[:SUB_CLASS_OF*0..]->(:X {name:"node_of_interest"} )
RETURN a, r, b
The issue I am having is that the nodes that match node2 tend to have LOTS of edges between them. I would like to get the links between node a (type Y) and node(s) that match b (type X), but not the edges between the different nodes that match b.
So to further clarify, lets say there is a single match for a and b matches three nodes (lets call them b1, b2, b3) I would like to return a subgraph, that has the edges between (a-b1), (a-b2) and (a-b3) but not (b1-b2), (b1-b3) and (b2-b3).
Is this possible?
EDIT: added more information and tried to clarify the code as well as what is needed.

Cypher: Get Nodes with ONLY incoming or ONLY outgoing Edges (Start Nodes / End Nodes)

Iam searching for the right cypher query to get the first and last nodes of paths when selecting a node which is in between. The idea is to compress a large impact graph so that only the sources (only outgoing edges = green nodes) and the final consequences (only incoming edges = red nodes) as well as the selected node is displayed.
Here is an illustrative example graph:
Now, when selecting e.g node d, i would like to receive node d and the first node and last node of every path in which node d is part of as well as the respective (new) relationships so that the output is the follwing graph:
Hence, Iam searching for a kind of collapsing where the start and end nodes are excluded.
Due to this answer I already know that is possible to create virtual graphs with apoc.create.vRelationship.
But Iam struggling with the identification of the green start nodes and red end nodes as described above as well as the creation of the desired output.
Iam searching for a query where only the node in between (e.g node d) is a parameter and the output is always like in the second image.
I appreciate every help or inspiration a lot, thank you in advance!
For your illustrated data model (assuming the desired middle node is neither the start nor end node):
MATCH (start)-[:RELATED_TO*]->(middle)-[:RELATED_TO*]->(end)
WHERE
middle.id = 123 AND
NOT EXISTS(()-[:RELATED_TO]->(start)) AND
NOT EXISTS((end)-[:RELATED_TO]->())
RETURN start, middle, end,
apoc.create.vRelationship(start, 'RELATED_TO', {}, middle) as pre_rel,
apoc.create.vRelationship(middle, 'RELATED_TO', {}, end) as post_rel
[UPDATE]
The above query can, unfortunately, create duplicate virtual relationships. This one does not:
MATCH (middle)
WHERE middle.id = 123
MATCH (start)-[:RELATED_TO*]->(middle)
WHERE NOT EXISTS(()-[:RELATED_TO]->(start))
WITH middle, COLLECT(start) AS starts, COLLECT(apoc.create.vRelationship(start, 'RELATED_TO', {}, middle)) AS vr1s
MATCH (middle)-[:RELATED_TO*]->(end)
WHERE NOT EXISTS((end)-[:RELATED_TO]->())
RETURN middle, starts, COLLECT(end) AS ends, vr1s, COLLECT(apoc.create.vRelationship(middle, 'RELATED_TO', {}, end)) AS vr2s
NOTE: You also need to uncheck the "Connect result nodes" option in the Browser Settings (click on the Gear icon in the Browser's left panel), or else some "real" relationships will also be displayed.
This query would return node d (filtering here by a name property just as an example) and all related edge nodes:
MATCH (d {name: "d"})-[:RELATED_TO*]-(n)
WHERE NOT ((n)-[:RELATED_TO]->() AND (n)<-[:RELATED_TO]-())
RETURN d, n
The condition for the edge nodes would be that they don't have :RELATED_TO relationships in both directions.

Finding all subtrees of nodes with a common second level relationship

I am working with bill of materials (BOM) and part data in a Neo4J database.
There are 3 types of nodes in my graph:
(ItemUsageInstance) these are the elements of the bill of materials tree
(Item) one exists for each unique item on the BOM tree
(Material)
The relationships are:
(ItemUsageInstance)-[CHILD_OF]->(ItemUsageInstance)
(ItemUsageInstance)-[INSTANCE_OF]->(Item)
(Item)-[MADE_FROM]->(Material)
The schema is pictured below:
Here is a simplified picture of the data. (Diagram with nodes repositioned to enhance visibility):
What I would like to do is find subtrees of adjacent ItemUsageInstances whose Itemss are all made from the same Materials
The query I have so far is:
MATCH (m:Material)
WITH m AS m
MATCH (m)<-[:MADE_FROM]-(i1:Item)<-[]-(iui1:ItemUsageInstance)-[:CHILD_OF]->(iui2:ItemUsageInstance)-[]->(i2:Item)-[:MADE_FROM]->(m) RETURN iui1, i1, iui2, i2, m
However, this only returns one such subtree, the adjacent nodes in the middle of the graph that have a common Material of "M0002". Also, the rows of the results are separate entries, one for each parent-child pair in the subtree:
╒══════════════════════════╤══════════════════════╤══════════════════════════╤══════════════════════╤═══════════════════════╕
│"iui1" │"i1" │"iui2" │"i2" │"m" │
╞══════════════════════════╪══════════════════════╪══════════════════════════╪══════════════════════╪═══════════════════════╡
│{"instance_id":"inst5002"}│{"part_number":"p003"}│{"instance_id":"inst7003"}│{"part_number":"p004"}│{"material_id":"M0002"}│
├──────────────────────────┼──────────────────────┼──────────────────────────┼──────────────────────┼───────────────────────┤
│{"instance_id":"inst7002"}│{"part_number":"p003"}│{"instance_id":"inst7003"}│{"part_number":"p004"}│{"material_id":"M0002"}│
├──────────────────────────┼──────────────────────┼──────────────────────────┼──────────────────────┼───────────────────────┤
│{"instance_id":"inst7001"}│{"part_number":"p002"}│{"instance_id":"inst7002"}│{"part_number":"p003"}│{"material_id":"M0002"}│
└──────────────────────────┴──────────────────────┴──────────────────────────┴──────────────────────┴───────────────────────┘
I was expecting a second subtree, which happens to also be a linked list, to be included. This second subtree consists of ItemUsageInstances inst7006, inst7007, inst7008 at the far right of the graph. For what it's worth, not only are these adjacent instances made from the same Material, they are all instances of the same Item.
I confirmed that every ItemUsageInstance node has an [INSTANCE_OF] relationship to an Item node:
MATCH (iui:ItemUsageInstance) WHERE NOT (iui)-[:INSTANCE_OF]->(:Item) RETURN iui
(returns 0 records).
Also confirmed that every Item node has a [MADE_FROM] relationship to a Material node:
MATCH (i:Item) WHERE NOT (i)-[:MADE_FROM]->(:Material) RETURN i
(returns 0 records).
Confirmed that inst7008 is the only ItemUsageInstance without an outgoing [CHILD_OF] relationship.
MATCH (iui:ItemUsageInstance) WHERE NOT (iui)-[:CHILD_OF]->(:ItemUsageInstance) RETURN iui
(returns 1 record: {"instance_id":"inst7008"})
inst5000 and inst7001 are the only ItemUsageInstances without an incoming [CHILD_OF] relationship
MATCH (iui:ItemUsageInstance) WHERE NOT (iui)<-[:CHILD_OF]-(:ItemUsageInstance) RETURN iui
(returns 2 records: {"instance_id":"inst7001"} and {"instance_id":"inst5000"})
I'd like to collect/aggregate the results so that each row is a subtree. I saw this example of how to collect() and got the array method to work. But it still has duplicate ItemUsageInstances in it. (The "map of items" discussed there failed completely...)
Any insights as to why my query is only finding one subtree of adjacent item usage instances with the same material?
What is the best way to aggregate the results by subtree?
Finding the roots is easy. MATCH (root:ItemUsageInstance) WHERE NOT ()-[:CHILD_OF]->(root)
And for the children, you can include the root by specifying a min distance of 0 (default is 1).
MATCH p=(root)-[:CHILD_OF*0..25]->(ins), (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(ins)
And then assuming only one item-material per instance, aggregate everything based on material (You can't aggregate in an aggregate, so use WITH to get the depth before collecting the depth with the node)
WITH ins, SIZE(NODES(p)) as depth, m RETURN COLLECT({node:ins, depth:depth}) as instances, m as material
So, all together
MATCH (root:ItemUsageInstance),
p=(root)<-[:CHILD_OF*0..25]-(ins),
(m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(ins)
WHERE NOT ()<-[:CHILD_OF]-(root)
AND NOT (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-()<-[:CHILD_OF]-(ins)
MATCH p2=(ins)<-[:CHILD_OF*1..25]-(cins)
WHERE ALL(n in NODES(p2) WHERE (m)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(n))
WITH ins, cins, SIZE(NODES(p2)) as depth, m ORDER BY depth ASC
RETURN ins as collection_head, ins+COLLECT(cins) as instances, m as material
In your pattern, you don't account for situations like the link between inst_5001 and inst_7001. Inst_5001 doesn't have any links to any part usages, but your match pattern requires that both usages have such a link. I think this is where you're going off track. The inst_5002 tree you're finding because it happens to have a link to an usage as your pattern requires.
In terms of "aggregating by subtree", I would return the ID of the root of the tree (e.g. id(iui1) and then count(*) the rest, to show how many subtrees a given root participates in.
Here is my heavily edited query:
MATCH path = (cinst:ItemUsageInstance)-[:CHILD_OF*1..]->(pinst:ItemUsageInstance), (m:Material)<-[:MADE_FROM]-(:Item)<-[:INSTANCE_OF]-(pinst)
WHERE ID(cinst) <> ID(pinst) AND ALL (x in nodes(path) WHERE ((x)-[:INSTANCE_OF]->(:Item)-[:MADE_FROM]->(m)))
WITH nodes(path) as insts, m
UNWIND insts AS instance
WITH DISTINCT instance, m
RETURN collect(instance), m
It returns what I was expecting:
╒═════════════════════════════════════════════════════════════════════════════════════════════════════════════╤═══════════════════════╕
│"collect(instance)" │"m" │
╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════╪═══════════════════════╡
│[{"instance_id":"inst7002"},{"instance_id":"inst7003"},{"instance_id":"inst7001"},{"instance_id":"inst5002"}]│{"material_id":"M0002"}│
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│[{"instance_id":"inst7007"},{"instance_id":"inst7008"},{"instance_id":"inst7006"}] │{"material_id":"M0001"}│
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────┘
The one limitation is that it does not distinguish the root of the subtree from the children. Ideally the list of {"instance_id"} would be sorted by depth in the tree.

Cypher Query - return nodes of a tier 2 relationship that are related to 2 or more indirect nodes

Unsure of how best to word this - in the below diagram
I am trying to return all nodes where the 2nd tier node is related to 2 or more of the 1st tier nodes, but only where the first tier nodes are different. So in the example picture I want to return grey node 660082, green node 110258, and all the pink nodes & relationships that are related to it. I do not want to see, for example, green nodes where pink nodes have 2 relationships to the same green node. so far my cypher looks like this
MATCH (i:IFB_Flagged)-[r]->(m:Matters)<-[r2]-(ie:Indirect_Entity)
WITH i, ie,r, collect(m) AS overlap
WHERE size(overlap) > 1 and i.id = '660082'
RETURN i, ie, overlap
This does appear to work as it filters out pink nodes that have only one link to a green node, however I can't figure out how to only return pink nodes where the related green nodes are not the same node
UPDATE
When adding a distinct to the collect & removing the where clause entirely I get a completely different graph, however it is actually closer to what I want to show
I still want to see all pink nodes that relate to more than one green node - however I do not want to see the pink nodes that only relate to one green node (the 6 pink nodes at the bottom left of the screen)
Here is my Cypher - I am not sure why collect(distinct m) doesn't work in this case?
MATCH (i:IFB_Flagged)-[r]->(m:Matters)<-[r2]-(ie:Indirect_Entity)
WITH i, ie,r, collect(distinct m) AS overlap
WHERE i.id = '385886'
RETURN i, ie, overlap limit 20
Use the DISTINCT keyword for collect (docs):
The DISTINCT operator works in conjunction with aggregation. It is used to make all values unique before running them through an aggregate function.
Also, you can move the check for id inside the MATCH clause for conciseness.
Update. Try this.
MATCH (i:IFB_Flagged)-[r]->(m:Matters)<-[r2]-(ie:Indirect_Entity)
WHERE i.id = '385886'
WITH i, ie, collect(distinct m) AS overlap
WHERE size(overlap) > 1
RETURN i, ie, overlap
LIMIT 20

Neo4J / Cypher Match subtrees of choices to identify valid outcomes

Given a Neo4J graph that represents potential choices (the Green nodes represent potential choices in the picture below) Only certain choices are valid - indicated with a valid outcome of having all leaf nodes in the choice path being orange.
I would like to identify paths (series of choices (and associated nodes)) from the yellow start node where all Leaf Nodes (to an arbitrary depth) are orange. The graph is directed and whether a node is blue or green is saved as a node property.
Blue and Orange Nodes may be shared between choices (ie an orange node may not necessarily have degree = 1)
Given the graph in the figure I would like the following returned …
Yellow -> A -> E
A -> G
Yellow -> C -> M
This is a more complicated extension of my earlier question...
Neo4J - count outermost nodes
You can use the predicate ALL to search for appropriate nodes:
MATCH (Y {color: 'Yellow'}) WITH Y
MATCH (G {color: 'Green'})-->(O)
WITH Y,
G,
ALL(color IN COLLECT(O.color) WHERE color = 'Orange') AS valid
WHERE valid = TRUE
MATCH path = (Y)-[*]->(G)
RETURN path

Resources