Filtering disconnected nodes in vis.js - vis.js

I've got a network backed by DataSets containing my nodes and edges. The edges are weighted, and I want to add the ability to hide edges, and their corresponding nodes, that fall below some threshold. I can easily filter the edges using a DataView, but want to know how to find nodes that no longer have an edge associated with them and hide them as well. Any hints?

I actually figured out a slick way to do it. After I update the edgeView as described above, I do this:
nodeView = new vis.DataView(nodes, {
filter: function(node) {
connEdges = edgeView.get({
filter: function(edge) {
return(
(edge.to == node.id) || (edge.from == node.id));
}});
return connEdges.length > 0;
}
});
Works like a charm.

One way would be to loop over the nodes, and for each node, loop over all edges to see if there is at least one edge which has this node's id as it's from or to property.

Related

How to get visible nodes with Visjs

I have this large network created with vis-network:
When clicking on the nodes I create clusters. For example if I click on the 2 green boxes the result is:
In this new view I have two regular nodes ("Program #3289" and "Task #7300") and two clusters ("Project #3415" and "Project #3416") that contain their children.
If I use dataset.get() it returns all my 106 initial nodes.
If I use network.body.nodes it returns all my 106 initial nodes + my two clusters.
What I want: a way to only get the visible nodes in my network. In that case, I should get only 2 regular nodes and 2 clusters.
Did I miss a function that permits to do it?
Thank you
I finally came up with the below solution:
var visibleNodes = [];
for (var nodeId in visNetwork.body.nodes) {
// we check if the node is inside a cluster
if (!visNetwork.clustering.clusteredNodes[nodeId]) {
visibleNodes.push(nodeId)
}
}

How to traverse all vertex and get nested objects

