Use d3.js on a new window - javascript

Is it possible to use d3.js when opening new windows? For example, I am trying:
new_window = window.open("userpage.html");
new_window.document.write("<html><body>");
new_window.document.write("<table id=\"usertable\">");
new_window.document.write("</table>");
new_window.document.write("</body></html>");
table = d3.select("#usertable");
console.log(table);
var thead = table.append("thead");
var tbody = table.append("tbody");
var columns = ["dataset"];
thead.append("tr")
.selectAll("th")
.data(columns)
.enter()
.append("th")
.text(function(column) { console.log(column); return column; });
It doesn't work and the ouput of the first console.log is
[
Array[1]
0: null
length: 1
parentNode: HTMLHtmlElement
__proto__: Array[0]
]
I think 0: null is not good.

There are a few issues here:
I think you're opening the new window incorrectly - generally, you either open a URL with content, or you use "" as the URL and write your content into a blank window. Opening a URL like "usertable.html" and then writing <html><body> doesn't make sense. Finally, even with a blank window, you don't need to write <html><body> - the browser will generally provide these nodes by default.
Using d3.select is going to look, by default, in the current document. In order to access the body of the newly opened window, you'll need to pass in new_window.document - in fact, you'll need to pass in new_window.document.body, since you can't append anything to document without a HIERARCHY_REQUEST_ERROR.
I also don't think it's a good idea to mix D3 with document.write as you're doing here. D3 selects nodes in the DOM, and the way you have the code now, I don't think your table is actually a well-formed node until after you've tried to select it. D3 is perfectly good at inserting new DOM nodes - use it instead.
Putting all this together yields something like this:
var newWindow = window.open('');
var newWindowRoot = d3.select(newWindow.document.body);
// now do some writing with D3
var data = [
{ foo: "Foo 1", bar: "Bar 1" },
{ foo: "Foo 2", bar: "Bar 2" }
];
var table = newWindowRoot.append('table');
var rows = table.selectAll('tr')
.data(data);
rows.enter().append('tr');
var cells = rows.selectAll('td')
.data(function(d) { return d3.entries(d); });
cells.enter().append('td');
cells.text(function(d) { return d.value; });
Working example: http://jsfiddle.net/nrabinowitz/gQf7J/

Related

How can i append in javascript?

First off i'll state the obvious, i'm new to javascript,html, and web development tools.
var labels = {{ labels|tojson|safe }};
using console.log i was able to see the content of labels console.log(JSON.stringify(labels));
output:
[
{"id":"1","image":"1-0.png","name":"","xMax":"4802","xMin":"4770","yMax":"156","yMin":"141"},
{"id":"2","image":"1-0.png","name":"","xMax":"4895","xMin":"4810","yMax":"157","yMin":"141"},
{"id":"3","image":"1-0.png","name":"","xMax":"4923","xMin":"4903","yMax":"156","yMin":"145"},
{"id":"4","image":"1-0.png","name":"","xMax":"4956","xMin":"4931","yMax":"156","yMin":"145"}
]
It's clearly a list of dictionaries, so far so good, now there is new elements i want to append as it runs and WITHOUT REFRESHING THE PAGE Manually, it should auto update, so since i have some experience with python, i quickly thought about appending, something like that :
labels.append({"id":labels.length + 1,
"name":"",
"xMin":xMin,
"xMax":xMax,
"yMin":yMin,
"yMax":yMax
})
but it isn't working, how can i append that line?
labels is a array type as it has
[{"id":"1","image":"1-0.png","name":"","xMax":"4802","xMin":"4770","yMax":"156","yMin":"141"},{"id":"2","image":"1-0.png","name":"","xMax":"4895","xMin":"4810","yMax":"157","yMin":"141"},{"id":"3","image":"1-0.png","name":"","xMax":"4923","xMin":"4903","yMax":"156","yMin":"145"},{"id":"4","image":"1-0.png","name":"","xMax":"4956","xMin":"4931","yMax":"156","yMin":"145"}]
So you need to use labels.push(obj) to add new object in the labels instead of append()
var labels = [{"id":"1","image":"1-0.png","name":"","xMax":"4802","xMin":"4770","yMax":"156","yMin":"141"},{"id":"2","image":"1-0.png","name":"","xMax":"4895","xMin":"4810","yMax":"157","yMin":"141"},{"id":"3","image":"1-0.png","name":"","xMax":"4923","xMin":"4903","yMax":"156","yMin":"145"},{"id":"4","image":"1-0.png","name":"","xMax":"4956","xMin":"4931","yMax":"156","yMin":"145"}]
var xMin = 1, xMax = 5, yMin = 3, yMax = 8;
labels.push({"id":labels.length + 1, "name":"", "xMin": xMin, "xMax":xMax, "yMin":yMin, "yMax":yMax});
console.log(labels);
Array.prototype.append() does not exist. You need to use Array.prototype.push() if you want to add to it:
Like this:
var labels = [{"id":"1","image":"1-0.png","name":"","xMax":"4802","xMin":"4770","yMax":"156","yMin":"141"},{"id":"2","image":"1-0.png","name":"","xMax":"4895","xMin":"4810","yMax":"157","yMin":"141"},{"id":"3","image":"1-0.png","name":"","xMax":"4923","xMin":"4903","yMax":"156","yMin":"145"},{"id":"4","image":"1-0.png","name":"","xMax":"4956","xMin":"4931","yMax":"156","yMin":"145"}];
console.log(labels);
labels.push({"id":labels.length + 1, "name":"name", "xMin":'xMin', "xMax":'xMax', "yMin":'yMin', "yMax":'yMax'});
console.log(labels);

