what I'm trying to do is d3.nest() one csv into another.
The node list looks like this:
id,movie,year,genre
85442,Hamlet,1907,Drama
57421,Don Quijote,1908,Drama
13146,Amleto [I],1908,Drama
85443,Hamlet,1908,Drama
160468,Othello,1909,Drama
160468,Othello,1909,Romance
And the edges or links look like this:
sourceid,targetid
234,99455
234,125817
234,201681
476,72885
476,188536
476,246634
1028,14948
1028,60050
So I would like to nest the edges into the node list by the given IDs.
I'm doing some unclever nesting that doesn't work that looks like this right now:
d3.csv("edges.csv", function(edges){
d3.csv("nodes.csv", function(nodes){
var nested_data = d3.nest()
.key(function(d) { return d.sourceid; })
.key(function(d) { return d.id; })
.entries(edges)
.entries(nodes);
console.debug(nested_data);
});
});
I searched for help and found this: D3 change elements based on two different datasets?
But I can't get my head around it. Is it really so difficult? Or might there be another way of doing this? I found this visualization (http://mbostock.github.io/d3/talk/20111116/airports.html) which also deals with two csv files and network structures without using nest().
Thanks,
Kim
Because many people looked at this question, I thought of writing a short follow-up on how this can be solved, to my understanding now.
Lars already gave the right hints. So here just a coded version.
d3.csv("edges.csv", function(edges){
d3.csv("nodes.csv", function(nodes){
var newlist = [];
var i = edges.length;
while(i--){
var edge = edges[i];
newlist.push(
nodes[edge.sourceid].x),
nodes[edge.targetid].y)
);
}
var nested_data = d3.nest()
.key(function(d) { return ... })
.entries(newlist);
});
});
It's not fitting the question perfectly because it assumes that the nodes list is ordered by the ids. The two lists above could be itterated over with something like http://underscorejs.org/#find
Hope this helps.
Related
I'm having difficulties to update the values of a Word.TableRow using the Javascript API. I've look to Doc and I can't find any hints that will help me to accomplish my duty...
Here is my Question: What is the best way to set the values of a TableRow inside a Word Document using the Javascript API.
And Here is what I tried:
Word.run((context: Word.RequestContext) => {
var tables = context.document.body.tables;
tables.load("items");
return context.sync().then(() => {
var firstTableRows = tables.items[0].rows;
context.load(firstTableRows, "items");
context.sync().then(() => {
var header = firstTableRows.items[0];
header.load("values");
context.sync().then(() => {
header.values = ["MyValue"]
context.sync();
});
});
});
}).catch(errorHandler);
This is a 1x2 table
No errors are thrown and the table is not getting updated...
Am I missing something?
Sorry for the delayed response here. There are a couple of issues with your code.
the first one is associated with a bug we are currently fixing with keeping references of items mentioned in the load method. There is a related question on stack explaining this issue. Check it out here. (specially the detailed explanation in the comments).
The second issue I see with your code is that you are trying to set the row values using a 1d array, when a 2D array is expected. (and this is an error in our documentation, we need to fix it thanks to you!)
You have a couple of options for changing values, this is the first one:
Word.run(function (context) {
var myTables = context.document.body.tables;
context.load(myTables);
return context.sync()
.then(function () {
var myRows = myTables.items[0].rows;
context.load(myRows);
return context.sync()
.then(function () {
//assumes a table with at least 3 columns!
myRows.items[0].values = [["1", "3", "4"]];
return context.sync()
})
})
})
.catch(function (e) {
app.showNotification(e.message);
})
}
Now, until the bug mentioned in the first point is fixed you need to do several trips to the host application in order to set the data you want. a potential shortcut is to use our new navigation options,specially if you want to change the first or last row values (please note that we are planning to rename the first to getFirst() by the time we ship the API, so this code will break in a couple of months, maybe already breaks if you are using the insider fast release), you can do something like this in just one call:
Word.run(function (context) {
//this gets the first row of the first table in the document and sets its values. Please note the 2D array used!
context.document.body.tables.first.rows.first.values =[["Juan", "Peter", "Jeff"]];
return context.sync()
.catch(function (e) {
app.showNotification(e.message);
})
})
Please give it a try to these options and let me know how it goes.
thanks!
I need to provide "renaming" functionality to rename nodes using the Icicle example (http://bl.ocks.org/mbostock/4347473).
I am not able to find any solutions similar to what I would like to do, and as browsers usually do not allow for right click, I was wondering if anyone has any suggestions on how to allow for this option and then also how to go about allowing someone to be able to rename a specific node's name.
Thanks.
For the record and per kind request by user2651192, the most workable path for this that we could find is here and, more specifically, the code to change the text is:
...
node.append("text")
.text(function(d){ return d.name; })
.on('click', function(d){
var result = prompt('Change the name of the node',d.name);
if(result) {
d.name = result;
var node1 = canvas.selectAll('.node').data(nodes);
node1.select('text')
.text(function(d){ return d.name; });
}
)};
...
(there are other questions but neither helped me out)
Hi, I would like to know if this is the right way to filter the results I get from service where I'm displaying only one result (like a detail).
I know I could use ng-repeat and filter it in the view and that is the cleanest, but I want to have more control over because I will re-use some of the data in the controller for other operations.
Right now I'm doing this:
$scope.savedEvents = Event.getPayedEvents(); //gets a list from service
//Goes through entire list and checks for a match
angular.forEach($scope.savedEvents, function(event) {
if (event.IdEvent == $stateParams.eventId) {
$scope.showEvent = event;
}
});
//now if there is a match I can use $scope.showEvent.eventName etc
Not sure if this would be easier using $filter to return just one event that has correct IdEvent. Or if someone has better solution, please let me know.
thanks
I don't see any problems with what you have, but you could inject the $filter service and do this one liner:
$scope.showEvent = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId });
EDIT: Here is an easy way to resolve the result to a single value from the returned array:
var showEvents = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId });
$scope.showEvent = showEvents && showEvents.length ? showEvents[0] : null;
In CoffeeScript it is a little more concise:
$scope.showEvent = $filter('filter')($scope.savedEvents, { IdEvent: $stateParams.eventId })?[0]
I previously asked a similar question before, however it seemed that I wasn't being precise enough about my question - hopefully this is.
Many examples of the Tree Layout format their hierarchy data set as this: https://gist.github.com/tchaymore/1249394#file-math_map_compact-json
However I wanted to change the "children" node in the json to "children1" for example
var flare = {
"Name": "Example",
"children1": [
{
"BName":"Ja",
"Email":"",
"children1":[
{
"NickName":"NC",
"id":2
}
],
}
]};
When I had changed the name of that node, I then used the children function:
var tree = d3.layout.tree()
.size([height, width])
.children(function(d) { return d.children1; });
After that I changed all of the "children" references to "children1" & so on.
However, now I have the problem of not being able to collapse the tree back into its parent. I've tried to use this example as a reference, but no luck: http://blog.pixelingene.com/2011/07/building-a-tree-diagram-in-d3-js/
Here's a example of my current problem: http://jsfiddle.net/mEyQW/1/
.. I apologize for the previous confusion
I don't really get what you wanted to do with your collapse() function and the _children1 but if you remove it, then everything works fine:
jsFiddle: http://jsfiddle.net/chrisJamesC/mEyQW/2/
I've searched through the myriad parent/child array/object/whatever questions here and elsewhere and haven't been able to solve my issue. I know this is a bit long, but I wanted to ensure I'm providing enough info to you guys.
Here's what I want to do:
I have a number of <div>-delineated items on the page with parent/child relationships, generated via php from my database
I want to use these items as the data source for a D3.js Dendrogram (a node-link tree diagram http://mbostock.github.com/d3/ex/cluster.html)
I'm storing them with left/right nested set values but also parentID values, so I can add ID, parentID, rgt, lft and depth attributes to the <div> elements, so I should have available whatever's needed to generate the parent/child relationships on the client side
For various reasons, instead of creating a JSON file on the server side to use as the data source, I need to create it on the client side based on the attributes in #3
I've had difficulty getting various suggested javascript functions to work and all the D3 examples I've found use either a preexisting JSON file or generated math-based file, not attributes of elements already on the page
Here is an example of what already works for me with the D3 Dendrogram, but it's not generated dynamically:
var tree3 =
{"sid": "1", "children": [
{"sid": "2", "children": [
{"sid": "5", "children": [
{"sid": "75"},
{"sid": "85", "children": [
{"sid": "87"}, ...
To give you an idea of where these attributes are in the DOM, I originally tried the below, but of course it doesn't generate any hierarchy:
function tree() {
var tree=[];
$("article").each(function(){
tree.push({
sid:$(this).attr("sid"),
l:$(this).attr("l"),
r:$(this).attr("r"),
pid:$(this).attr("pid")
});
});
return tree;
}
I've been messing around unsuccessfully with variants of the below to get a nested array:
function tree2() {
$("article").(function(d) {
return d.parent().attr("pid") === 0;
}, function(parent, child) {
return parent.attr("pid") === child.parent().attr("sid");
}).toArray();
}
So, I'm driving myself crazy trying to create the javascript array nested correctly, but it's dawned on me that I may not need to and that D3's data selectors and methods could be sufficient. Could you please help me with the code to:
Pull the needed attributes to generate the parent/child relationship within a D3 function ("sid" is the identifier) or, if this isn't possible,
Create the needed array or array-like object in javascript for use by D3 (still with "sid" as the identifier).
Thanks in advance.
You need to get recursive! Basically the trick is to pass the current parent in as you go, which changes the context and allows you to walk down the tree.
Update: Working fiddle.
Assuming your HTML structure is something like this:
<div sid="1" pid="">
<div sid="1.1" pid="1">
<div sid="1.1.1" pid="1.1">
</div>
</div>
</div>
You could do something like this:
var _json = {};
function addTreeNode(div, parentObj) {
var childObj = {
sid: $(div).attr("sid"),
pid: $(div).attr("pid")
}
// add this to it's parent in the JSON hierarchy
if (!parentObj.children) parentObj.children = [];
parentObj.children.push(childObj);
// keep adding for all children div's
$(div).find("div").each(function() {
addTreeNode(this, childObj);
});
}
// start at the roots, it will magically work it's way out to the leaves
$("body > div").each(function(){
addTreeNode(this, _json);
});
console.log(_json);
Note that if your tree is big enough, you will cause stack overflows, especially in IE. In that case, you'll need to switch this over from recursion to iteration. It's not as pretty that way, though.