d3js - how to prevent the `line` from `null` values in json data? - json

I am getting the json data from back-end to draw the line. the problem what i am getting is, even if the data is being as null ( out of 20 say 5 doesn't have data ) i am getting line drawn in.
what i expect is, I don't want to draw the lines once the data has the values as null.
example data :
[
{
"ActualPercentage": 48.78,
"PlanPercentage": 44.05,
"Week": "2015-10-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 45.25,
"Week": "2015-11-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 46.45,
"Week": "2015-12-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 47.65,
"Week": "2016-01-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 48.85,
"Week": "2016-02-28T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 50.05,
"Week": "2016-03-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 51.25,
"Week": "2016-04-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 100,
"Week": "2016-05-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 100,
"Week": "2016-06-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 100,
"Week": "2016-07-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": 100, //let this line alone stop here.
"Week": "2016-08-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null, //still drawing!?
"Week": "2016-09-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2016-10-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2016-11-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2016-12-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2017-01-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2017-02-27T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2017-03-30T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2017-04-29T18:30:00.000Z"
},
{
"ActualPercentage": 100,
"PlanPercentage": null,
"Week": "2017-05-30T18:30:00.000Z"
}
]
I am drawing 2 lines here. let first line draw as fill data and second one let stop up to it's find the value.
how to do this?
here is my code :
var that = this;
var parseDate = d3.time.format("%Y%m%d").parse;
var width = this.width;
var height = this.height;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var toolTipScale = d3.scale.linear().domain([height + 90, 80]).range([0, 100]);
var iScale = d3.scale.linear().domain([width + 80, 80]).range([this.datas.length, 0]);
var color = d3.scale.ordinal()
.domain(["ActualPercentage", "PlanPercentage", "WeeklyActual", "WeeklyPlan"])
.range(["#FF0000", "#009933" , "#FFFFFF", "#ff0099"]);
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(-height)
.ticks(d3.time.month, 1)
.tickFormat(d3.time.format("%Y-%b"))
.tickSubdivide(true)
.orient("bottom")
.outerTickSize(0); //removing right border as the way top too.
var yAxis = d3.svg.axis().scale(y).tickSize( -width ).tickSubdivide(true).orient("left").outerTickSize(0);
var line = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.defined(function(d) { return d.y; })
.y(function(d) { return y(d.temperature); });
var svg = this.svg;
var div = d3.select("body").append("div")
.attr("class", "tooltips")
.style("opacity", 0);
color.domain(d3.keys(this.datas[0]).filter(function(key) {
return key !== "Week" && key !== "Value" && key !== 'WeeklyActual' && key !== 'WeeklyPlan'
}));
this.datas.forEach(function(d) {
var dateObj = new Date(d.Week);
var month = dateObj.getUTCMonth() + 1; //months from 1-12
var day = dateObj.getUTCDate();
var year = dateObj.getUTCFullYear();
d.Week = new Date(month+'/'+day+'/'+year );
// console.log( d.Week );
});
var cities = color.domain().map(function(name) {
return {
name: name,
values: that.datas.map(function(d) {
return {date: d.Week, temperature: (+d[name]) };
})
};
});
x.domain(d3.extent(this.datas,
function(d) {
return d.Week;
})
);
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr('class', 'text-xaxis')
.style("text-anchor", "end")
// .attr('dx', -40)
// .attr('dy', 60)
.attr("transform", function(d) {
return "rotate(-65)"
});
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text")
.attr('class', 'text-yaxis')
.attr('dx', -10)
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr('id', function(d) {
return d.name;
})
.attr("class", "city");
var path = city.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) { return color(d.name); });
var totalLength = [
path[0][0].getTotalLength(),
path[0][1].getTotalLength()
];
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
var circles = city.selectAll("circle")
.data(function(d) {
return d.values
})
.enter()
.append("circle")
.attr("r", 3.5)
.attr("cx", function(d, i) {
return x(d.date)
})
.attr("cy", function(d) {
return y(d.temperature)
})
.style('cursor', 'pointer')
.attr("fill", "transparent")
.attr("stroke", "yellow")
.attr("stroke-width", 0);
circles.transition().duration(3000).attr("stroke-width", 2);
circles.on("mouseover", function(d, i) {
div.transition().duration(200).style("opacity", 0.9);
var data = d3.select(this.parentNode).select("path").data()[0];
var date = d.date;
var dateValues = date.getDate() +'/' + (date.getMonth() + 1) +'/' + date.getFullYear();
div.html( "<span>"+ data.name + ": </span><span>" + dateValues + '</span><span>' + d.temperature +'</span>')
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 60) + "px");
})
.on("mouseout", function(d, i) {
div.transition().duration(500).style("opacity", 0);
})