Unable to re-produce valid data for d attribute of a path

When I create the first set of sectors in my pie chart, it works great. Especially, the attribute d of each path is set correctly.
var grx = chart.selectAll(".sector").data(pie(dataPoints))
.enter().append("g").attr("class", "sector");
grx.append("path").attr("d", arc)
.style("fill", function(d) { return colorsFull(d.value); });
Then, I try to use the same pattern to add a new, inner pie chart. The elements are created, which I can confirm by investigating the DOM structure. However, they're not displayed and, even though it's not shown in the console of the JsFiddle, I got it to have a bunch of NaN.
var gry = chart.selectAll(".subSector").data(pie(drillData))
.enter().append("g").attr("class", "subSector");
gry.append("path").attr("d", sub)
.style("fill", function(d) {return colorsDrill(d.value); });
So, I've got an invalid data for the path but I can't see how it goes wrong. Suggestions?
The fiddle is here.
Your drillData is not in the correct format to pass to your pie function. It looks like this:
[
{
"key": "Category 1",
"val": [{ "Category": "", "Key": "", Value: 1}, ... ]
}
...
]
Your pie function, though, is expecting an array of objects with a property val that's a number, not an array (this is what the .value does).
I'm guessing you need to subset your drillData to the one you clicked on something like:
var subData = null;
drillData.forEach(function(d,i){
if (d.key === key) subData = drillData[i].val;
});
You now have in subData an array of objects with a property Value that's a number. We are getting closer but now we need to redefine our pie function since it's expecting val, not Value:
pie.value(function(d){
return d.Value;
});
So, now we can finally call:
pie(subData)
without error. But, we still got a problem, now you are trying to build an inner donut chart with 300+ wedges (it ain't going to be pretty).
Here's an updated fiddle where I started fixing things.

D3.js method chaining command dosn't work when I split it, it works

I am new in D3.js,
when i use this code it doesn't work,(it is part of the redraw, when running for first time it works good when calling redraw again it works unexpextedly)
var rows=tbody.selectAll('tr').data(roster);
rows.enter().append('tr');
rows.exit().remove();
rows.selectAll('td').data(function(row) { return columns.map(function(col) {
return row[col];
});}).enter().append('td').text(function(d) {return d;} );
when I break the chain down into smaller it works.
var rows=tbody.selectAll('tr').data(roster);
rows.enter().append('tr');
rows.exit().remove();
var cells = rows.selectAll("td")
.data(function(row) { return columns.map(function(col) {
return row[col];
});});
cells.enter().append("td");
cells.text(function(d) { return d; });
any reason or any rule govern this.
In the first case you are only updating the text on the new cells, not the old ones. When you chain .enter() like that, all of the following methods chained apply to the object returned by .enter() and that is the enter selection : added cells in other words.
Read this

Manually Add Nodes to JavaScript InfoVis Toolkit Force Directed Graph

I am attempting to use the JavaScript InfoVis Toolkit found here: JS InfoVis ToolKit to create a Force Directed Graph. We don't really want to use a JSON to "feed" the data to the graph -- instead we would rather manually add nodes.
I have put together the following code -- but when I attempt to draw the graph my root node is not found in line 7118 of jit.js (var root = aGraph.getNode(id);). I have omitted the specifics on my ForceDirected options -- but those should not affect the result.
fd = new $jit.ForceDirected({...})
//Create main node
var rootNode = { id: "root", name: "Actors", data: { "$color": "#557EAA"} }
fd.root = rootNode;
fd.graph.addNode(rootNode);
$.each(array, function (index, art) {
var pubId = art.pubMedId.toString();
var labelText = "Article " + pubId;
var node = { id: pubId.toString(), name: labelText, data: { "$color": "#557EAA"} }
//Create Nodes -- connect them to main node for now
fd.graph.addNode(node);
fd.graph.addAdjacence(rootNode, node, {});
text = text + art.pubMedId + ',';
});
//Display graph
fd.plot();
Does anyone have experience doing this?? Looking for guidance. I have debugged in FireBug and everything appears to be loaded into the graph correctly (ie - all nodes exist). I am at a loss.
Instead of fd.root = rootNode;, you want to use fd.root = rootNode.id;. I was surprised by this as well.
Additionally, you'll probably want to initialize the Graph before adding the root node:
fd.graph = new $jit.Graph(fd.graphOptions, fd.config.Node, fd.config.Edge, fd.config.Label);
Note: tested with version 2.0.1.

Understanding how D3.js binds data to nodes

I'm reading through the D3.js documentation, and am finding it hard to understand the selection.data method from the documentation.
This is the example code given in the documentation:
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr");
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.text(function(d) { return d; });
I understand most of this, but what is going on with the .data(function(d) { return d; }) section of the var td statement?
My best guess is as follows:
The var tr statement has bound a four-element array to each tr node
The var td statement then uses that four-element array as its data, somehow
But how does .data(function(d) { return d; }) actually get that data, and what does it return?
When you write:
….data(someArray).enter().append('foo');
D3 creates a bunch of <foo> elements, one for each entry in the array. More importantly, it also associates the data for each entry in the array with that DOM element, as a __data__ property.
Try this:
var data = [ {msg:"Hello",cats:42}, {msg:"World",cats:17} ];
d3.select("body").selectAll("q").data(data).enter().append("q");
console.log( document.querySelector('q').__data__ );
What you will see (in the console) is the object {msg:"Hello",cats:42}, since that was associated with the first created q element.
If you later do:
d3.selectAll('q').data(function(d){
// stuff
});
the value of d turns out to be that __data__ property. (At this point it's up to you to ensure that you replace // stuff with code that returns a new array of values.)
Here's another example showing the data bound to the HTML element and the ability to re-bind subsets of data on lower elements:
The key to understanding what this code is doing is to recognize that selections are arrays of arrays of DOM elements. The outer-most array is called a 'selection', the inner array(s) are called 'groups' and those groups contain the DOM elements. You can test this by going into the console at d3js.org and making a selection like d3.selectAll('p'), you will see an array containing an array containing 'p' elements.
In your example, when you first call selectAll('tr') you get a selection with a single group that contains all the 'tr' elements. Then each element of matrix is matched to each 'tr' element.
But when you call selectAll('td') on that selection, the selection already contains a group of 'tr' elements. This time each of those elements will each become a group of 'td' elements. A group is just an array, but it also has a parentNode property that references the old selection, in this case the 'tr' elements.
Now when you call data(function(d) { return d; }) on this new selection of 'td' elements, d represents the data bound to each group's parent node. So in the example, the 'td's in the first group will be bound with the array [11975, 5871, 8916, 2868]. The second group of 'td's are bound with [ 1951, 10048, 2060, 6171].
You can read mike bostock's own excellent explanation of selections and data binding here: http://bost.ocks.org/mike/selection/
Use the counter i to show the index of the data being used.
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr") //create a row for each data entry, first index
.text(function(d, i) { return i}); // show the index i.e. d[0][] then d[1][] etc.
var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.style("background-color", "yellow") //show each cell
.text(function(d,i) { return i + " " + d; }); // i.e d[from the tr][0] then d[from the tr][1]...

Categories

Resources