d3.js Bubble distribution to match container dimensions - javascript

I want to create a dynamic .container where each circle preserves its size ratio and always distributes to fit the available space of the .container.
How do I modify the code so that the distribution of the data points always resizes to the bounds of the .container while maintaining the size ratio of each circle?
.container {
width: 400px;
height: 200px;
}
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
2,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg"
],
[
"Environment",
8,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg"
],
[
"Medical",
6,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg"
],
[
"Food",
4,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg"
]
]
};
var width = 200;
var height = 200;
var tooltip = d3
.select(".bubble_chart")
.append("div")
.classed("tooltip", true);
var svg = d3
.select(".bubble_chart")
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height);
var bubble = d3.layout
.pack()
.size([200, 200])
.value(function(d) {
return d.size;
})
.padding(12);
// generate data with calculated layout values
var nodes = bubble.nodes(processData(json)).filter(function(d) {
return !d.children;
}); // filter out the outer bubble
var vis = svg.selectAll("circle").data(nodes, function(d, i) {
return d.name + i;
});
vis
.enter()
.append("circle")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.attr("class", function(d) {
return d.className;
})
.attr("r", 0)
.transition()
.duration(1000)
.attr("r", function(d) {
return d.r;
});
vis
.enter()
.append("svg:image")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("x", d => -(d.r / 1.5) / 2)
.attr("y", d => -(d.r / 1.5) / 2)
.attr("xlink:href", function(d) {
return d.img;
})
.attr("width", d => d.r / 1.5)
.transition()
.duration(1000)
.style("opacity", 1);
/*
vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 5 / 100))
.text(d => d.name);
*/
/* vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 3 / 100))
.text(d => d.value);
*/
vis
.on("mousemove", function(d) {
tooltip
.style("opacity", 1)
.style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px")
.style("top", d3.event.y + 25 + "px").html(`
<p>Category: ${d.name}</p>
<p>Ordered: ${d.value}</p>
`);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
function processData(data) {
var obj = data.call_data;
var newDataSet = [];
for (var prop in obj) {
newDataSet.push({
name: obj[prop][0],
className: obj[prop][0].toLowerCase(),
size: obj[prop][1],
img: obj[prop][2]
});
}
return {
children: newDataSet
};
}
var aspect = width / height,
chart = d3.select('.bubble_chart');
d3.select(window)
.on("resize", function() {
var targetWidth = chart.node().getBoundingClientRect().width;
chart.attr("width", targetWidth);
chart.attr("height", targetWidth / aspect);
});
})();
.container {
border: 2px solid red;
width: 400px;
height: 200px;
}
.bubble_chart {
flex: 1;
border: 2px solid
}
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.tooltip {
opacity: 0;
position: absolute;
pointer-events: none;
background-color: #fafafa;
border-radius: 8px;
padding: 15px;
z-index: 999;
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1)
}
.tooltip p {
margin: 0;
}
.tooltip:before {
content: " ";
position: absolute;
border: 12px solid transparent;
border-bottom-color: #fafafa;
top: -20px;
left: 50%;
margin-left: -12px;
}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script>
<div class="container">
<div class="bubble_chart"></div>
</div>

