D3.js: Is this good practise for data-DOM-binding? - d3.js

I'm trying to grasp the D3 basics. I understand that it's crucial to get the binding right.
So I did a simple web page with update, enter and exit operations. Every time the data changes (modified, added, removed) I call a function where the data is bound to svg-objects in the update, enter and exit ways.
I wonder if my approach is a good one?
<html>
<head>
<style>
.drawarea { border-style: solid; }
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data, drawArea;
function init(){
data = [{"px" : 25, "py" : 25, "s" : 5}, {"px" : 25, "py" : 50, "s" : 5}, {"px" : 25, "py" : 75, "s" : 10} ];
drawArea = d3.select("#drawareadiv").append("svg:svg")
.attr("class", "drawarea")
.attr("width", 500)
.attr("height", 250);
draw();
}
function draw(){
var domRects = drawArea.selectAll("rect");
// update
domRects
.data(data)
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; });
// enter
domRects
.data(data)
.enter()
.append("svg:rect")
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; });
// exit
domRects
.data(data)
.exit()
.remove();
}
function updateDataAndBinding(){
for(i=0; i<data.length; i++)
data[i].px += 10;
draw();
}
function enterDataAndBinding(){
var px = 25;
var py = 25 * (data.length+1);
var s = Math.floor(data.length/2)*5+5;
data.push({"px" : px, "py" : py, "s" : s});
draw();
}
function exitDataAndBinding(){
data.splice(data.length-1, 1);
draw();
}
</script>
</head>
<body onload="init()">
<div id="drawareadiv"></div>
<button onclick="updateDataAndBinding()">updateDataAndBinding</button>
<button onclick="enterDataAndBinding()">enterDataAndBinding</button>
<button onclick="exitDataAndBinding()">exitDataAndBinding</button>
</body>
</html>

I'd suggest two things:
Don't bind the data again and again. Do this just one time:
var domRects = drawArea.selectAll("rect").data(data);
As this is D3 v4.x, use merge to deal with the "enter" and "update" selections together:
// enter + update
domRects.enter()
.append("svg:rect")
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; })
.merge(domRects)
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; });
Here is the demo (click "run code snippet"):
<style>
.drawarea { border-style: solid; }
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data, drawArea;
function init(){
data = [{"px" : 25, "py" : 25, "s" : 5}, {"px" : 25, "py" : 50, "s" : 5}, {"px" : 25, "py" : 75, "s" : 10} ];
drawArea = d3.select("#drawareadiv").append("svg:svg")
.attr("class", "drawarea")
.attr("width", 500)
.attr("height", 200);
draw();
}
function draw(){
var domRects = drawArea.selectAll("rect").data(data);
// enter
domRects.enter()
.append("svg:rect")
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; })
.merge(domRects)
.attr("x", function(d) { return d.px; })
.attr("y", function(d) { return d.py; })
.attr("width", function(d) { return d.s; })
.attr("height", function(d) { return d.s; });
// exit
domRects.exit()
.remove();
}
function updateDataAndBinding(){
for(i=0; i<data.length; i++)
data[i].px += 10;
draw();
}
function enterDataAndBinding(){
var px = 25;
var py = 25 * (data.length+1);
var s = Math.floor(data.length/2)*5+5;
data.push({"px" : px, "py" : py, "s" : s});
draw();
}
function exitDataAndBinding(){
data.splice(data.length-1, 1);
draw();
}
</script>
</head>
<body onload="init()">
<div id="drawareadiv"></div>
<button onclick="updateDataAndBinding()">updateDataAndBinding</button>
<button onclick="enterDataAndBinding()">enterDataAndBinding</button>
<button onclick="exitDataAndBinding()">exitDataAndBinding</button>
</body>
Other than that, your approach seems to be a good (and standard) one.

Related

D3.JS bar graph in Firefox cshtml