from the idea of softwarenewbie7331 I have modified the code like this: ( Y values )
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.defined(function(d) { return d.temperature })
.y(function(d) { return y(d.temperature); });
this is working fine for me.

Related

D3.js multiple svg event not triggered

Trying to display two tree using d3.js. After adding second tree neither zoom or click event works on first SVG. I added zoom and event by qualifying specific svg class name. Still it doesn't work. Any help please
<script src="http://d3js.org/d3.v3.min.js"></script>
// ************** Generate the tree diagram *****************
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 900 - margin.right - margin.left,
height = 500 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var nodeWidth = 150;
var nodeHeight = 30;
var tree1 = d3.layout.tree()
.size([height, width])
.nodeSize([nodeWidth, nodeHeight])
.separation(function(a, b) {
return ((a.parent == root) && (b.parent == root)) ? 0.2 : 0.3;
});
var tree2 = d3.layout.tree()
.size([height, width])
.nodeSize([nodeWidth, nodeHeight])
.separation(function(a, b) {
return ((a.parent == root) && (b.parent == root)) ? 0.2 : 0.3;
});
var treeDict = {};
treeDict["_lhs"] = tree1;
treeDict["_rhs"] = tree2;
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.y, d.x];
})
.source(function(d) {
return {
x: d.source.x,
y: d.source.y
};
})
.target(function(d) {
return {
x: d.target.x,
y: d.target.y
};
});
var posCSS;
var pos_CSS;
/*
.call(d3.behavior.zoom().on("zoom", function () { d3.select(posCSS).select(".svg_1").select(".svg_2").attr("transform", d3.event.transform) }))
*/
var ret = drawTree(".lhs", tree1);
function drawTree(cssPos, treeData) {
posCSS = cssPos
pos_CSS = cssPos.replace(/[&\/\\#, +()$~%.'":*?<>{}]/g, '_');
var svg = d3.select("body").select(posCSS).append("svg:svg")
.attr("class", "svg_1" + pos_CSS)
.attr("width", width)
.attr("height", height)
.style("background-color", "#EEEEEE")
.style("overflow", "scroll")
.call(d3.behavior.zoom().scaleExtent([0.5, 5]).on("zoom", zoom))
.append("svg:g")
.attr("class", "svg_2")
.append("svg:g")
.attr("class", "svg_3")
.attr("transform", "translate(" + (margin.left) + "," + (margin.top + height / 2) + ")");
//without svg_3 when we select the graph first time, it moves to top left and then we need to drag..so leave it
/*
d3.select(posCSS).select(".svg_1")
.call(d3.behavior.zoom()
.scaleExtent([0.5, 5])
.on("zoom", zoom));
*/
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
}
function update(source) {
//var nodeHeight = 50, nodeWidth = 100;
// Compute the new tree layout.
var nodes = treeDict[pos_CSS].nodes(root).reverse(),
links = treeDict[pos_CSS].links(nodes);
// Normalize for fixed-depth.
//For Right to Left
//nodes.forEach(function(d) { d.y = width - (d.depth * 180); });
//For Left to Right
nodes.forEach(function(d) {
d.y = d.depth * 180;
});
// Update the nodes
//var node = svg.selectAll("g.node")
var node = d3.select("div" + posCSS).select("svg.svg_1" + pos_CSS).select("g.svg_2").select("g.svg_3").selectAll("g.node")
.data(nodes, function(d) {
return d.id || (d.id = ++i);
});
//var arrow = svg.append("svg:defs").selectAll("marker")
var arrow = d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2").select(".svg_3").append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.attr("class", "arrow")
.append("svg:path")
.attr('d', 'M10,-5L0,0L10,5');
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + source.x0 + "," + source.y0 + ")";
})
//.on("click", click);
// Toggle children on click.
.on("click", function(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
});
nodeEnter.append("rect")
.attr("width", nodeWidth)
.attr("height", nodeHeight)
.attr("stroke", "black")
.attr("fill", "blue")
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("foreignObject")
.attr('x', -5)
.attr('y', -10)
.append("xhtml:body")
.append("xhtml:div")
.style({
width: nodeWidth + 'px',
height: nodeHeight + 'px',
"font-size": "10px",
"background-color": "white"
}).html(function(d) {
return '<b>' + d.funcName + '<br>' + '<A HREF="http://127.0.0.1:5000" target="_blank" >' + d.modName + '</A></b>'
});;
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
if (d.parent == "null") {
d.y = 700;
//d.x = 10;
}
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("rect")
.attr("r", 10)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
nodeExit.select("circle")
//nodeExit.select("rect")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links
var link = d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2").select(".svg_3").selectAll("path.link")
.data(links, function(d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("marker-end", "url(#end)")
.attr("class", "link")
.attr("d", function(d) {
var valX = 15,
valY = 10
var o = {
x: source.x0 + valX,
y: source.y0
};
return diagonal({
source: o,
target: o
});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d) {
var valX = 15,
valY = 10
var s = {
x: d.source.x + valX,
y: d.source.y + nodeWidth + valY - 5
},
t = {
x: d.target.x + valX,
y: d.target.y - valY
}
return diagonal({
source: s,
target: t
});
});
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var valX = 15,
valY = 10
var o = {
x: source.x + valX,
y: source.y + nodeWidth + valY
};
return diagonal({
source: o,
target: o
});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
node.on("mouseover", function(p) {
var nodes = [];
nodes.push(p);
while (p.parent) {
p = p.parent;
nodes.push(p);
}
//color the links
link.filter(function(d) {
if (nodes.indexOf(d.target) !== -1) return true;
}).style("stroke", "orange");
//color the nodes
node.filter(function(d) {
if (nodes.indexOf(d) !== -1) return true;
}).style("fill", "steelblue");
});
node.on("mouseout", function(p) {
var nodes = [];
nodes.push(p);
while (p.parent) {
p = p.parent;
nodes.push(p);
}
//color the links
link.filter(function(d) {
if (nodes.indexOf(d.target) !== -1) return true;
}).style("stroke", "#ccc");
//color the nodes
node.filter(function(d) {
if (nodes.indexOf(d) !== -1) return true;
}).style("fill", "#ccc");
});
}
function zoom() {
var realWidth = window.innerWidth - 80;
var realHeight = window.innerHeight - 480;
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -height * scale,
bbound = height * scale,
lbound = (-width + 240) * scale,
rbound = (width - 240) * scale;
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
d3.select(posCSS).select(".svg_1" + pos_CSS).select(".svg_2")
.attr("transform", "translate(" + translation + ")" +
" scale(" + scale + ")");
}
</script>
<div class="lhs">
<script>
var tree2 = [{
"children": [{
"children": [{
"count": 1,
"funcName": "main",
"modName": "bash-5.0/array.c"
}, {
"count": 1,
"funcName": "print_array_assignment",
"modName": "bash-5.0/arrayfunc.c"
}, {
"count": 1,
"funcName": "array_var_assignment",
"modName": "bash-5.0/subst.c"
}, {
"count": 1,
"funcName": "make_env_array_from_var_list",
"modName": "bash-5.0/variables.c"
}],
"count": 1,
"funcName": "array_to_assign",
"modName": "bash-5.0/array.c"
}, {
"children": [{
"count": 1,
"funcName": "print_assoc_assignment",
"modName": "bash-5.0/arrayfunc.c"
}, {
"count": 1,
"funcName": "array_var_assignment",
"modName": "bash-5.0/subst.c"
}, {
"count": 1,
"funcName": "make_env_array_from_var_list",
"modName": "bash-5.0/variables.c"
}],
"count": 2,
"funcName": "assoc_to_assign",
"modName": "bash-5.0/assoc.c"
}, {
"children": [{
"count": 1,
"funcName": "execute_disk_command",
"modName": "bash-5.0/execute_cmd.c"
}],
"count": 1,
"funcName": "printable_filename",
"modName": "bash-5.0/general.c"
}, {
"children": [{
"count": 1,
"funcName": "string_var_assignment",
"modName": "bash-5.0/subst.c"
}, {
"count": 1,
"funcName": "string_transform",
"modName": "bash-5.0/subst.c"
}],
"count": 1,
"funcName": "sh_quote_reusable",
"modName": "bash-5.0/lib/sh/shquote.c"
}, {
"children": [{
"count": 1,
"funcName": "do_assignment_internal",
"modName": "bash-5.0/subst.c"
}, {
"count": 1,
"funcName": "assign_in_env",
"modName": "bash-5.0/variables.c"
}],
"count": 1,
"funcName": "xtrace_print_assignment",
"modName": "bash-5.0/print_cmd.c"
}, {
"children": [{
"count": 2,
"funcName": "execute_simple_command",
"modName": "bash-5.0/execute_cmd.c"
}, {
"count": 1,
"funcName": "xtrace_print_for_command_head",
"modName": "bash-5.0/print_cmd.c"
}, {
"count": 1,
"funcName": "xtrace_print_select_command_head",
"modName": "bash-5.0/print_cmd.c"
}],
"count": 1,
"funcName": "xtrace_print_word_list",
"modName": "bash-5.0/print_cmd.c"
}, {
"children": [{
"count": 1,
"funcName": "print_heredocs",
"modName": "bash-5.0/print_cmd.c"
}, {
"count": 2,
"funcName": "print_redirection_list",
"modName": "bash-5.0/print_cmd.c"
}],
"count": 1,
"funcName": "print_redirection",
"modName": "bash-5.0/print_cmd.c"
}, {
"children": [{
"count": 1,
"funcName": "printenv_builtin",
"modName": "bash-5.0/examples/loadables/printenv.c"
}, {
"count": 1,
"funcName": "print_assignment",
"modName": "bash-5.0/variables.c"
}],
"count": 1,
"funcName": "print_var_value",
"modName": "bash-5.0/variables.c"
}, {
"children": [{
"count": 1,
"funcName": "push_heredoc",
"modName": "bash-5.0/y.tab.c"
}, {
"count": 1,
"funcName": "yyerror",
"modName": "bash-5.0/y.tab.c"
}],
"count": 1,
"funcName": "report_syntax_error",
"modName": "bash-5.0/y.tab.c"
}],
"count": 1,
"funcName": "ansic_quote",
"modName": "FileName.c"
}];
var ret = drawTree(".lhs", tree2);
</script>
</div>
<div class="rhs">
<script>
var ret = drawTree(".rhs", tree2);
</script>
.node {
cursor: pointer;
}
.link {
fill: none;
stroke: #aaa;
stroke-width: 2px;
}
.lhs {
position: fixed;
top: 0;
left: 0px;
border: 3px solid #73AD21;
}
.rhs {
position: fixed;
top: 0;
right: 0px;
border: 3px solid #73AD21;
}
<html>
<body>
<div class="lhs">
<script>
var ret = drawTree(".lhs", treeData);
</script>
</div>
<div class="rhs">
<script>
var ret = drawTree(".rhs", treeData);
</script>
</div>
<body>
Trying to display two tree using d3.js. After adding second tree neither zoom or click event works on first SVG. I added zoom and event by qualifying specific svg class name. Still it doesn't work. Any help please
My mistake. I was manipulating both SVGs with global variable pos_CSS. After adding all elements, when focus moves towards a given SVG (say mouseclick), I forgot to update pos_CSS accordingly (i.e either _lhs or _rhs). By fixing this updation of pos_CSS my problem got solved. Thanks for all your effort in helping me out.

Proper data structure for d3 nodes

I want to build force-directed graph using d3. Each nodes of the graph is a character from Marvel comics (e.g. Spider-man). If the characters appear in one comic there should be a link between the nodes which represent them.
I have a characters_by_comics.json file which contains array of object the following type:
{
"comic_id": 2,
"characters": [
1009220,
1010776,
1009378,
1010363,
1009215,
1009471,
1009718
]
},
I also have characters.json which contains all info about each character including their character_id. In addition, comics.json contains the title of every comic and its comic_id.
The graph is going to be quiet huge. That will affect user experience in a negative way. So, to prevent this I added some information about each character, such as race, gender, alive, etc. Using this information then I am planning to:
Create different filters that can be applied to the graph. For example, if I apply only female filter, only the nodes representing female characters should be visible
Create different types of links: not only appear in one comic, but also belongs to one team, for example.
My question is how can I transform the data I have so it is easy to create nodes and links from it using d3?
You don't include a snippet of characters.json, but that is your node data. Sounds like it might already formatted correctly. It would need to be something like this:
var characters = [
{
id: 1009220,
name: 'Ms Marvel'
}, {
id: 1010776,
name: 'Spiderman'
}
....
];
Now the real question becomes, how do we get your link data from your characters_by_comics.json? Assuming a structure like this:
var charactersByComic = [{
"comic_id": 2,
"characters": [
1009221,
1010776,
...
]
}, {
"comic_id": 3,
"characters": [
1009221,
1009220,
1009379,
...
]
}];
You could do it like:
var linkData = {}; // object to hold data
charactersByComic.forEach(d0 => { // loop the master data
d0.characters.forEach(d1 => { // outer loop of characters
d0.characters.forEach(d2 => { // inner loop of characters
var key = d1 + "|" + d2; // create unique key to prevent duplicate relationshipts
if (d1 !== d2 && !linkData[key]) { // if its not the same character, and they don't already have a relationship
linkData[key] = { // add it
source: d1,
target: d2
};
}
});
});
});
linkData = Object.values(linkData); // take just the array of relationships
This would produce our desired link structure:
[
{"source":1009221,"target":1010776},
{"source":1009221,"target":1009378},
...
]
Now we can jam this whole thing into a force directed graph:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="200" height="200"></svg>
<script>
var characters = [{
id: 1009220,
name: 'Ms Marvel'
}, {
id: 1010776,
name: 'Spiderman'
}, {
id: 1009378
}, {
id: 1010363
}, {
id: 1009215
}, {
id: 1009471
}, {
id: 1009718
}, {
id: 1009221
}, {
id: 1010777
}, {
id: 1009379
}, {
id: 1010361
}, {
id: 1009212
}, {
id: 1009474
}, {
id: 1009715
}];
var charactersByComic = [{
"comic_id": 2,
"characters": [
1009221,
1010776,
1009378,
1010363,
1009215,
1009471,
1009718,
1010777
]
}, {
"comic_id": 3,
"characters": [
1009221,
1009220,
1009379,
1010361,
1009212,
1009474,
1009715,
1010777
]
}];
var linkData = {};
charactersByComic.forEach(d0 => {
d0.characters.forEach(d1 => {
d0.characters.forEach(d2 => {
var key = d1 + "|" + d2;
if (d1 !== d2 && !linkData[key]) {
linkData[key] = {
source: d1,
target: d2
};
}
});
});
});
linkData = Object.values(linkData);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
console.log(d)
return d.id;
}))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(linkData)
.enter().append("line")
.attr("stroke-width", 1);
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(characters)
.enter()
.append("circle")
.attr("r", 5)
.attr("fill", "steelblue");
node.append("title")
.text(function(d) { return d.id; });
simulation
.nodes(characters)
.on("tick", ticked);
simulation.force("link")
.links(linkData);
console.log(simulation)
function ticked() {
link
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
</script>

Plotting data from json file with different date format

I am using graph1.json file which is as given. The createdOn date in stored as date time value. The graph is plotted but at wrong values of createdOn. How to parse the date for plotting the graph.
{
"Vitals": [
{
"createdOn": "2015-08-01 23:35:15.652",
"read": "1",
"ews": 3,
"vitalVal": 78
},
{
"createdOn": "2015-08-01 22:35:15.652",
"read": "1",
"ews": 2,
"vitalVal": 82
},
{
"createdOn": "2015-08-01 21:35:15.652",
"read": "1",
"ews": 2,
"vitalVal": 80
},
{
"createdOn": "2015-08-01 21:25:15.652",
"read": "1",
"ews": 4,
"vitalVal": 101
},
{
"createdOn": "2015-08-01 21:15:15.652",
"read": "1",
"ews": 0,
"vitalVal": 100
},
{
"createdOn": "2015-08-01 21:05:15.652",
"read": "1",
"ews": 1,
"vitalVal": 85
},
{
"createdOn": "2015-08-01 20:59:15.652",
"read": "1",
"ews": 0,
"vitalVal": 91
},
{
"createdOn": "2015-07-27 12:58:15.652",
"read": "1",
"ews": 0,
"vitalVal": 96
},
{
"createdOn": "2015-07-27 12:57:15.652",
"read": "1",
"ews": 0,
"vitalVal": 94
}
],
"unit": "mg"
}
My controller is
.controller('ChartCtrl', ['$scope','$http', function ($scope,$http) {
}])
.directive('linearChart', ['$http',function ($http) {
return {
restrict: 'EA',
link: function (scope, elem, attrs) {
var req = {
method: 'GET',
url: 'js/modules/myvitals/graph1.json',
headers: {
'Content-Type': "application/json"
},
data: {
"userName":'userName'
,"password":'password'
}
};
$http(req).then(function(response){
//console.log(response.data);
scope.data = response.data.SPO2;
var data = scope.data;
var margin = {
top: 40,
right: 20,
bottom: 30,
left: 50
},
width = 365 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
console.log("Date parsed:"+parseDate);
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5).tickFormat(d3.time.format("%d"));
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line1
var valueline1 = d3.svg.line()
.x(function (d) {
return x(new Date(d.createdOn));
// return x(d.date);
})
.y(function (d) {
return y(d.vitalVal);
});
// Adds the svg canvas
var svg = d3.select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return new Date(d.createdOn);
}));
y.domain([0, d3.max(data, function (d) {
return d.vitalVal;
})]);
// Add the valueline1 path.
svg.append("path")
.attr("class", "line")
//.attr("id", "valueline1") //add id to path for hide/show
.attr("d", valueline1(data));
//text label for y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.attr("class", "ylabel")
.text("Measurement (bpm)");
// text label for the x axis
svg.append("text")
.attr("x", width/2 )
.attr("y", height +30)
.style("text-anchor", "middle")
.attr("class", "xlabel")
.text("Date");
// Add the scatterplot for line1
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 4.5)
// .attr("class", "valueline1") //add class to each dot
.style("fill", function (d) {
if (d.ews == 0) return "green";
if (d.ews == 1) return "yellow";
if (d.ews == 2) return "orange";
if (d.ews == 3) return "red";
})
.attr("cx", function (d) {
return x(new Date(d.createdOn));
//return x(parseDate(d.createdOn));
})
.attr("cy", function (d) {
return y(d.vitalVal);
}) .on("mouseover", function () {
return d3.select("#mytooltip").style("visibility", "visible"); //making the tooltip visible
})
.on("mousemove", function (d) {
// console.log()
d3.select("#mytooltip").style("top", (d3.mouse(this)[1] + 12) + "px").style("left", (d3.mouse(this)[0] + 10) + "px");
d3.select("#mytooltip").select("#txvalue").text(function () {
return d.createdOn; //setting the date values to tooltip
});
d3.select("#mytooltip").select("#tyvalue").text(function () {
return d.vitalVal; //setting the date values to tooltip
});
return;
})
.on("mouseout", function () {
return d3.select("#mytooltip").style("visibility", "hidden"); //hidding the tooltip
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// console.log(resposneData);
}, function(error){
console.log(error);
});
}
};
}])
And I am rendering svg in html file
<div ng-controller="ChartCtrl">
<svg linear-chart></svg>
<div class="mytool" id="mytooltip">
<div id="tyvalue"></div>
<div id="txvalue"></div>
</div>
</div>
You can do somthing like this in you tool tip
d3.select("#mytooltip").select("#ttdate").text(function () {
var timeFormat = d3.time.format('%I:%M %p');//to show time in 10.00 AM, 12.30 PM
return timeFormat(new Date(d.date)); //setting the time values to tooltip
});
d3.select("#mytooltip").select("#ttclose").text(function () {
return d.close; //setting the date values to tooltip
});
This is very good tutorial for d3 date formats http://bl.ocks.org/zanarmstrong/ca0adb7e426c12c06a95
Hope this helps!

