The treemap examples do this. In SVG, you use an svg:text element; in
HTML, you just set the text content of your div elements with the
`text` operator.
Mike
[{year: 1931, values: [
{key: "Manchuria", values: [
{yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
:
..we should ideally see something along the lines of :
{ "year": "1931", "values": [ { "variety": "Manchuria", "values": [
{ "site": "University Farm", "values": [{yield: 27.00}
] },
:
Is such an optimisation possible at the moment using d3?
That would require creating new objects that contain only the
properties that weren't nested. So I'm not sure that would really be
an optimization. You can do this yourself by specifying a rollup
operator, for example, rollup(function(v) { return v.map(function(d) {
return d.yield; }); }) would have values contain an array of yields
rather than objects.
Mike
symbol,date,priceS&P 500,Jan 2000,1394.46S&P 500,Feb 2000,1366.42S&P 500,Mar 2000,1498.58S&P 500,Apr 2000,1452.43S&P 500,May 2000,1420.6S&P 500,Jun 2000,1454.6
: : :
d3.csv("file:///Volumes/PLEXTOR/AAA_MyStartup/CSV/stocks.csv", function( csv ) {
console.log("csv = " + csv.toSource() );
csv = [{symbol:"S&P 500", date:"Jan 2000", price:"1394.46"}, {symbol:"S&P 500", date:"Feb 2000", price:"1366.42"}, {symbol:"S&P 500", date:"Mar 2000", price:"1498.58"}, {symbol:"S&P 500", date:"Apr 2000", price:"1452.43"}, {symbol:"S&P 500", date:"May 2000", price:"1420.6"}, {symbol:"S&P 500", date:"Jun 2000",: :{symbol:"AAPL", date:"Dec 2009", price:"210.73"}, {symbol:"AAPL", date:"Jan 2010", price:"192.06"}, {symbol:"AAPL", date:"Feb 2010", price:"204.62"}, {symbol:"AAPL", date:"Mar 2010", price:"223.02"}]
json = d3.nest()
.key(function(d) { return d.symbol; })
.key(function(d) { return d.date; })
.rollup(function(v) { return v.map(function(d) { return d.price; }); })
.entries(csv);
console.log("json = " + json.toSource() );
json = [{key:"S&P 500", values:[{key:"Jan 2000", values:["1394.46"]}, {key:"Feb 2000", values:["1366.42"]}, {key:"Mar 2000", values:["1498.58"]}, {key:"Apr 2000", values:["1452.43"]}, {key:"May 2000", values:["1420.6"]}, {key:"Jun 2000",: :{key:"Oct 2009", values:["188.5"]}, {key:"Nov 2009", values:["199.91"]}, {key:"Dec 2009", values:["210.73"]}, {key:"Jan 2010", values:["192.06"]}, {key:"Feb 2010", values:["204.62"]}, {key:"Mar 2010", values:["223.02"]}]}]
var nodes = tree.nodes(json);
console.log("nodes = " + nodes.toSource() );
nodes = [[{key:"S&P 500", values:[{key:"Jan 2000", values:["1394.46"]}, {key:"Feb 2000", values:["1366.42"]}, {key:"Mar 2000", values:["1498.58"]}, {key:"Apr 2000", values:["1452.43"]}, {key:"May 2000", values:["1420.6"]}, {key:"Jun 2000", values:["1454.6"]}, {key:"Jul 2000", values:["1430.83"]},: :{key:"Oct 2009", values:["188.5"]}, {key:"Nov 2009", values:["199.91"]}, {key:"Dec 2009", values:["210.73"]}, {key:"Jan 2010", values:["192.06"]}, {key:"Feb 2010", values:["204.62"]}, {key:"Mar 2010", values:["223.02"]}]}]]
var link = vis.selectAll("path.link").data(tree.links(nodes))
.enter().append("svg:path").attr("class", "link").attr("d", diagonal);
console.log("link = " + link.toSource() );
link = [[]]
var link = vis.selectAll("path.link").data(tree.links(nodes)).enter().append("svg:path").attr("class", "link").attr("d", diagonal);
console.log("link = " + link.toSource() );
node = [[({})]]
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
:
Copy/paste error above. Last trace output should of course be preceded by node instead of link code :
var node = vis.selectAll("g.node").data(nodes).enter().append("svg:g").attr("class", "node").attr("transform", function(d) {return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
console.log("node = " + node.toSource() );
node = [[({})]]
In the DOM inspector, I see the following is throwing up a NaN error:
node = vis.selectAll("g.node").data(nodes).enter().append("svg:g").attr("class", "node").attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
class="node" transform="rotate(NaN)translate(0)"
This also seems to suggest a formatting problem arising during the csv-json conversion process.
node = vis.selectAll("g.node").data(nodes).enter().append("svg:g").attr("class", "node").attr("transform", function(d) {
console.log("d = " + d.toSource());
return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
});
d = [{key:"S&P 500", values:[{key:"Jan 2000", values:["1394.46"]}, {key:"Feb 2000", values:["1366.42"]}, {key:"Mar 2000", values:["1498.58"]}, {key:"Apr 2000", values:["1452.43"]}, {key:"May 2000", values:["1420.6"]}, {key:"Jun 2000", values:["1454.6"]}, {key:"Jul 2000", values:["1430.83"]}, {key:"Aug 2000", values:["1517.68"]}, {key:"Sep ...
json = d3.nest().key(function(d) { return d.root; })
.key(function(d) { return d.symbol; })
.key(function(d) { return d.date; })
.rollup(function(v) { return v.map(function(d) { return d.price; }); })
.entries(csv);
One of the most important parts is how the partition layout converts
the nested set. For that, you need to define the call like so:
var partition = d3.layout.partition()
.sort(null)
.size([2 * Math.PI, r * r])
.value(function(d) { return d.values; })
.children(function (d) { return d.values; });
This means that it looks for both the value and the children
in .values (instead of the standard .children) - we have to do this
because a nested set only has .values as properties of a node.
I pull my data from a json source, but it really doesn't matter much -
my data isn't even close to being formatted in the way we need it
here, it's just a collection of sales records:
{"type":"SalesCollection","sales":[
{"type":"Sale","id":"9122","invoice":"invoice-1","date":"2011-11-23","plan":"60","group":"10","amount":"55.00"},
{"type":"Sale","id":"9123","invoice":"invoice-2","date":"2011-11-23","plan":"60","group":"10","amount":"34.00"},
{"type":"Sale","id":"9124","invoice":"invoice-3","date":"2011-11-23","plan":"69","group":"8","amount":"12.00"}
]}
From this, I build the nested set:
pre.values = d3.nest()
.key(function(d) { return d.group; })
.rollup(function(v) { return d3.nest()
.key(function(d) { return d.plan; })
.rollup(function(v) { return d3.sum(v.map(function(d)
{ return d.amount; })); })
.entries(v);
})
.entries(json.sales); // <-get the sales array from the json above
So in this case, I get a two-level nested set array: group->plan-
>amount. I get the amount with the rollup trick that Mike quoted
above.
Finally, I take almost the same call for the path:
var path = vis.data([pre]).selectAll("path")
.data(partition.nodes).enter()
.append("svg:path")
.attr("display", function(d) { return d.depth ? null :
"none"; }) // hide inner ring
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("opacity", "0.8")
.style("fill", function(d) { return color(( (typeof d.values !=
'object') ? d.parent : d).key); });
As you can see, in the "fill" rule, I make a distinction on whether
the content of d.values is an object - thus giving me the correct
color rule depending on whether I'm in a child item or a group.
The part I'm working on right now is that instead of just calling in
the data, I would like to attach it to the path I'm creating.
Anyhow - hope it helps. Oh and also: Hello World, d3-js list.
cheers,
skore
On Nov 30, 4:00 pm, Thug <a.douglas.h...@gmail.com> wrote:
> Hi,
>
> I've returned to this problem -the generation of "optimised"
> (non-redundant) json from csv files- a number of times, but -even using csv
> files known to work in other contexts and extended by a root column with
> identical value zero throughout- the generated JSON (tested
> usinghttp://www.jsonlint.com) is invariably invalid.
>
> Here (in order of likelihood) are the aspects I feel may be contributing to
> the failure:
>
> - Missing double quotes around the generated collection labels *key* and
> *values*
> - Though present in original csv, missing label for field
> contents identified in the rollup function (here *price*).
> - A gradual accumulation of outer square brackets around the entire
> logged output construct.
>
> *Valid JSON looks like:*
>
> {
> "name": "flare",
> "children": [
> {
> "name": "analytics",
> "children": [
> {
> "name": "cluster",
> "children": [
> {
> "name": "AgglomerativeCluster",
> "size": 3938
> },
>
> *Invalid JSON (here generated from stocks.csv) looks like:*
>
> {
> key: "0",
> values: [
> {
> key: "S&P 500",
> values: [
> {
> key: "Jan-00",
> values: [
> "1394.46"
> ]
> },
> {
> key: "Feb-00",
> values: [
> "1366.42"
> ]
> },
>
> Here the code generating the above:
>
> json = d3.nest().key(function(d) { return d.root; })
> .key(function(d) { return d.symbol; })
> .key(function(d) { return d.date; })
> .rollup(function(v) { return v.map(function(d) { return d.price; }); })
> .entries(csv);
> Are there inconsistencies in some of these respects in d3's conversion of
> csv to json? Fromhttp://www.jsonlint.com: "Be sure to follow JSON's syntax<http://www.json.org/> properly.
var pre = new Object;
pre.key = 0;
pre.values = d3.nest()
.key(function(d) { return d.group; })
.rollup(function(v) { return d3.nest()
.key(function(d) { return d.plan; })
.rollup(function(v) { return d3.sum(v.map(function(d)
{ return d.amount; })); })
.entries(v);
})
.entries(json.sales); // <-get the sales array from the json above
cheers,
skore
My trial code is here: http://bl.ocks.org/1439067
Eventually I want to allow users to:
1 -- Apply multiple filters to a csv file to obtain a sub selection of
interest via dropdown select box.
2 -- Choose from a variety of different nest options to create
different "flare.json" style format.
3 -- Choose from a variety of different visualization options that use
the "flare.json" style format.
4 -- RENDER the visualisation.
I can generate a treemap from a filtered and nested csv file. Then if
I select a csv filter and refresh the page it updates the treemap!
This "refresh" approach doesn't seem to work on bl.ocks.org... and I
would rather it did it as an "onchange" event... but I cant figure out
how to make it to work!
I am sure this is probably something really simple for somebody who
knows what they are doing!!
Hope somebody can point out the mistake... or even better suggest ways
to progress towards the end goal....
cheers
James
much simplified version now here: http://bl.ocks.org/1446865
On select it draws the treemap for the filtered csv and onchange it
redraws. Hooray! .. BUT positioning goes haywire and old nodes are not
being removed.... not so good.
guessing this is something to do will cell.exit().remove();
despite lots of poking still cant figure out the problem.
d3 is tough with my almost non existent javascript or programming
background.... but I recognise its power and hope I can figure out
some more of the basics soon!
James
// join data to .cell elements
// optionally specify a key function to the data join!
var cell = svg.selectAll(".cell")
.data(nodes);
// enter new elements
var cellEnter = cell.enter().append("g")
.attr("class", "cell")
…
cellEnter.append("rect")
…
cellEnter.append("text")
…
// update remaining elements
cell.select("rect")
…
cell.select("text")
…
// remove old elements
cell.exit().remove();
Your code isn't working because you are appending the rect and text to
the update selection (cell) rather than the enter selection
(cell.enter()). And conversely, you're not updating the update
selection or using a key function for the data join.
Mike
Have been hacking stuff together that I still don't fully understand.
Your guidance above is the clearest yet...definitely some dim lights
at the end of my tunnel as things become clearer!
Ok v3 is now updated here:
Its getting better. Old cells are now removing properly but new cells
are still all over the place. I am thinking this is something to do
with treemap.sticky(false)?
Found this: https://github.com/mbostock/d3/issues/393
and tried some tweaks but no luck yet. Is this an unresolved issue?
Not likely. That bug that you linked isn't a bug, just a
misunderstanding about the behavior of sticky(true).
The problem in your case is that you've forgotten to update the g.cell
elements' transform attribute. You could say:
cell.attr("transform", function(d) { return "translate(" + d.x + ","
+ d.y + ")"; });
Also, you can simplify your code by removing the duplicate operations
on both the enter and update selections. Whatever you apply to the
update selection after enter is applied to both entering and updating
nodes. So, for example, rather than saying this:
var cellEnter = cell.enter().append("g")
.attr("class", "cell");
cellEnter.append("rect")
.attr("width", function(d) { return d.dx - 1; })
.attr("height", function(d) { return d.dy - 1; })
.style("fill", function(d) { return color(d.parent.key); })
cell.select("rect")
.attr("width", function(d) { return d.dx - 1; })
.attr("height", function(d) { return d.dy - 1; })
.style("fill", function(d) { return color(d.parent.key); })
You can just say:
var cellEnter = cell.enter().append("g")
.attr("class", "cell");
cellEnter.append("rect");
cell.select("rect")
.attr("width", function(d) { return d.dx - 1; })
.attr("height", function(d) { return d.dy - 1; })
.style("fill", function(d) { return color(d.parent.key); })
Of course, if something only needs to be set on enter, you should set
it there rather than on update to improve performance.
Mike
now to test with big data....
thanks Mike!!
"the conductor enters the stage, raps three times with his baton, and
harmony emerges from the chaos." --Arthur Koestler, The Sleepwalkers
(New York: Macmillan, 1968), p. 25
To date I have been using python to generate flare style
hierarchies...It has successfully converted 12,000 line csv files into
exact d3 flare format (with a bit of cutting and pasting from the
python shell).
For the moment it is MUCH faster than through nested csv with d3.js
(but I still dont understand nesting that well). I still like the
pure javascript option because I want to filter and nest my data in
multiple ways and tweaking the python code every time is tedious!
Maybe somebody who understands python better could turn it into some
sort of useful tool.
code is pretty simple...
import csv, itertools, json
def cluster(rows):
result = []
data = sorted(rows, key=lambda r: r[1])
for k, g in itertools.groupby(rows, lambda r: r[0]):
group_rows = [row[1:] for row in g]
if len(row[1:]) == 4:
result.append({"name": row[1],"fon": row[1],"bud":
int(row[2]),"act": int(row[3])}) // NEED TO FIDDLE WITH THIS LINE
DEPENDING ON NUMBER OF COLUMNS IN YOUR CSV
else:
result.append({"name": k,"children":
cluster(group_rows)})
return result
if __name__ == '__main__':
s = '''\
//PASTE YOUR CSV HERE!!!
'''
rows = list(csv.reader(s.splitlines()))
print json.dumps(cluster(rows),indent = 2)
here's an example that has been validated by json lint
# -*- coding: utf8 -*-
import csv, itertools, json
def cluster(rows):
result = []
data = sorted(rows, key=lambda r: r[1])
for k, g in itertools.groupby(rows, lambda r: r[0]):
group_rows = [row[1:] for row in g]
if len(row[1:]) == 1:
result.append({"name": row[0],"size": int(row[1])})
else:
result.append({"name": k,"children":
cluster(group_rows)})
return result
if __name__ == '__main__':
s = '''\
wotamess,907,3-4-0-0412-070-0160-02-1,3-621-10,850000
wotamess,907,3-4-0-0412-070-0160-02-1,3-628-20,850000
wotamess,907,4-4-0-0912-070-0150-02-1,2-611-07,111318000
wotamess,907,4-4-0-0912-070-0150-02-1,2-611-22,440775000
'''
rows = list(csv.reader(s.splitlines()))
print json.dumps(cluster(rows),indent=2)
Hi All,
--
You received this message because you are subscribed to a topic in the Google Groups "d3-js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/d3-js/L3UeeUnNHO8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.