I am trying to put together an interactive bar chart in cshtml.
The good news is it works on every browser except for Firefox.
That being said I'd very much like to know why it is failing on Firefox when it even works on Internet Explorer.. I mean come on, the internet doesn't even work on Internet Explorer.
I have added in what I believe to be the relevant patch of code here:
function buildVisualization(dataSet) {
var barWidth = (chartWidth / dataSet.Items.length - 1) - 1;
var bars = svg.selectAll("rect")
.data(dataSet.Items);
// Build bars for each item
// Example "rect" element: <rect x="200" y="400" width="300" height="100" style="" class="" />
bars.enter()
.append("rect")
.attr("x", function (item, i) { return xScale(new Date(item.DateAsked)) } )
.attr("y", function (item, i) { return chartHeight - yScale(item.Rate)})
.attr("width", function (item) { return barWidth})
.attr("height", function (item) { return yScale(item.Rate)})
.attr("fill", "teal");
bars.exit().remove();
bars.transition()
.attr("x", function (item, i) { return xScale(new Date(item.DateAsked))} )
.attr("y", function (item, i) { return chartHeight - yScale(item.Rate)})
.attr("width", function (item) { return barWidth})
.attr("height", function (item) { return yScale(item.Rate)})
.attr("fill", "teal");
}
That being said I can provide any information required if requested.
I should point out that when run the chart itself is put into the right place however the bars (an important bit of a bar chart) are all pushed off to the left and stacked on top of each other though they do change height when different options are selected so it seems to be something wrong with the positioning rather than with how they are created. Any advice would be quite welcome.
Entire Snippet:
#{
ViewBag.Title = "Bar Chart";
var choices = new List<SelectListItem>
(){
new SelectListItem(){Text= "C#", Value="c#", Selected=true },
new SelectListItem(){Text= ".Net", Value=".net" },
new SelectListItem(){Text= "ASP.Net", Value="asp.net" },
new SelectListItem(){Text= "ASP.Net MVC", Value="asp.net-mvc" },
new SelectListItem(){Text= "C", Value="c" },
new SelectListItem(){Text= "C++", Value="c++" },
new SelectListItem(){Text= "JavaScript", Value="javascript" },
new SelectListItem(){Text= "Objective C", Value="objective-c" },
new SelectListItem(){Text= "PHP", Value="php" },
new SelectListItem(){Text= "Ruby", Value="ruby" },
new SelectListItem(){Text= "Python", Value="python" }
};
}
<style type="text/css">
svg g.axis {
font-size: .75em;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
svg g.axis text.label {
font-size: 2em;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
svg g.axis path,
svg g.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
</style>
<h2>#ViewBag.Title</h2>
<div class="row">
<div class="col-md-8">
<p>This demo takes tag information from data.stackexchange.com and projects it below.</p>
</div>
</div>
<div class="row">
<div class="col-md-4">
#Html.Label("TagChoice", "Tag")
#Html.DropDownList("TagChoice", choices)
</div>
</div>
<div class="row">
<div id="chartContainer">
</div>
</div>
#Scripts.Render("~/bundles/d3")
#section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$("#TagChoice").on("change", function () {
var tag = $(this).val();
var url = "/api/tags?tag=";
url += encodeURIComponent(tag);
$.getJSON(url, function (data) {
buildVisualization(data);
});
});
$("#TagChoice").change();
});
// Overall dimensions of the SVG
var height = 400;
var width = 900;
// Padding...
var leftPadding = 75;
var bottomPadding = 50;
// Actual space for the bars
var chartWidth = width - leftPadding;
var chartHeight = height - bottomPadding;
//Building the scale for the heights
var yScale = d3.scale
.linear()
.range([0, chartHeight])
.domain([0, 21000]);
var yAxisScale = d3.scale
.linear()
.range([chartHeight, 0])
.domain([0, 21000]);
//Building the scale for the bar locations
var xScale = d3.time.scale()
.domain([new Date("5-1-2008"), new Date("2-1-2014")])
.range([leftPadding, width - 10]);
//Building a Y axis
var yAxis = d3.svg.axis()
.scale(yAxisScale)
.orient("left");
// Building an X Axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(d3.time.format("%m/%d/%Y"));
// Build the overall SVG container
var svg = d3.select("#chartContainer")
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "chart");
// Adding the Axes
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + leftPadding + ",0)")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("dy", "-55px")
.attr("dx", "-50px")
.attr("class", "label")
.style("text-anchor", "end")
.text("Number of Questions Asked");
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + chartHeight + ")")
.call(xAxis)
.append("text")
.attr("dy", "40px")
.attr("dx", "475px")
.attr("class", "label")
.style("text-anchor", "end")
.text("Month Asked");
function buildVisualization(dataSet) {
var barWidth = (chartWidth / dataSet.Items.length - 1) - 1;
var bars = svg.selectAll("rect")
.data(dataSet.Items);
// Build bars for each item
// Example "rect" element: <rect x="200" y="400" width="300" height="100" style="" class="" />
bars.enter()
.append("rect")
.attr("x", function (item, i) { return xScale(new Date(item.DateAsked)) })
.attr("y", function (item, i) { return chartHeight - yScale(item.Rate) })
.attr("width", function (item) { return barWidth })
.attr("height", function (item) { return yScale(item.Rate) })
.attr("fill", "teal");
bars.exit().remove();
bars.transition()
.attr("x", function (item, i) { return xScale(new Date(item.DateAsked)) })
.attr("y", function (item, i) { return chartHeight - yScale(item.Rate) })
.attr("width", function (item) { return barWidth })
.attr("height", function (item) { return yScale(item.Rate) })
.attr("fill", "teal");
}
</script>
}
Perhaps the reason of your problem is that in Chrome
>> new Date("5-1-2008")
Thu May 01 2008 ...
while in Firefox:
>> new Date("5-1-2008")
Invalid Date
(this is relevant to lines, where you construct xScale)