How to set up links and tooltip in d3 force directed layout

I am trying to put together a force directed layout in d3 but am having some problems getting my links in. I am trying to create links that connect from each of my nodes in the json array to static svg nodes that I created. Do I need to have a json file that includes both links and nodes? Or can I reference them separately. What am I missing in my code to make this happen?
Here's the json file for nodes:
https://api.myjson.com/bins/1rnhq
And here's the json file for links:
var links = [
{ source: academiaNode, target: 0 },
{ source: academiaNode, target: 1 },
{ source: academiaNode, target: 2 },
{ source: academiaNode, target: 3 },
{ source: academiaNode, target: 4 },
{ source: academiaNode, target: 5 },
{ source: academiaNode, target: 6 },
{ source: academiaNode, target: 7 },
{ source: ngoNode, target: 8 },
{ source: ngoNode, target: 9 },
{ source: ngoNode, target: 10 },
{ source: ngoNode, target: 11 },
{ source: ngoNode, target: 12 },
{ source: ngoNode, target: 13 },
{ source: ngoNode, target: 14 },
{ source: ngoNode, target: 15 },
{ source: ngoNode, target: 16 },
{ source: commonwealthNode, target: 17 },
{ source: commonwealthNode, target: 18 },
{ source: commonwealthNode, target: 19 },
{ source: commonwealthNode, target: 20 },
{ source: commonwealthNode, target: 21 },
{ source: commonwealthNode, target: 22 },
{ source: commonwealthNode, target: 23 },
{ source: commonwealthNode, target: 24 },
{ source: commonwealthNode, target: 25 },
{ source: academiaNode, target: 26 },
{ source: commonwealthNode, target: 27 },
{ source: legislatureNode, target: 28 },
{ source: legislatureNode, target: 29 },
{ source: legislatureNode, target: 30 },
{ source: legislatureNode, target: 31 },
{ source: federalNode, target: 32 },
{ source: federalNode, target: 33 },
{ source: federalNode, target: 34 },
{ source: federalNode, target: 35 },
{ source: federalNode, target: 36 },
{ source: federalNode, target: 37 },
{ source: federalNode, target: 38 },
{ source: federalNode, target: 39 },
{ source: federalNode, target: 40 },
{ source: federalNode, target: 41 },
{ source: federalNode, target: 42 },
{ source: federalNode, target: 43 },
{ source: federalNode, target: 44 },
{ source: militaryNode, target: 45 },
{ source: militaryNode, target: 46 }
];
I'm also trying to set up a click function on my nodes so that an svg rectangle expands out from the left of the screen and displays the description of each node. You can see the description I am trying to display in the nodes json file. Here's the d3 code I'm working with to power the visualization.
<script type= "text/javascript">
var w = 1000,
h = 650;
var svg = d3.select("body").append("svg")
.attr("height", 0)
.attr("width", 0)
.style("border", "1px solid black");
var data; // a global
var force = d3.layout.force()
.size([w, h])
.linkDistance([150])
.charge([-1050])
.gravity(0.5)
.on("tick", tick);
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var academiaNode = svg.append("circle")
.attr("cx", 125)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue");
var ngoNode = svg.append("circle")
.attr("cx", 225)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue");
var federalNode = svg.append("circle")
.attr("cx", 325)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue")
var commonwealthNode = svg.append("circle")
.attr("cx", 425)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue");
var legislatureNode = svg.append("circle")
.attr("cx", 525)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue");
var commonwealthNode = svg.append("circle")
.attr("cx", 625)
.attr("cy", 300)
.attr("r", 10)
.attr("fill", "lightblue");
var circles = svg.selectAll(".node");
d3.json("https://api.myjson.com/bins/1rnhq", function(error, json) {
if (error) return console.warn(error);
data = json;
console.log(data);
force.nodes(data).links()
.start();
// Update nodes.
circles = circles.data(data);
circles.exit().remove();
var nodeEnter = circles.enter().append("g")
.attr("class", "node")
.style("fill", "#000")
.style("opacity", 0.75)
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", function(d) { return d.sector == "Academia" ? 1:5 });
nodeEnter.attr("cursor", "pointer");
// Update links
var links = svg.selectAll(".link")
.data(data.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", "1px");
links.exit().remove();
function mouseover() {
d3.select(this).select("circle").transition()
.duration(250)
.attr('r', 10);
}
function mouseout() {
d3.select(this).select("circle").transition()
.duration(250)
.attr('r', 5);
}
nodeEnter.append("text")
.attr("text-anchor", "middle")
.style("font-size", ".75em")
.attr("dy", "-0.85em").text(function (d) { return d.name });
var tooltip = svg.append("rect")
.attr("x", 1000)
.attr("y", 0)
.attr("width", 900)
.attr("height", 700)
.attr("opacity", 0.85);
function click() {
d3.select(tooltip).transition()
.duration(450)
.attr("x", 650)
};
});
function tick() {
links.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
circles.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
};
</script>
The default for the links is: source: index_number, target: index_number
You should have in the source and target the same: or the index number or just an id (which has to be also in the json for the nodes), or a name, ..
So if you don't connect your links with the index_number then you have to add something like this:
var nodeById = d3.map();
graph.nodes.forEach(function(node) {
nodeById.set(node.id, node);
});
graph.links.forEach(function(link) {
link.source = nodeById.get(link.source);
link.target = nodeById.get(link.target);
});
Here in that example i connected the likes with the node.id.
My json file looked like this:
{"nodes": [
{
"id":9053,
"name":"0009053",
"category":"AP"
}
,{
"id":9136,
"name":"Curon Venosta",
"category":"TCS"
}
,{
"id":9116,
"name":"Dummy",
"category":"EQP"
}
,{
"id":9286,
"name":"T",
"category":"EQ"
}
],
"links": [
{
"source":9136,
"target":9053
}
,{
"source":9116,
"target":9136
}
,{
"source":9286,
"target":9116
}
]}
See also this: http://bl.ocks.org/mbostock/533daf20348023dfdd76
Hope this helps you a bit..

Collapsible Tree rendered issue

I am trying to render Collapsible Tree from below link but i am not able to render collapsible tree
http://bl.ocks.org/mbostock/4339083
below is my code and json data.i could n't able to figure out where i made mistake.please help
json data
{
"name": "flare",
"children": [
{
"name": "analytics",
"children": [
{
"name": "cluster",
"children": [
{"name": "AgglomerativeCluster", "size": 3938},
{"name": "CommunityStructure", "size": 3812},
{"name": "HierarchicalCluster", "size": 6714},
{"name": "MergeEdge", "size": 743}
]
},
{
"name": "graph",
"children": [
{"name": "BetweennessCentrality", "size": 3534},
{"name": "LinkDistance", "size": 5731},
{"name": "MaxFlowMinCut", "size": 7840},
{"name": "ShortestPaths", "size": 5914},
{"name": "SpanningTree", "size": 3416}
]
},
{
"name": "optimization",
"children": [
{"name": "AspectRatioBanker", "size": 7074}
]
}
]
}
my code:same code i am using in my application only json path is changed
var margin = { top: 20, right: 120, bottom: 20, left: 120 },
width = 360 - margin.right - margin.left,
height = 200 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function (d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("/Js/flare.json", function (error, flare) {
root = flare;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function (d) { d.y = d.depth * 180; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function (d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function (d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function (d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function (d) { return d.children || d._children ? "end" : "start"; })
.text(function (d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function (d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function (d) {
var o = { x: source.x0, y: source.y0 };
return diagonal({ source: o, target: o });
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = { x: source.x, y: source.y };
return diagonal({ source: o, target: o });
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
}
The problems were small but pesky ones. Here is the FIDDLE with the corrections. You had an extra curly bracket in the end, some missing brackets at the end of the JSON, and finally the width of the graph had to be expanded. Again, small stuff that gets you...
width = 800...