You should set your width and height to the bounding rect height and width at the outset. Right now you have it set as both 200px, which are the same.
Do that like this:
var width = document.querySelector(".container").getBoundingClientRect().width;
var height = document.querySelector(".container").getBoundingClientRect().height;
(function() {
var json = {
call_data: [
[
"Lifestyle",
1,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5bb3ce2f801fbc657f83dd57_pp-lifestyle(white).svg"
],
[
"Sports",
2,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/5c9131911ad86f445cb5abc7_pp-sport(white).svg"
],
[
"Environment",
8,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4bef42fff000159ba7a_pp-environ(white).svg"
],
[
"Medical",
6,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f2a4dc831e8500015fda53_pp-health(white).svg"
],
[
"Food",
4,
"https://uploads-ssl.webflow.com/59df9e77ad9420000140eafe/59f8c2cc78cc2d0001fd4a7e_pp-food(white).svg"
]
]
};
var width = document.querySelector(".container").getBoundingClientRect().width;
var height = document.querySelector(".container").getBoundingClientRect().height;
var tooltip = d3
.select(".bubble_chart")
.append("div")
.classed("tooltip", true);
var svg = d3
.select(".bubble_chart")
.append("svg")
//responsive SVG needs these 2 attributes and no width and height attr
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 " + width + " " + height);
var bubble = d3.layout
.pack()
.size([200, 200])
.value(function(d) {
return d.size;
})
.padding(12);
// generate data with calculated layout values
var nodes = bubble.nodes(processData(json)).filter(function(d) {
return !d.children;
}); // filter out the outer bubble
var vis = svg.selectAll("circle").data(nodes, function(d, i) {
return d.name + i;
});
vis
.enter()
.append("circle")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.attr("class", function(d) {
return d.className;
})
.attr("r", 0)
.transition()
.duration(1000)
.attr("r", function(d) {
return d.r;
});
vis
.enter()
.append("svg:image")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("x", d => -(d.r / 1.5) / 2)
.attr("y", d => -(d.r / 1.5) / 2)
.attr("xlink:href", function(d) {
return d.img;
})
.attr("width", d => d.r / 1.5)
.transition()
.duration(1000)
.style("opacity", 1);
/*
vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 5 / 100))
.text(d => d.name);
*/
/* vis
.enter()
.append("text")
.attr("transform", d => "translate(" + d.x + "," + d.y + ")")
.attr("fill", "white")
.attr("text-anchor", "middle")
.attr("font-size", d => d.r / (d.r * 3 / 100))
.text(d => d.value);
*/
vis
.on("mousemove", function(d) {
tooltip
.style("opacity", 1)
.style("left", d3.event.x - tooltip.node().offsetWidth / 2 + "px")
.style("top", d3.event.y + 25 + "px").html(`
<p>Category: ${d.name}</p>
<p>Ordered: ${d.value}</p>
`);
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
function processData(data) {
var obj = data.call_data;
var newDataSet = [];
for (var prop in obj) {
newDataSet.push({
name: obj[prop][0],
className: obj[prop][0].toLowerCase(),
size: obj[prop][1],
img: obj[prop][2]
});
}
return {
children: newDataSet
};
}
var aspect = width / height,
chart = d3.select('.bubble_chart');
d3.select(window)
.on("resize", function() {
var targetWidth = chart.node().getBoundingClientRect().width;
chart.attr("width", targetWidth);
chart.attr("height", targetWidth / aspect);
});
})();
.container {
border: 2px solid red;
width: 400px;
height: 200px;
}
.bubble_chart {
flex: 1;
border: 2px solid
}
.lifestyle {
fill: #89BED3;
}
.sports {
fill: #2A83D4;
}
.environment {
fill: #6CC070;
}
.food {
fill: #665C9E;
}
.medical {
fill: #C13E40;
}
.tooltip {
opacity: 0;
position: absolute;
pointer-events: none;
background-color: #fafafa;
border-radius: 8px;
padding: 15px;
z-index: 999;
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, .1)
}
.tooltip p {
margin: 0;
}
.tooltip:before {
content: " ";
position: absolute;
border: 12px solid transparent;
border-bottom-color: #fafafa;
top: -20px;
left: 50%;
margin-left: -12px;
}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.js"></script>
<div class="container">
<div class="bubble_chart"></div>
</div>

Related

Heatmaps do not control ordering properly

I am trying to compare the variables data1, data2 and data3 using three heatmaps. When I try to order the variables R, S and T by clicking on them, the order is only controlled by the top heatmap. How can I control the order with the two lower heatmaps as well?
The colors are scaled from1 to 10, green 1, red 10.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<style>
.heatmap {
font-size: 8px;
font-family: monospace;
}
rect.bordered {
stroke: #E6E6E6;
stroke-width:2px;
}
text.mono {
font-size: 8px;
font-family: monospace;
fill: #000;
}
text.legendElement {
font-size: 10px;
}
text.hover {
font-weight: bold;
fill: #d62419;
font-background: #000;
}
.heatmap_tooltip {
text-align: center;
font-family: monospace;
font-size: 10pt;
color: #000;
position: relative;
background: rgba(255, 255, 255, 0.8);
border: 4px solid #d62419;
padding: 5px;
border-radius: 8px ;
-webkit-border-top-left-radius: 8px;
-webkit-border-top-right-radius: 8px;
-webkit-border-bottom-right-radius: 8px;
-webkit-border-bottom-left-radius: 8px;
-khtml-border-top-left-radius: 8px;
-khtml-border-top-right-radius: 8px;
-khtml-border-bottom-right-radius: 8px;
-khtml-border-bottom-left-radius: 8px;
-moz-border-radius-topleft: 8px;
-moz-border-radius-topright: 8px;
-moz-border-radius-bottomright: 8px;
-moz-border-radius-bottomleft: 8px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
width: 50px;
z-index:10000;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8);
}
.heatmap_tooltip:after, .heatmap_tooltip:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.heatmap_tooltip:after {
border-color: rgba(236, 240, 241, 0);
border-top-color: #FFFFF;
border-width: 10px;
left: 50%;
margin-left: -10px;
}
.heatmap_tooltip:before {
border-color: rgba(44, 62, 80, 0);
border-top-color: #d62419;
border-width: 16px;
left: 50%;
margin-left: -16px;
}
</style>
</head>
<body>
<div class="bar_holder" align = "center">
<div id="heatmap1"></div>
<div id="heatmap2"></div>
<div id="heatmap3"></div>
<div id="heatmap4"></div>
<div id="heatmap5"></div>
</div>
<script>
var paletteName = "Spectral";
var colorbrewer = {Spectral: {3: ["#005824","#ffffff","#91003F"],21: ["#005824","#1A693B","#347B53","#4F8D6B","#699F83","#83B09B","#9EC2B3","#B8D4CB","#D2E6E3","#EDF8FB","#FFFFFF","#F1EEF6","#E6D3E1","#DBB9CD","#D19EB9","#C684A4","#BB6990","#B14F7C","#A63467","#9B1A53","#91003F"]}};
var rowtopics = [["R"],["S"],["T"]];
var coltopics = [["R","MS"],["R","MT"],["R","MU"],["R","MV"],["R","MW"],["R","MX"],["R","NI"],["R","NJ"],["R","NL"]];
var data1 = [["1","2","3","4","5","6","7","8","9"],["2","3","1","5","4","7","8","9","1"],["2","4","5","6","7","8","2","1","9"]];
var data2 = [["9","8","7","6","5","4","3","2","1"],["1","3","4","5","6","2","3","9","1"],["3","4","8","5","7","8","9","1","2"]];
var data3 = [["6","5","7","6","2","4","3","2","8"],["7","3","4","5","6","7","8","9","3"],["3","8","5","6","2","8","9","6","2"]];
var row_number = rowtopics.length;
var col_number = coltopics.length;
var minval=parent.minval;
var maxval=parent.maxval;
var fitems=parent.fitems;
var round = 0;
var datat = ["data1", "data2", "data3", "data4", "data5"];
var datas = data1;
var heatmaps = ["#heatmap1","#heatmap2","#heatmap3","#heatmap4","#heatmap5"];
var heatmapId = heatmaps[round];
var classesNumber = 21,
cellSize = 20;
var margin = {top: 5, right: 20, bottom: 10, left: 40},
width = 960 - margin.left - margin.right,
height = 125 - margin.left - margin.right;
function heatmap_display(heatmapId, paletteName) {
var tooltip = d3.select(heatmapId)
.append("div")
.style("position", "absolute")
.style("visibility", "hidden");
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);
var viewerWidth = 960;
var viewerHeight = 150;
var viewerPosTop = 20;
var viewerPosLeft = 150;
var legendElementWidth = cellSize * 2;
var colors = colorbrewer[paletteName][classesNumber];
var svg;
var colorScale = d3.scale.quantize()
.domain([1, 10])
.range(colors);
//d3.selectAll(heatmapId +" > *").remove();
svg = d3.select(heatmapId).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.call(zoomListener)
.append("g")
.attr("transform", "translate(" + viewerPosLeft + "," + viewerPosTop + ")");
svg.append('defs')
.append('pattern')
.attr('id', 'diagonalHatch')
.attr('patternUnits', 'userSpaceOnUse')
.attr('width', 4)
.attr('height', 4)
.append('path')
.attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2')
.attr('stroke', '#000000')
.attr('stroke-width', 1);
var rowSortOrder = false;
var colSortOrder = false;
var rowLabels = svg.append("g")
.attr("class", "rowLabels")
.selectAll(".rowLabel")
.data(rowtopics)
.enter().append("text")
.text(function(d) {
return d.count > 1 ? d.join("/") : d;
})
.attr("x", 0)
.attr("y", function(d, i) {
return (i * cellSize);
})
.style("text-anchor", "end")
.attr("transform", function(d, i) {
return "translate(-3," + cellSize / 1.5 + ")";
})
.attr("class", "rowLabel mono")
.attr("id", function(d, i) {
return "rowLabel_" + i;
})
.on('mouseover', function(d, i) {
d3.select('#rowLabel_' + i).classed("hover", true);
})
.on('mouseout', function(d, i) {
d3.select('#rowLabel_' + i).classed("hover", false);
})
.on("click", function(d, i) {
rowSortOrder = !rowSortOrder;
sortByValues("r", i, rowSortOrder);
d3.select("#order").property("selectedIndex", 0);
});
var colLabels = svg.append("g")
.attr("class", "colLabels")
.selectAll(".colLabel")
.data(coltopics)
.enter().append("text")
.text(function(d) {
d.shift();
return d.count > 1 ? d.reverse().join("/") : d.reverse();
})
.attr("x", 0)
.attr("y", function(d, i) {
return (i * cellSize);
})
.style("text-anchor", "left")
.attr("transform", function(d, i) {
return "translate(" + cellSize / 2 + ", -3) rotate(-90) rotate(45, 0, " + (i * cellSize) + ")";
})
.attr("class", "colLabel mono")
.attr("id", function(d, i) {
return "colLabel_" + i;
})
.on('mouseover', function(d, i) {
d3.select('#colLabel_' + i).classed("hover", true);
})
.on('mouseout', function(d, i) {
d3.select('#colLabel_' + i).classed("hover", false);
})
.on("click", function(d, i) {
colSortOrder = !colSortOrder;
sortByValues("c", i, colSortOrder);
d3.select("#order").property("selectedIndex", 0);
});
var row = svg.selectAll(".row")
.data(datas)
.enter().append("g")
.attr("id", function(d) {
return d.idx;
})
.attr("class", "row");
var j = 0;
var heatMap = row.selectAll(".cell")
.data(function(d) {
j++;
return d;
})
.enter().append("svg:rect")
.attr("x", function(d, i) {
return i * cellSize;
})
.attr("y", function(d, i, j) {
return j * cellSize;
})
.attr("rx", 4)
.attr("ry", 4)
.attr("class", function(d, i, j) {
return "cell bordered cr" + j + " cc" + i;
})
.attr("row", function(d, i, j) {
return j;
})
.attr("col", function(d, i, j) {
return i;
})
.attr("width", cellSize)
.attr("height", cellSize)
.style("fill", function(d) {
if (d != null) return colorScale(d);
else return "url(#diagonalHatch)";
})
.on('mouseover', function(d, i, j) {
d3.select('#colLabel_' + i).classed("hover", true);
d3.select('#rowLabel_' + j).classed("hover", true);
d3.select(this).style("stroke", "#000");
if (d != null) {
tooltip.html('<div class="heatmap_tooltip">' + String(Number(d).toFixed(3))) + '</div>';
tooltip.style("visibility", "visible");
} else
tooltip.style("visibility", "hidden");
})
.on('mouseout', function(d, i, j) {
d3.select('#colLabel_' + i).classed("hover", false);
d3.select('#rowLabel_' + j).classed("hover", false);
d3.select(this).style("stroke", "none");
tooltip.style("visibility", "hidden");
})
.on("mousemove", function(d, i) {
tooltip.style("top", (d3.event.pageY - 55) + "px").style("left", (d3.event.pageX - 80) + "px");
})
.on('click', function() {
});
function sortByValues(rORc, i, sortOrder) {
for ( x = 0; x < heatmaps.length; x++ ) {
svg = d3.select(heatmaps[x])
var t = svg.transition().duration(1000);
var values = [];
var sorted;
d3.selectAll(".c" + rORc + i)
.filter(function(d) {
if (d != null) values.push(d);
else values.push(-999);
});
if (rORc == "r") {
sorted = d3.range(col_number).sort(function(a, b) {
if (sortOrder) {
return values[b] - values[a];
} else {
return values[a] - values[b];
}
});
t.selectAll(".cell")
.attr("x", function(d) {
var col = parseInt(d3.select(this).attr("col"));
return sorted.indexOf(col) * cellSize;
});
t.selectAll(".colLabel")
.attr("y", function(d, i) {
return sorted.indexOf(i) * cellSize;
})
.attr("transform", function(d, i) {
return "translate(" + cellSize / 2 + ", -3) rotate(-90) rotate(45, 0, " + (sorted.indexOf(i) * cellSize) + ")";
});
} else {
sorted = d3.range(row_number).sort(function(a, b) {
if (sortOrder) {
return values[b] - values[a];
} else {
return values[a] - values[b];
}
});
t.selectAll(".cell")
.attr("y", function(d) {
var row = parseInt(d3.select(this).attr("row"));
return sorted.indexOf(row) * cellSize;
});
t.selectAll(".rowLabel")
.attr("y", function(d, i) {
return sorted.indexOf(i) * cellSize;
})
.attr("transform", function(d, i) {
return "translate(-3," + cellSize / 1.5 + ")";
});
}
}
}
}
for ( x = 0; x < 3; x++ ) {
heatmapId = heatmaps[x];
if (x == 0)
datas = data1;
if (x == 1)
datas = data2;
if (x == 2)
datas = data3;
heatmap_display(heatmapId, paletteName);
round +=1;
}
</script>
</body>
</html>