How to link multiple graph networks in d3js so that an event in one calls the same event in other networks

I am drawing four network graphs of the same data but using different properties to color the node. Currently, I am able to generate all 4 networks and for each network I am able to double click a node to see the connected nodes of the network. My question is how do I extend this functionality so that if I click a node on any of the graph networks, the other 3 also show me the node I clicked and the connected nodes therein.
This question asked previously Mouseover event on two charts at the same time d3.js does a similar thing for pie charts but I am not sure how I can adapt it to my code.
var drawNetworkFunction = function(descriptor, chartId) {
var width = 470;
var height = 310;
var toggle = 0;
var activenode;
var svg = d3.select(chartId).append("svg")
.attr("width", width)
.attr("height", height);
var container = svg.append("g")
.attr("class", "everything");
if (descriptor == "id" || descriptor == "cluster") {
var color = d3.scaleOrdinal(d3.schemeCategory10);
}
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-7))
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("Perovskite_info.json", function(graph) {
if (descriptor == "cohesive") {
var cscale = d3.scaleLinear()
.domain([1.6, 7.2])
.range([0, 1]);
} else if (descriptor == "similarity") {
var cscale = d3.scaleLinear()
.domain([0, 1])
.range([0, 1]);
}
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke", "#000")
.attr("stroke-opacity", "0.1");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.attr("pvs_id", function(d) { return d.id; })
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) {
var col = '';
if (descriptor == "id") {
col = color(d.group);
} else if (descriptor == "cluster") {
col = color(d.cluster);
} else if (descriptor == "cohesive") {
col = d3.interpolatePurples(cscale(d.cohesive));
} else if (descriptor == "similarity") {
col = d3.interpolateReds(cscale(d.similarity));
}
return col;
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick", connectedNodes);
node.append("title")
.text(function(d) {
return ["Perovskite :" + d.id,
"Cluster :" + d.cluster,
"Cohesive Energy :" + d.cohesive,
"Similarity to CaTiO3 :" + d.similarity
];
});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
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;
});
}
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
linkedByIndex[i + "," + i] = 1;
};
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function HS_f(activenode) {
if (activenode != null) {
var fing_plot = d3.select("#HSA_fingerprint")
.append("svg")
.attr("id", "fin_pl")
.attr("width", 300)
.attr("height", 300);
fing_plot.append('svg:image')
.attr("xlink:href", function() { return "./finger_prints_lo/" + activenode + "_lo.png" })
.attr("width", 250)
.attr("height", 250);
return fing_plot;
}
}
function connectedNodes() {
if (toggle == 0) {
d = d3.select(this).node().__data__;
node.style("opacity", function(o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.15;
});
toggle = 1;
activenode = d.id;
window.activenode = activenode;
console.log(activenode);
HS_f(activenode);
} else {
node.style("opacity", 1);;
toggle = 0;
d3.select("#fin_pl").remove();
}
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return svg;
}
For the json file please refer to the link: https://api.myjson.com/bins/m3gd8
Also my html file is below:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type=" text/javascript " src="http://code.jquery.com/jquery-latest.js "></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="draw_net.js"></script>
<title>Library of Perovskite structures from Materials Project Database</title>
<div id="title_main">
<h2>Graph Network of Perovskite structures from Materials Project Database</h2>
</div>
</head>
<body>
<link rel="stylesheet" href="pvs-net.css" />
<div style="width: 80%; float:left; overflow: auto;">
<div id="Perovskite_Network">
<div style="width: 50%; float:left;">
<div id="Network1">
<div id="title_1">
<h3>Isomap Graph Network</h3>
<script>
var Net1 = drawNetworkFunction('id', '#Network1');
</script>
</div>
</div>
<div id="Network2">
<div style="width: 50%; float:left; overflow: auto;"></div>
<div id="title_2">
<h3>Spectral Clustering on Isomap Graph Network</h3>
<script>
var Net2 = drawNetworkFunction('cluster', '#Network2');
</script>
</div>
</div>
</div>
<div style="width: 50%; float:right; overflow: auto;">
<div id="Network3">
<div id="title_3">
<h3>Calculated Cohesive Energy</h3>
<script>
var Net3 = drawNetworkFunction('cohesive', '#Network3');
</script>
</div>
</div>
<div id="Network4">
<div id="title_4">
<h3>Similarity score against CaTiO3</h3>
<script>
var Net4 = drawNetworkFunction('similarity', '#Network4');
</script>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="width: 20%; height: 500px; float:right;">
<div id="HSA_fingerprint">
<div id="title">
<h3>Hirschfeld Surface Fingerprint Plot</h3>
</div>
</div>
</div>
</body>
</html>
Glad you came back with the data and the HTML. It makes it easier to debug and come up with a solution.
I just changed a couple of lines of code in the connectedNodes function:
Instead of node.style("opacity", function(o) {...}), I replaced it with:
d3.select('#Perovskite_Network').selectAll('.nodes').selectAll('circle').style("opacity", function(o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.15;
});
This would select all circles from all the the SVGs. Let me know if that doesn't help or if you need any improvements.
Snippet:
var drawNetworkFunction = function(descriptor, chartId) {
var width = 470;
var height = 310;
var toggle = 0;
var activenode;
var svg = d3.select(chartId).append("svg")
.attr("width", width)
.attr("height", height);
var container = svg.append("g")
.attr("class", "everything");
if (descriptor == "id" || descriptor == "cluster") {
var color = d3.scaleOrdinal(d3.schemeCategory10);
}
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-7))
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("https://api.myjson.com/bins/m3gd8", function(graph) {
if (descriptor == "cohesive") {
var cscale = d3.scaleLinear()
.domain([1.6, 7.2])
.range([0, 1]);
} else if (descriptor == "similarity") {
var cscale = d3.scaleLinear()
.domain([0, 1])
.range([0, 1]);
}
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke", "#000")
.attr("stroke-opacity", "0.1");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.attr("pvs_id", function(d) { return d.id; })
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) {
var col = '';
if (descriptor == "id") {
col = color(d.group);
} else if (descriptor == "cluster") {
col = color(d.cluster);
} else if (descriptor == "cohesive") {
col = d3.interpolatePurples(cscale(d.cohesive));
} else if (descriptor == "similarity") {
col = d3.interpolateReds(cscale(d.similarity));
}
return col;
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("dblclick", connectedNodes);
node.append("title")
.text(function(d) {
return ["Perovskite :" + d.id,
"Cluster :" + d.cluster,
"Cohesive Energy :" + d.cohesive,
"Similarity to CaTiO3 :" + d.similarity
];
});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
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;
});
}
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
linkedByIndex[i + "," + i] = 1;
}
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function HS_f(activenode) {
if (activenode != null) {
var fing_plot = d3.select("#HSA_fingerprint")
.append("svg")
.attr("id", "fin_pl")
.attr("width", 300)
.attr("height", 300);
fing_plot.append('svg:image')
.attr("xlink:href", function() { return "./finger_prints_lo/" + activenode + "_lo.png" })
.attr("width", 250)
.attr("height", 250);
return fing_plot;
}
}
function connectedNodes() {
if (toggle == 0) {
d = d3.select(this).node().__data__;
d3.select('#Perovskite_Network').selectAll('.nodes').selectAll('circle').style("opacity", function(o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.15;
});
toggle = 1;
activenode = d.id;
window.activenode = activenode;
//console.log(activenode);
HS_f(activenode);
} else {
d3.select('#Perovskite_Network').selectAll('.nodes').selectAll('circle').style("opacity", 1);
toggle = 0;
d3.select("#fin_pl").remove();
}
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return svg;
}
drawNetworkFunction('id', '#Network1');
drawNetworkFunction('cluster', '#Network2');
drawNetworkFunction('cohesive', '#Network3');
drawNetworkFunction('similarity', '#Network4');
<meta charset="utf-8">
<script type=" text/javascript " src="http://code.jquery.com/jquery-latest.js "></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="draw_net.js"></script>
<title>Library of Perovskite structures from Materials Project Database</title>
<div id="title_main">
<h2>Graph Network of Perovskite structures from Materials Project Database</h2>
</div>
<link rel="stylesheet" href="pvs-net.css" />
<div style="width: 80%; float:left; overflow: auto;">
<div id="Perovskite_Network">
<div style="width: 50%; float:left;">
<div id="Network1">
<div id="title_1">
<h3>Isomap Graph Network</h3>
</div>
</div>
<div id="Network2">
<div style="width: 50%; float:left; overflow: auto;"></div>
<div id="title_2">
<h3>Spectral Clustering on Isomap Graph Network</h3>
</div>
</div>
</div>
<div style="width: 50%; float:right; overflow: auto;">
<div id="Network3">
<div id="title_3">
<h3>Calculated Cohesive Energy</h3>
</div>
</div>
<div id="Network4">
<div id="title_4">
<h3>Similarity score against CaTiO3</h3>
</div>
</div>
</div>
</div>
</div>
<div style="width: 20%; height: 500px; float:right;">
<div id="HSA_fingerprint">
<div id="title">
<h3>Hirschfeld Surface Fingerprint Plot</h3>
</div>
</div>
</div>
And a fiddle link: https://jsfiddle.net/shashank2104/bj76ckh4/4/
I have a few suggestions though:
The file is being fetched for every drawNetworkFunction call which slows down the rendering of the page.
Along with fetching of the file, the object linkedByIndex is created in every call which is independent of the descriptor or chartId.
Suggestion: Move the above steps in a single function and pass the linkedByIndex and graph (data) to the drawNetworkFunction and then the rest. Hope this helps.