I want to get nested objects in the form of
{ country :
{code:'IN',states:
{code:'TG',cities:
{code:'HYD',malls:
{[shopping-mall1],[shopping-mall2],.....}
},
{code:'PKL',malls:
{[shopping-mall1],[shopping-mall2],.....}
}
},
{code:'AP',cities:
{code:'VJY',malls:
{[shopping-mall1],[shopping-mall2],.....}
}
}
}
}
MY graph is in format
vertex: country ---> states ---->cities ---> mallls
edges: (type:'state') ('type','city')
ex: inE('typeOf').outV().has('type','state') move to next vertex "states".
next same inE('typeOf').outV().has('type','city') moves to "city" vertex. then "malls" vertex .
And tired to write the code, some vertex has no cities i have an error that situavation."
error
The provided traverser does not map to a value: v[8320]->[JanusGraphVertexStep(IN,[partOf],vertex), HasStep([type.eq(city)]), JanusGraphPropertiesStep([code],value)]
Thats why i am using coalesce because some state has not an edge 'inE('partOf').outV().has('type','city')' means no city
.by(coalesce(select('states').inE('partOf').outV().has('type','city'))
My query
g.V().hasLabel('Country').has('code','IN')
.project('country')
.by(project('code','states')
.by(values('code'))
.by(inE('partOf').outV().has('type','state').has('code').as('states').
project('code','cities')
.by(select('states').values('code'))
.by(coalesce(select('states').inE('partOf').outV().
has('type','city').has('code').as('cities').
project('code','malls')
.by(select('cities').values('code'))
.by(coalesce(select('cities').inE('partOf').outV().
has('type','malls').valueMap(),constant(0))),
constant(0)))))
But the result is
{country={code=IN, states={code=DD, cities=0}}}
here i am getting one state 'DD' and that state is no city,so it gives 'cities = 0".
the above result is only one state is coming, i want all states, cities and malls in each city.
Please update query or change query
In order to collect all the results you should use .fold() traversal which returns a list of the collected traversals. without fold you will get only the first traversal like in your example.
In order to keep the types the same I changed the constant to [] instead of 0.
It was also not clear if the "type" property is on the edge or the vertex. I find it more appropriate to have it on the edge, so I fixed it as well by moving the has('type',...) between the inE() and outV().
Last, you don't need to "store" the traversal using "as" and then "select" it.
This query should give you the required result:
g.V().hasLabel('Country').has('code','IN')
.project('country')
.by(project('code','states')
.by(values('code'))
.by(inE('partOf').has('type','state').outV().has('code')
.project('code','cities')
.by(values('code'))
.by(coalesce(inE('partOf').has('type','city').outV().has('code')
.project('code','malls')
.by(values('code'))
.by(coalesce(
inE('partOf').has('type','malls').outV().valueMap(),
constant([])).fold()),
constant([])).fold())
.fold()))

Gremlin graph traversal backtracking

I have some code that generates gremlin traversals dynamically based on a query graph that a user supplies. It generates gremlin that relies heavily on backtracking. I've found some edge cases that are generating gremlin that doesn't do what I expected it to, but I also can't find anything online about the rules surrounding the usage of some of these pipes (like 'as' and 'back' in this case). An example of one of these edge cases:
g.V("id", "some id").as('1').inE("edgetype").outV.has("#class", "vertextype").as('2').inE("edgetype").outV.has("#class", "vertextype").filter{(it.getProperty("name") == "Bob")}.outE("edgetype").as('target').inV.has("id", "some id").back('2').outE("edgetype").inV.has("id", "some other id").back('target')
The goal of the traversal is to return the edges that were 'as'd as 'target'. When I run this against my orientdb database it encounters a null exception. I narrowed down the exception to the final pipe in the traversal: back('target'). I'm guessing that the order of the 'as's and 'back's matters and that the as('target') went 'out of scope' as soon as back('2') was executed. So a few questions:
Is my understanding (that 'target' goes out of scope because I backtracked to before it was 'as'd) correct?
Is there anywhere I can learn the rules surrounding backtracking without having to reverse engineer the gremlin source?
edit:
I found the relevant source code:
public static List<Pipe> removePreviousPipes(final Pipeline pipeline, final String namedStep) {
final List<Pipe> previousPipes = new ArrayList<Pipe>();
for (int i = pipeline.size() - 1; i >= 0; i--) {
final Pipe pipe = pipeline.get(i);
if (pipe instanceof AsPipe && ((AsPipe) pipe).getName().equals(namedStep)) {
break;
} else {
previousPipes.add(0, pipe);
}
}
for (int i = 0; i < previousPipes.size(); i++) {
pipeline.remove(pipeline.size() - 1);
}
if (pipeline.size() == 1)
pipeline.setStarts(pipeline.getStarts());
return previousPipes;
}
It looks like the BackFilterPipe does not remove any of the aspipes between the back pipe and the named as pipe, but they must not be visible to pipes outside the BackFilterPipe. I guess my algorithm for generating the code is going to have to be smarter about detecting when the target is within a meta pipe.
Turns out the way I was using 'as' and 'back' made no sense. When you consider that everything between the 'back('2')' and the 'as('2')' is contained within the BackFilterPipe's inner pipeline, it becomes clear that meta pipes can't be overlapped like this: as('2'), as('target'), back('2'), back('target').

Selectively removing node labels in D3 force directed diagram

Overall context: I have a db of cross-references among pages in a wiki space, and want an incrementally-growing visualization of links.
I have working code that shows clusters of labels as you mouseover. But when you move away, rather than hiding all the labels, I want to keep certain key labels (e.g. the centers of clusters).
I forked an existing example and got it roughly working.
info is at http://webseitz.fluxent.com/wiki/WikiGraphBrowser
near the bottom of that or any other page in that space, in the block that starts with "BackLinks:", at the end you'll find "Click here for WikiGraphBrowser" which will launch a window with the interface
equivalent static subset example visible at http://www.wikigraph.net/static/d3/cgmartin/WikiGraphBrowser/:
code for that example is at https://github.com/BillSeitz/WikiGraphBrowser/blob/master/js/wiki_graph.js
Code that works at removing all labels:
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return !(o.name in clicked_names);
})
.text(function(o) { return ""; });
j++;
}
Code attempting to leave behind some labels, which does not work:
labels.forEach(function(o) {
if (!(d.name in clicked_names)) {
d.text.label.remove();
}
I know I'm just not grokking the d3 model at all....
thx
The problem comes down to your use of in to search for a name in an array. The Javascript in keyword searches object keys not object values. For an array, the keys are the index values. So testing (d.name in clicked_names) will always return false.
Try
i = j = 0;
if (!bo) { //bo=False - from mouseout
//labels.select('text.label').remove();
labels.filter(function(o) {
return (clicked_names.indexOf(o.name) < 0);
})
.text(function(o) { return ""; });
j++;
}
The array .indexOf(object) method returns -1 if none of the elements in the array are equal (by triple-equals standards) to the parameter. Alternatively, if you are trying to support IE8 (I'm assuming not, since you're using SVG), you could use a .some(function) test.
By the way, there's a difference between removing a label and just setting it's text content to the empty string. Which one to use will depend on whether you want to show the text again later. Either way, just be sure you don't end up with a proliferation of empty labels clogging up your browser.

Adding nodes group by group to a D3 force directed graph

I am trying to implement a force directed network similar to this. However, each of my nodes are assigned a group value for example
Node Group
node1 1
node2 1
node3 2
node4 3
node5 3
And I would like the network to grow i.e. after a period of time (say 2 seconds), the subsequent node group is added with their links.
Is this attainable?
Yes. the trick is to encapsulate the part that draws the graph in a function. Add the specific groups after the approppriate intervals to the graph data structure and call that function. The code would look roughly like this.
function update(graph) {
var link = svg.selectAll("line.link")
.data(graph.links)
.enter().append("line");
var node = svg.selectAll("circle.node")
.data(graph.nodes)
.enter().append("circle")
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.start();
}
You should be able to reuse everything else basically as it is.

Resources