D3 multi line data point circle getting out of line

I've been trying to build a multiline chart of three lines and display tooltip along with circles on data points when hovered over. However the circle is not following the line and at certain data points and it comes out of the line. Setting the element focus, for the particular line by adjusting transform, translate for the specific line solves the issue but then messes up the other lines. How to pass all the datasets instead of one dataset on focus element? I tried sorting all the datasets in one common dataset consisting of all the objects and pass it on transform of focus but that is also making the circle shift away from the lines at certain datapoints
drawAUCROCGraphExpanded(fprTpr_train, fprTpr_test, fprTpr_oot, fprTpr_default, trainroc, testroc, ootroc) {
var margin = { top: 20, right: 0, bottom: 20, left: 0 },
width = 560 - margin.left - margin.right,
height = 395 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// Draw the X-axis on the DOM
this.aucRocSvgExpanded.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(d3.axisBottom(x).ticks(5));
// Draw the Y-axis on the DOM
this.aucRocSvgExpanded.append('g')
.attr('transform', 'translate(0, 0)')
.call(d3.axisLeft(y).ticks(10));
var valueline = d3.line()
.curve(d3.curveMonotoneX)
.x(function (d: any) { return x(d.fpr); })
.y(function (d: any) { return y(d.tpr); });
var valueline2 = d3.line()
.curve(d3.curveMonotoneX)
.x(function (d: any) { return x(d.fpr); })
.y(function (d: any) { return y(d.tpr); });
var valueline3 = d3.line()
.curve(d3.curveMonotoneX)
.x(function (d: any) { return x(d.fpr); })
.y(function (d: any) { return y(d.tpr); });
var valueline4 = d3.line()
.curve(d3.curveMonotoneX)
.x(function (d: any) { return x(d.fpr); })
.y(function (d: any) { return y(d.tpr); });
x.domain([0, 1]);
y.domain([0, 1]);
this.aucRocSvgExpanded.append("path")
.attr("style", 'stroke: #c1c2c2; stroke-width: 2; fill: none; stroke-dasharray: 3, 4.5;')
.attr("d", valueline(fprTpr_default))
this.aucRocSvgExpanded.append("path")
.attr("style", 'stroke: #2E4A71; stroke-width: 2; fill: none;')
//.style('fill', d => fprTpr_flag == true ? '#e6e8ed;' : null )
.attr("d", valueline2(fprTpr_train))
.attr("class", "line")
.attr("width", width)
.attr("height", height)
if (fprTpr_test.length > 0) {
this.aucRocSvgExpanded.append("path")
.attr("style", 'stroke: #517BAD; stroke-width: 2; fill: none;')
//.style('fill', d => fprTpr_flag == true ? '#e6e8ed;' : null )
.attr("d", valueline3(fprTpr_test))
.attr("class", "line")
.attr("width", width)
.attr("height", height)
}
if (fprTpr_oot.length > 0) {
this.aucRocSvgExpanded.append("path")
.attr("style", 'stroke: #74A0D8; stroke-width: 2; fill: none;')
.attr("d", valueline4(fprTpr_oot))
.attr("class", "line")
.attr("width", width)
.attr("height", height)
}
var focus = this.aucRocSvgExpanded.append("g")
.attr("class", "focus")
.style("display", "none")
// append the x line
focus.append("line")
.attr("class", "x")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("y1", 0)
.attr("y2", height);
// append the circles at the intersection
focus.append("circle")
.attr("id", "train_circle")
.style("fill", "#2E4A71")
.style("stroke", "#2E4A71")
.attr("r", 4);
if (fprTpr_test.length > 0) {
focus.append("circle")
.attr("id", "test_circle")
.style("fill", "#517BAD")
.style("stroke", "#517BAD")
.attr("r", 4);
}
if (fprTpr_oot.length > 0) {
focus.append("circle")
.attr("id", "oot_circle")
.style("fill", "#74A0D8")
.style("stroke", "#74A0D8")
.attr("r", 4);
}
var bisectData = d3.bisector((d: any) => d.fpr).right,
sortData_train = fprTpr_train.sort(function (a, b) { return d3.ascending(a.fpr, b.fpr) }),
sortData_test = fprTpr_test.sort(function (a, b) { return d3.ascending(a.fpr, b.fpr) }),
sortData_oot = fprTpr_oot.sort(function (a, b) { return d3.ascending(a.fpr, b.fpr) })
const mouseover = () => {
focus.style("display", null);
this.roc_tooltipExpanded.style("display", "block")
}
const mouseout = () => {
focus.style("display", "none");
this.roc_tooltipExpanded.style("display", "none")
}
const mousemove = (event) => {
var x0 = x.invert(d3.pointer(event)[0]),
i = bisectData(sortData_train, x0, 1),
j = bisectData(sortData_test, x0, 1),
k = bisectData(sortData_oot, x0, 1),
a = sortData_train[i].fpr,
d = sortData_train[i].tpr
if (fprTpr_test.length > 0) {
var b = sortData_test[j].fpr,
e = sortData_test[j].tpr
}
if (fprTpr_oot.length > 0) {
var c = sortData_oot[k].fpr,
f = sortData_oot[k].tpr
}
if (fprTpr_oot.length > 0) {
focus.attr("transform", "translate(" + x(sortData_oot[k].fpr) + "," + 0 + ")");
} else if (fprTpr_test.length > 0) {
focus.attr("transform", "translate(" + x(sortData_test[j].fpr) + "," + 0 + ")"); //selecting one of this fixes issue for the particular line but messes up others
} else {
focus.attr("transform", "translate(" + x(sortData_train[i].fpr) + "," + 0 + ")");
}
var roc_label;
if (fprTpr_oot.length > 0 && fprTpr_test.length > 0) {
roc_label = `<div style="height: 20px; padding: 2px 4px; background-color: #E6E8ED;"">AUC:</div><div style="background-color: #fff; padding: 2px 4px"><div style = "color: #2E4A71;"><span>Train:</span> ${trainroc} - <b>${d}</b></div><div style="color: #517BAD;"><span style="padding: 0px 7px 0px 0px;">Test:</span> ${testroc} - <b>${e}</b></div><div style="color: #74A0D8;"><span style="padding: 0px 6px 0px 0px;">OOT:</span> ${ootroc} - <b>${f}</b></div></div>`;
} else if (fprTpr_test.length > 0 && fprTpr_oot.length <= 0) {
roc_label = `<div style="height: 20px; padding: 2px 4px; background-color: #E6E8ED;"">AUC:</div><div style="background-color: #fff; padding: 2px 4px"><div style = "color: #2E4A71;><span>Train:</span> ${trainroc} - <b>${d}</b></div><div style="color: #517BAD;><span style="padding: 0px 7px 0px 0px;">Test:</span> ${testroc} - <b>${e}</b></div></div>`;
} else if (fprTpr_test.length <= 0 && fprTpr_oot.length > 0) {
roc_label = `<div style="height: 20px; padding: 2px 4px; background-color: #E6E8ED;"">AUC:</div><div style="background-color: #fff; padding: 2px 4px"><div style = "color: #2E4A71;><span>Train:</span> ${trainroc} - <b>${d}</b></div><div style="color: #74A0D8;"><span style="padding: 0px 6px 0px 0px;">OOT:</span> ${ootroc} - <b>${f}</b></div></div>`;
} else {
roc_label = `<div style="height: 20px; padding: 2px 4px; background-color: #E6E8ED;"">AUC:</div><div style="background-color: #fff; padding: 2px 4px"><div style = "color: #2E4A71;><span>Train:</span> ${trainroc} - <b>${d}</b></div></div>`;
}
this.roc_tooltipExpanded
.html(roc_label)
// .style("left", (d3.pointer(event)[0]+40) + "px")
.style("right", (d3.pointer(event)[0]) + "px")
.style("top", (d3.pointer(event)[1]) + "px")
.style("pointer-events", "none")
.style("z-index", "1")
.style("display", "block")
focus.select("circle#train_circle").attr("transform", "translate(" + x(0) + "," + y(sortData_train[i].tpr) + ")")
if (fprTpr_test.length > 0) {
focus.select("circle#test_circle").attr("transform", "translate(" + x(0) + "," + y(sortData_test[j].tpr) + ")")
}
if (fprTpr_oot.length > 0) {
focus.select("circle#oot_circle").attr("transform", "translate(" + x(0) + "," + y(sortData_oot[k].tpr) + ")")
}
}
this.aucRocSvgExpanded.append("g")
.append("rect")
.attr("class", "rect")
.attr("width", width)
.attr("height", height)
.style("fill", "transparent")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("mousemove", mousemove);
this.aucRocSvgExpanded.append("g")
.append("text")
.attr('y', 390)
.attr('x', 280)
.style("font-size", "14px")
.style("font-weight", "600")
.style("text-anchor", "middle")
.text("FPR");
this.aucRocSvgExpanded.append("g")
.append("text")
.attr("transform", "rotate(-90)")
.attr('y', -35)
.attr('x', -180)
.style("font-size", "14px")
.style("font-weight", "600")
.style("text-anchor", "middle")
.text("TPR");
}