D3 binding data to SVG tooltip

Id like to use this tooltip from this answer however I can't figure out how to bind data to it.
In this example I'd like to have two circles, that on hover show their size value as text.
watch.csv
circle,size
green,5
yellow,10
code
d3.csv("watch.csv", function(error, watch) {
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text(function(d) { return d.size; }) //TRYING THIS
var sampleSVG = d3.select(".example_div")
.append("svg:svg")
.attr("class", "sample")
.attr("width", 300)
.attr("height", 300);
d3.select(".example_div svg")
.data(watch) //AND THIS
.enter()
.append("svg:circle")
.attr("stroke", "black")
.attr("fill", "aliceblue")
.attr("r", 30)
.attr("cx", 52)
.attr("cy", 52)
.on("mouseover", function() {
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
return tooltip.style("top", (d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function() {
return tooltip.style("visibility", "hidden");
});
});
Plunker
Change your tooltip var for this:
var tooltip = d3.select("body")
.append("div")
.attr("class", "someTooltip")
.style("opacity", 0);
Style your tooltip in the CSS, using the selector .someTooltip.
And change all your "mouseove", "mousemove" and "mouseout" for this:
.on("mousemove", function(d) {
tooltip.html("The size is: " + d.size)
.style("top", (d3.event.pageY - 10) + "px")
.style("left", (d3.event.pageX + 10) + "px")
.style("opacity", 1);
}).on("mouseout", function(){
tooltip.style("opacity", 0);
});
First you need to add jquery and tipsy which is a jquery plugin.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.3/jquery.tipsy.js"></script>
tipsy css
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.3/jquery.tipsy.css" rel="stylesheet" type="text/css" />
Next you need to bind the data to the tipsy jquery way like this.
$('svg circle').tipsy({ //select all circles
gravity: 'w',
html: true,
title: function() {
var d = this.__data__;//get the data from the dom
return 'Hi there! My color is <span style="color:' + d.circle + '">' + d.size + '</span>'; //make the tipsy tool tip using the data
}
});
Remove all the tooltip code like this as that is not needed:
.on("mouseover", function() {
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
return tooltip.style("top", (d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function() {
return tooltip.style("visibility", "hidden");
});
Remove this
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text(function(d) { return d.size; }) //TRYING THIS
So your code will look like this here

Render multiple svg in d3js

Im trying to render circles in d3js. On multiply svg:s. In my HTML i have all the svg:s likte this.
<section id="a" class="render">
<svg></svg>
</section>
<section id="b" class="render">
<svg></svg>
</section>
<section id="c" class="renderr">
<svg></svg>
</section>
<section id="d" class="render">
<svg></svg>
</section>
What im trying to do is this. Depending on some values i get back from a json-call i want to render and animate the circles in different svgs.
My javascript looks like this.
for(i = 0; i<json.answers[0].length; i++) {
personal.color = json.answers[0][i].color;
personal.answer = json.answers[0][i].alternative_id;
if(json.answers[0][i].alternative_id == 1) {
drawSvg("#a")
}
if(json.answers[0][i].alternative_id == 2) {
drawSvg("#b")
}
if(json.answers[0][i].alternative_id == 3) {
drawSvg("#c")
}
if(json.answers[0][i].alternative_id == 4) {
drawSvg("#d")
}
createCircle(personal);
}
drawSvg = function(el) {
svg = d3.select(el+ " svg")
.attr("width", svgWidth)
.attr("height", svgHeight)
force.on("tick", function(e) {
svg.selectAll("path")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
}
);
});
}
createCircle = function(p) {
people.push({
type: "circle",
size: Math.random() * 1200 + 700
});
force.start();
svg.selectAll("path")
.data(people)
.enter().append("path")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("d", d3.svg.symbol()
.size(function(d) { return d.size; })
.type(function(d) { return d.type; }))
.style("fill", p.color)
.attr("class","person")
.attr("id","p_"+index)
index++;
}

How to align two svg's side by side in d3.js

I have two graphs(rectangles with text the other circles with text) to be displayed but instead of displaying one below the other,I want to display side by side i.e 2 charts displaying horizontally(one at the left of div and the other at right of div). I created 2 svg's and added the charts in to that. However when ever i change the top or bottom margin it is not working.
My code goes like:
<!DOCTYPE html>
<html xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Circle legends</title>
<script type="text/javascript" src="../../js/d3/d3.v3.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js?1.27.2"></script>
<link rel="stylesheet" href="../../css/style.css" />
<style type="text/css">
</style>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var width=960,height=500;
var margin = {top: 29.5, right: 29.5, bottom: 29.5, left: 59.5};
radiusScale = d3.scale.sqrt().domain([1, 100]).range([10, 39]),
colorScale = d3.scale.category10();
//Create the SVG for legends.
var svglegend = d3.select("#chart").append("svg").attr("id","svglegend")
.attr("width", width-100)
.attr("height", height -100)
.append("g")
.attr("transform", "translate(" + margin.left + "," + (margin.top +30) + ")");
//alert("Non-empty");
d3.json("SbuLegendData.json", function(data) {
jsondata = data;
rectangle= svglegend.selectAll("rect").data(data).enter().append("rect");
var RectangleAttrb = rectangle.attr("x", function (d) { return d.x_axis; })
.attr("y", function (d) { return d.y_axis; })
.attr("width",function(d) { return d.width; } )
.attr("height",function(d) { return d.height; })
.style("fill", function(d) { return d.color; });
var textparam = svglegend.selectAll("text").data(data).enter().append("text");
var text = textparam .attr("x", function (d) { return d.x_axis + d.width +10; })
.attr("y", function (d) { return d.y_axis + d.height-5; })
.attr("width",30 )
.attr("height",20)
.text(function(d) { return d.text; });
});
// Create the SVG container and set the origin.
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var i =0;
while (i<=50)
{
console.log("i value is " + i + " value of scale " +i+ " is " + radiusScale(i));
var g = svg.append("g");
g.append("circle")
.attr("id","circle" + i)
.attr("cx", i*12 )
.attr("cy", 30)
.attr("fill",colorScale(i))
.attr("r", radiusScale(i));
g.append("text").attr("dx",i*12).text(Math.round(radiusScale(i)));
i=i+10;
}
</script>
</body>
</html>
the json data contains:
[
{ "x_axis":40, "y_axis": 10,"width":50,"height":20,"color" : "#1f77b4","text":"F&R"},
{ "x_axis":40, "y_axis": 30,"width":50,"height":20,"color" : "#ff7f0e","text":"Legal"},
{ "x_axis":40, "y_axis": 50,"width":50,"height":20,"color" : "#2ca02c","text":"GGO"},
{ "x_axis":40, "y_axis": 70,"width":50,"height":20,"color" : "#d62728","text":"IP&S"},
{ "x_axis":40, "y_axis": 90,"width":50,"height":20,"color" : "#9467bd","text":"CORP"},
{ "x_axis":40, "y_axis": 110,"width":50,"height":20,"color": "#8c564b","text":"TAX"},
{ "x_axis":40, "y_axis": 130,"width":50,"height":20,"color" : "#e377c2","text":"REUTERS ALL"}
]
You need to use CSS for this. It's easier if you have two containers:
CSS:
.container {
float: left;
}
HTML:
<div class="container" id="chart1">
</div>
<div class="container" id="chart2">
</div>
Then use #chart1 and #chart2 in your code.

Resources