How to add click events inside d3 tooltip?

I've a d3js barchart as below. I'm adding a tooltip on click of each bar. I'm unable add event to close the tooltip which is inside the tip. Is there a way to add that?
The snippet as follows:
var margin = {
top: 10,
right: 0,
bottom: 58,
left: 30
};
var width = 300 - margin.left - margin.right;
var height = 300 - margin.top - margin.bottom;
var barWidth = 40;
var graph;
var x;
var y;
var dataset;
var yTicks = 6;
var tooltipEl = function(d) {
return (
'<div class="tip__container">' +
'<div class="val">' +
d.val +
"</div>" +
'<div class="close">' +
"<button>&times</button>" +
"</div>" +
"</div>"
);
};
dataset = [{
desc: "test1",
val: 40
},
{
desc: "some dummy text here",
val: 120
}
];
x = d3
.scaleBand()
.domain(
dataset.map(function(d) {
return d.desc;
})
)
.range([0, width]);
y = d3
.scaleLinear()
.range([height, 0])
.domain([0, 350]);
graph = d3
.select("#graph")
.append("svg")
.attr("class", "bar-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Tool Tip
const div = d3
.select("#graph")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
graph
.append("g")
.attr("class", "x-scale")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll(".tick text")
.call(wrap, x.bandwidth());
graph
.append("g")
.attr("class", "y-scale")
.call(
d3
.axisLeft(y)
.ticks(yTicks)
.tickPadding(10)
);
graph
.append("g")
.attr("class", "graph-placeholder")
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar1")
.attr("height", height)
.attr("width", barWidth)
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2);
graph
.append("g")
.attr("class", "graph-main")
.selectAll("bar1")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar2")
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2)
.attr("y", function(d) {
return y(d.val);
})
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", barWidth)
.on("click", d => {
div.html(tooltipEl(d));
div
.transition()
.duration(200)
.style("display", "block")
.style("opacity", 1);
div
.style("left", x(d.desc) + x.bandwidth() / 2 - 1 + "px")
.style("top", height + margin.top + 10 + "px");
});
graph
.append("g")
.attr("class", "bar-label")
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d.val + "%")
.attr("y", function(d) {
return y(d.val) - 5;
})
.attr("x", function(d) {
return x(d.desc) + x.bandwidth() / 2;
});
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text
.text()
.split(/\s+/)
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1,
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text
.text(null)
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", dy + "em");
while ((word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
}
.bar-chart {
background-color: #ccc;
}
.bar2 {
fill: steelblue;
}
.bar1 {
fill: #f2f2f2;
}
text {
font-size: 12px;
text-anchor: middle;
}
.bar-label text {
text-anchor: middle;
}
path.domain {
stroke-width: 0;
display: none;
}
.tooltip {
background: #FFFFFF;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.33);
font-family: "Segoe UI";
line-height: normal;
padding: 15px;
width: 100px;
position: absolute;
display: none;
}
.tooltip__container {
display: flex;
}
.tooltip::before {
content: "";
position: absolute;
left: 22px;
top: -8px;
transition: all 0.5s ease;
border: 8px solid #fff;
box-shadow: -5px -5px 5px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
}
.tip__container {
display: flex;
justify-content: space-between;
}
.close {
margin-left: 20px;
}
button {
border: 1px solid #ccc;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div id="graph"></div>
</div>
Fiddle
Because your div's HTML is created by the selection.html() method inside the callback of the click function for the bars, you have to set the listener inside the same callback:
div.select("button").on("click", function() {
div.style("opacity", 0)
});
Here is your code with that change:
var margin = {
top: 10,
right: 0,
bottom: 58,
left: 30
};
var width = 300 - margin.left - margin.right;
var height = 300 - margin.top - margin.bottom;
var barWidth = 40;
var graph;
var x;
var y;
var dataset;
var yTicks = 6;
var tooltipEl = function(d) {
return (
'<div class="tip__container">' +
'<div class="val">' +
d.val +
"</div>" +
'<div class="close">' +
"<button>&times</button>" +
"</div>" +
"</div>"
);
};
dataset = [{
desc: "test1",
val: 40
},
{
desc: "some dummy text here",
val: 120
}
];
x = d3
.scaleBand()
.domain(
dataset.map(function(d) {
return d.desc;
})
)
.range([0, width]);
y = d3
.scaleLinear()
.range([height, 0])
.domain([0, 350]);
graph = d3
.select("#graph")
.append("svg")
.attr("class", "bar-chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Tool Tip
const div = d3
.select("#graph")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
graph
.append("g")
.attr("class", "x-scale")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll(".tick text")
.call(wrap, x.bandwidth());
graph
.append("g")
.attr("class", "y-scale")
.call(
d3
.axisLeft(y)
.ticks(yTicks)
.tickPadding(10)
);
graph
.append("g")
.attr("class", "graph-placeholder")
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar1")
.attr("height", height)
.attr("width", barWidth)
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2);
graph
.append("g")
.attr("class", "graph-main")
.selectAll("bar1")
.data(dataset)
.enter()
.append("rect")
.attr("class", "bar2")
.attr("x", d => x(d.desc) + (x.bandwidth() - barWidth) / 2)
.attr("y", function(d) {
return y(d.val);
})
.attr("height", function(d) {
return height - y(d.val);
})
.attr("width", barWidth)
.on("click", d => {
div.html(tooltipEl(d));
div.select("button").on("click", function() {
div.style("opacity", 0)
});
div
.transition()
.duration(200)
.style("display", "block")
.style("opacity", 1);
div
.style("left", x(d.desc) + x.bandwidth() / 2 - 1 + "px")
.style("top", height + margin.top + 10 + "px");
});
graph
.append("g")
.attr("class", "bar-label")
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d.val + "%")
.attr("y", function(d) {
return y(d.val) - 5;
})
.attr("x", function(d) {
return x(d.desc) + x.bandwidth() / 2;
});
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text
.text()
.split(/\s+/)
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1,
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text
.text(null)
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", dy + "em");
while ((word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
}
.bar-chart {
background-color: #ccc;
}
.bar2 {
fill: steelblue;
}
.bar1 {
fill: #f2f2f2;
}
text {
font-size: 12px;
text-anchor: middle;
}
.bar-label text {
text-anchor: middle;
}
path.domain {
stroke-width: 0;
display: none;
}
.tooltip {
background: #FFFFFF;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.33);
font-family: "Segoe UI";
line-height: normal;
padding: 15px;
width: 100px;
position: absolute;
display: none;
}
.tooltip__container {
display: flex;
}
.tooltip::before {
content: "";
position: absolute;
left: 22px;
top: -8px;
transition: all 0.5s ease;
border: 8px solid #fff;
box-shadow: -5px -5px 5px rgba(0, 0, 0, 0.1);
transform: rotate(45deg);
}
.tip__container {
display: flex;
justify-content: space-between;
}
.close {
margin-left: 20px;
}
button {
border: 1px solid #ccc;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class="container">
<div id="graph"></div>
</div>

d3js toggling bars animation

I am trying to animate the bars when the user clicks on the legend. I've built the update function - but I am unsure on how to do the required filter and animation for this feature
http://jsfiddle.net/0ht35rpb/211/
function update(){
console.log("data", data);
var barData = data.filter(function(d1) {
console.log("d1", d1);
return !d1.disabled;
});
console.log("barData", barData);
var bar = chartHolder.selectAll(".bar")
.data(data)
console.log("bar", bar);
bar.transition()
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
bar.exit().remove();
/*
var bar = bar.selectAll("rect")
bar.transition()
//.attr("id", function(d){ return 'tag'+d.state.replace(/\s|\(|\)|\'|\,+/g, '');})
.attr("x", function(d) { return x1(d.name); })
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
//bar.exit().remove();
*/
This code var bar = chartHolder.selectAll(".bar") returns empty selection. You should select all .bars apply new data with method data, after that select all react, set animation parameters transition, duration, delay and set new values for approptiate attributes.
I rewrite your code - http://jsfiddle.net/168x28p3/1/ Here, I simply animate height of bars after click on legend. But this way you can create the another animation which you need.
var $this = document.querySelector('.chart');
var data = [{
label: "a",
"Current Period": 20,
"Prior Year": 10
}, {
label: "b",
"Current Period": 15,
"Prior Year": 30
}, {
label: "c",
"Current Period": 25,
"Prior Year": 40
}, {
label: "d",
"Current Period": 5,
"Prior Year": 60
}];
var configuration = [{
"yLabel": "People Count"
}];
var w = 660;
var h = 500;
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f", "#8bf41b"];
return colores_g[n % colores_g.length];
}
var margin = {
top: 20,
right: 110,
bottom: 30,
left: 20
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var svg = d3.select($this).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 axisHolder = svg.append("g")
.attr("class", "axis");
var chartHolder = svg.append("g")
.attr("class", "chart");
var legendHolder = svg.append("g")
.attr("class", "legend");
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
//var colorRange = d3.scale.category20();
//var color = d3.scale.ordinal()
//.range(colorRange.range());
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var options = d3.keys(data[0]).filter(function(key) {
return key !== "label";
});
data.forEach(function(d) {
d.valores = options.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(data.map(function(d) {
return d.label;
}));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.valores, function(d) {
return d.value;
});
})]);
axisHolder.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
axisHolder.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(configuration[0].yLabel);
var bar = chartHolder.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bars")
.attr("transform", function(d) {
return "translate(" + x0(d.label) + ",0)";
});
bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("value", function(d) {
return d.name;
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d, i) {
return colores_google(i);
});
bar
.on("mousemove", function(d) {
divTooltip.style("left", d3.event.pageX + 10 + "px");
divTooltip.style("top", d3.event.pageY - 25 + "px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX,
y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l - 1
elementData = elements[l].__data__
divTooltip.html((d.label) + "<br>" + elementData.name + "<br>" + elementData.value + "%");
});
bar
.on("mouseout", function(d) {
divTooltip.style("display", "none");
});
var legend = legendHolder.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(" + margin.right + "," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
})
.on("click", function(d) {
console.log("d", d);
d.disabled = !d.disabled;
update();
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
function update() {
var barData = data.map(item => {
item.valores = item.valores.map(valor => {
return Object.assign({}, valor, { value: Math.random() * 40 })
})
return item;
})
var bar = chartHolder.selectAll(".bars")
.data(barData)
var rect = bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
rect
.transition()
.duration(1000)
.delay(100)
.attr("width", x0.rangeBand() / 2)
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
}
* {
margin: 0;
padding: 0;
border: 0;
}
body {
background: #ffd;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: relative;
}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
rect {
stroke-width: 2;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path {
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axisHorizontal path {
fill: none;
}
.axisHorizontal line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
/*
.x.axis path {
display: none;
}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div class="chart"></div>

Unable to make pie chart from the dataset

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testing Pie Chart</title>
<script src="d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
#chart {
margin-top: 100px;
position: absolute;
margin-right: 50px;
margin-left: 50px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #000;
line-height: 16px;
border: 1px solid #d4d4d4;
}
.legend{
margin-left: 300px;
}
</style>
</head>
<body>
<div id="chart"></div>
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [ ["IP", "count"]
["192.168.12.1", "20"],
["76.09.45.34", "40"],
["34.91.23.76", "80"],
["192.168.19.32", "16"],
["192.168.10.89", "50"],
["192.178.34.07", "18"],
["192.168.12.98", "30"]];
var width = 300,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 10);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.data.count; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</body>
</html>
I am trying to make a pie chart with the provided dataset and I am facing error. How to define the parameter d to fetch the data from the variable "data" and its subsequent values "IP" and "count"? I dont know what mistake I am doing in my codes. What should I change in my current codes so that I can get a pie chart with current data format? Please help me. I am stuck. The condition is I should not use any kind of .csv or .tsv file in this code for importing. Thanks for any help.
One issue is with your data array... you need to remove the first item in it [ Also, you are missing a ',' after the item. but the item is itself not required as its an array ].
Second is with d.data.count inside the pie function... you need to refer it as d[1] as you need to plot the second item in data array in your chart.
Working code below:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testing Pie Chart</title>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
#chart {
margin-top: 100px;
position: absolute;
margin-right: 50px;
margin-left: 50px;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #900C3F;
display: inline-block;
font-size: 12px;
left: 600px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
width: 150px;
z-index: 10;
opacity: 1;
}
rect {
stroke-width: 2;
}
path {
stroke: #ffffff;
stroke-width: 0.5;
}
div.tooltip {
position: absolute;
z-index: 999;
padding: 10px;
background: #f4f4f4;
border: 0px;
border-radius: 3px;
pointer-events: none;
font-size: 11px;
color: #000;
line-height: 16px;
border: 1px solid #d4d4d4;
}
.legend{
margin-left: 300px;
}
</style>
</head>
<body>
<div id="chart"></div>
<div id="toolTip" class="tooltip" style="opacity: 0;"></div>
<script type="text/javascript">
var div = d3.select("#toolTip");
var data = [
["192.168.12.1", "20"],
["76.09.45.34", "40"],
["34.91.23.76", "80"],
["192.168.19.32", "16"],
["192.168.10.89", "50"],
["192.178.34.07", "18"],
["192.168.12.98", "30"]];
var width = 300,
height = 300;
var margin = {top: 15, right: 15, bottom: 20, left: 40},
radius = Math.min(width, height) / 2 - 10;
var legendRectSize = 18,
legendSpacing = 4;
var color = d3.scale.category20b();
var arc = d3.svg.arc()
.outerRadius(radius);
var arcOver = d3.svg.arc()
.outerRadius(radius + 10);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d[1]; });
var labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#chart").append("svg")
.datum(data)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = svg.selectAll(".arc")
.data(pie)
.enter().append("g")
.attr("class", "arc");
var arcs2 = svg.selectAll(".arc2")
.data(pie)
.enter().append("g")
.attr("class", "arc2");
arcs.append("path")
.attr("fill", function(d, i) { return color(i); })
.on("mouseover", function(d) {
var htmlMsg="";
div.transition()
.style("opacity",0.9);
var total = d3.sum(data.map(function(d) {
return d.count;
}));
var percent = Math.round(1000 * d.data.count / total) / 10;
div.html(
"IP :"+ d.data.IP +""+"<br/>"+
"Count : " + d.data.count +"<br/>" +
"Percent: " + percent + '%'+ htmlMsg)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
svg.selectAll("path").sort(function (a, b) {
if (a != d) return -1;
else return 1;
});
var endAngle = d.endAngle + 0.1;
var startAngle = d.startAngle - 0.1;
var arcOver = d3.svg.arc()
.outerRadius(radius + 10).endAngle(endAngle).startAngle(startAngle);
d3.select(this)
.attr("stroke","white")
.transition()
.ease("bounce")
.duration(1000)
.attr("d", arcOver)
.attr("stroke-width",6);
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
d3.select(this).transition()
.attr("d", arc)
.attr("stroke","none");
})
.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
var k=0;
arcs2.append("text")
.transition()
.ease("elastic")
.duration(2000)
.delay(function (d, i) {
return i * 250;
})
.attr("x","6")
.attr("dy", ".35em")
.text(function(d) { if(d.data.count >0){ k = k+1; return d.data.count;} })
.attr("transform", function(d) { if (k >1){return "translate(" + labelArc.centroid(d) + ") rotate(" + angle(d) + ")";} else{return "rotate(-360)";} })
.attr("font-size", "10px");
function type(d) {
d.count = +d.count;
return d;
}
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
var legend = d3.select("#chart")
.append("svg")
.attr("class", "legend")
.attr("width", radius+50)
.attr("height", radius * 2)
.selectAll("g")
.data(color.domain())
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.data(data)
.text(function(d,i) { return d.IP; });
</script>
</body>
</html>
Your data input format is wrong.
Change from:
var data = [ ["IP", "count"]
["192.168.12.1", "20"],
["76.09.45.34", "40"],
["34.91.23.76", "80"],
["192.168.19.32", "16"],
["192.168.10.89", "50"],
["192.178.34.07", "18"],
["192.168.12.98", "30"]];
to
var data = [
{"IP":"192.168.12.1", "count":"20"},
{"IP":"76.09.45.34", "count":"40"},
{"IP":"34.91.23.76", "count":"80"},
{"IP":"192.168.19.32", "count":"16"},
{"IP":"192.168.10.89", "count":"50"},
{"IP":"192.178.34.07", "count":"18"},
{"IP":"192.168.12.98", "count":"30"}
];

Categories

Resources