error in D3.js code regarding particular place - javascript

i am making a college project on D3.js. i copied the code of pie chart from Scott Murray's book on D3.js. It works. But now i am facing a problem.
1)i want to show the pie chart in a particular place in html page ,but i am unable to do it.
like
2)when i resubmit the data its created another pie chart very next to old one.But i want to first delete old one and then create new one at same place.
please help me.
the fiddle is-http://jsbin.com/acatof/3/edit
D3: Pie layout
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
text {
font-family: sans-serif;
font-size: 12px;
fill: white;
}
</style>
<body>
<script type="text/javascript">
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
</script>
</body>

To put it in an element, for example, a <div> instead on the <body>, you just need to replace the selection on which the svg will be appended, to the selector of the element where you want to put the graph.
So instead of
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
You can do:
var svg = d3.select("#container")
.append("svg")
.attr("width", w)
.attr("height", h);
Provided that there is a <div id = "container"></div> somewhere on your page.
Hope this helps :)

Related

why my two graph of d3.js is not combined in the single page?

I have made two separate graph on separate page of Bar and pie chart respectively and now i wanted to combine this two graph in the single page so that I can have a dashboard. but when i start to combine to two graph in the main page its not happening and they overlap of each other.
Code:
https://github.com/Mustafa2911/d3-design/blob/main/combine.html
Combine file contain: Code of both pie and bar chart.
Bar file contain: Code of bar chart.
Pie chart contain: Code of pie chart.
Tried this with your code.
Scroll to see the bar graph axis.
NOTE: The bar graph data will not be available ∵ it is from the demo1.csv file in your repository.
Hope this helps.
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var width = 800
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var data = {
Corporation_Tax: 15,
Income_Tax: 15,
Customs: 5,
Union_Excise_Duties: 7,
Good_and_Service_tax: 16,
Non_tax_Revenue: 5,
Non_Dept_Capital_Receipt: 2,
Borrowings_Liabilities: 35
}
// set the color scale
var color = d3.scaleOrdinal()
.domain(["a", "b", "c", "d", "e", "f", "g", "h"])
.range(d3.schemeSet1);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {
return d.value;
})
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d) {
return (color(d.data.key))
})
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text(function(d) {
console.log(d.data.key);
return d.data.key
})
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
</script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
<div id="my_dataviz_es"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 40,
left: 160
},
width = 460,
height = 400;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz_es")
.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 + ")");
// Parse the Data
d3.csv("demo1.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 550000])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([0, height])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(.1);
svg.append("g")
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0))
.attr("y", function(d) {
return y(d.Country);
})
.attr("width", function(d) {
return x(d.Value);
})
.attr("height", y.bandwidth())
.attr("fill", "#69b3a2")
// .attr("x", function(d) { return x(d.Country); })
// .attr("y", function(d) { return y(d.Value); })
// .attr("width", x.bandwidth())
// .attr("height", function(d) { return height - y(d.Value); })
// .attr
})
</script>
</body>
</html>
EDIT: See here - https://codepen.io/KZJ/pen/rNpqvdq?editors=1011 - for changes made reg. the below comment
what if I want to have my bar chart at the top and on right side i want to have my pie chart
Changed -
a) Both charts were using the same name 'svg' to d3.select() the divs. This caused the charts to overlap.
b) Modified width, height, transform, and added some border CSS - only for demonstration purposes - It can be removed/edited as required.
FYR this is how it looks now -

showing data in tool tip of a PieChart

I'm accessing a GITHUB raw file and using the d3.pie() function making the start and end angles of the pie, at that point the data is showing on console but when I access it in tooltip it gives UNDEFINED.
Do run the code if you can, the link to my github is given where I'm loading my file d3.csv() also FUNCTION TEST is running only once I need to run it till my data runs out.
//CALCULATING RADIUS OF CHART
var radius = Math.min(width, height) / 2 - margin
//APPENDING SVG IN DIV HAVING ID pieChart
var svg = d3.select("#pieChart")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// DATA
d3.csv
("https://raw.githubusercontent.com/Dehya/django/master/pkpopulation.csv?
token=AHXLL23PHQSJGYIYCLA6YX25I7IJA",function(error, data){
// GETTING VALUES AS POPULATION FROM DATA AND CALCULATING THE START AND
END
ANGLE:
var pie = d3.pie()
.value(function(d) {return d.population; })
console.log(pie(data));
//SETTING COLOR SCALE
var color = d3.scaleOrdinal()
.domain(data)
.range(["red", "yellow", "green", "blue", "orange"])
function Test(d){
for( i ; i<data.length ; i++)
{
console.log(data[i].name + " : " + data[i].population);
return data[i].name + " : " + data[i].population;
}
}
//MAKING TOOPTIP
var tip = d3.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(Test(data));
svg.call(tip);
//MAKING SLICES OF PIE CHART
svg
.selectAll("mySlices")
.data(pie(data))
.enter()
.append("path")
.attr('d',d3.arc()
.innerRadius(0)
.outerRadius(radius)
)
.attr("fill", function(d){ return color(d.data.key) })
.attr("stroke","black")
.style("stroke-width","1px")
.style("opacity",0.7)
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
});

Display multiple d3.js charts in a single html page

I have the the d3.js code which is pasted here.
I am trying to display more than one graphs in the same page. Though the d3.js code is same. Say one from data1.json and the other from data2.json. Following is the snippet which is bothering me.
<svg width="960" height="960"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg2 = d3.select("svg"),
margin = 20,
diameter = +svg2.attr("width"),
g = svg2.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
As per different answers in SO here, here, here, here or here, the solution seems to be one of the following:
Use different variable name to hold svgs such as svg1, svg2.. etc..
which I have done.
Use a method as described here.
var chart1 = d3.select("#area1")
.append("svg")
Method two is not working for me, as it shows blank page.
How to resolve this. I am sure that I am not getting the syntax correctly.
There's no problem at all using multiple SVGs on the same page. Here's an example:
var svg1 = d3.select("#svg1");
svg1.append("circle")
.attr("cx",100)
.attr("cy", 100)
.attr("r", 90)
.attr("fill", "red");
var svg2 = d3.select("#svg2");
svg2.append("circle")
.attr("cx",100)
.attr("cy", 100)
.attr("r", 90)
.attr("fill", "blue");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="200" height="200" id="svg1"></svg>
<svg width="200" height="200" id="svg2"></svg>
There is no need for repeating all the code, as you're doing right now. Don't repeat yourself.
An easy alternative is wrapping all your D3 code in a function that has two parameters, selector and url:
function draw(selector, url){
//code here
};
Then, inside that function draw, you set the position of your SVG:
var svg = d3.select(selector).append("svg")...
And the URL you get the data:
d3.json(ulr, function(error, root) {...
After that, just call the draw function twice, with different arguments:
draw(selector1, url1);
draw(selector2, url2);
Here is a demo, read it carefully to see how it works:
draw("#svg1", "#data1");
draw("#svg2", "#data2");
function draw(selector, url){
var data = d3.csvParse(d3.select(url).text())
var width = 500,
height = 150;
var svg = d3.select(selector)
.append("svg")
.attr("width", width)
.attr("height", height);
var xScale = d3.scalePoint()
.domain(data.map(function(d) {
return d.name
}))
.range([50, width - 50])
.padding(0.5);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, function(d) {
return d.value
}) * 1.1])
.range([height - 20, 6]);
var line = d3.line()
.x(function(d){ return xScale(d.name)})
.y(function(d){ return yScale(d.value)});
svg.append("path")
.attr("d", line(data))
.attr("stroke", "teal")
.attr("stroke-width", "2")
.attr("fill", "none");
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
svg.append("g").attr("transform", "translate(0,130)")
.attr("class", "xAxis")
.call(xAxis);
svg.append("g")
.attr("transform", "translate(50,0)")
.attr("class", "yAxis")
.call(yAxis);
}
pre {
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div>First SVG</div>
<div id="svg1"></div>
<div>Second SVG</div>
<div id="svg2"></div>
<pre id="data1">name,value
foo,8
bar,1
baz,7
foobar,9
foobaz,4</pre>
<pre id="data2">name,value
foo,1
bar,2
baz,3
foobar,9
foobaz,8</pre>
If the two charts use the same code, I think the most d3-like way to go about it would be
var width = 960,
height = 960,
margin = 30;
var svgs = d3.select('#area1')
.selectAll('svg')
.data([json1, json2])
.enter()
.append('svg')
.attr('width', width)
.attr('height', height)
svgs.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.each(function(d) {console.log(d)}) // will log json1, then json2
You'll then have json1 and json2 bound to each of the newly appended svgs, and all code that follows will be done to both.
var width = 200,
height = 100,
margin = 30;
var svgs = d3.select('#area1')
.selectAll('svg')
.data([{text:'thing1'}, {text:'thing2'}])
.enter()
.append('svg')
.attr('width', width)
.attr('height', height);
svgs.append("text")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.text(function(d) {return d.text});
<script src="https://d3js.org/d3.v4.js"></script>
<div id='area1'></div>

Adding clock points to d3 pie chart

I'm very new to D3 - in fact I only started yesterday - have a donut pie chart here:
var dataset = new Array();
dataset[0] = {"value":"50","color":"red"};
dataset[1] = {"value":"20","color":"blue"};
var pie = d3.layout.pie().sort(null).value(function(d){return d.value;});
var h = w = 500;
var center = w / 2;
var outerRadius = ((h/2)-5);
var innerRadius = outerRadius-10;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var arcOutter = d3.svg.arc()
.innerRadius(outerRadius)
.outerRadius(outerRadius + 1);
var arcInner = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(innerRadius - 1);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var outterArcs = svg.selectAll("g.outter-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "outter-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Set up outter arc groups
var innerArcs = svg.selectAll("g.inner-arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "inner-arc")
.attr("transform", "translate(" + center + ", " + center + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function (d, i)
{
return d.data.color;
}).attr("d", arc);
//Draw outter arc paths
outterArcs.append("path")
.attr("fill", 'green')
.attr("d", arcOutter).style('stroke', 'white')
.style('stroke-width', 0);
//Draw inner arc paths
innerArcs.append("path")
.attr("fill", 'green')
.attr("d", arcInner).style('stroke', 'white')
.style('stroke-width', 0);
jsFiddle chart
But I'm struggling to add 4 clock points and their time tables to it, (12am, 3pm, 6pm, 9pm), I've tried searching clock examples but they're all working clocks, not just the points.
I want it to look pretty much like this:
Any help would be greatly appreciated.
I don't know how aestheticaly correct it is, but here it goes. What you could do, is add 4 line segments in your chart at these locations:
[w/2, 0],[w/2,h],[0,h/2],[w,h/2]
You can achieve that if you add the following lines:
var x=d3.scale.linear().domain([0,outerRadius]).range([0,w])
var y=d3.scale.linear().domain([0,outerRadius]).range([h,0])
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",0).attr("x2",x(outerRadius/2)).attr("y2",20)
svg.append('line').attr("x1",x(outerRadius/2)).attr("y1",y(outerRadius)).attr("x2",x(outerRadius/2)).attr("y2",y(outerRadius)-20)
svg.append('line').attr("x1",0).attr("y1",y(outerRadius/2)).attr("x2",20).attr("y2",y(outerRadius/2))
svg.append('line').attr("x1",x(outerRadius)).attr("y1",y(outerRadius/2)).attr("x2",x(outerRadius)-20).attr("y2",y(outerRadius/2))
Please note that you have to create a css entry, so that the line is shown:
line{
display:block;
stroke:black;
}
JSFiddle here
Hope this helps
Following the lovely example here.
var radians = 0.0174532925;
var hourScale = d3.scale.linear()
.range([0,330])
.domain([0,11]);
var labelGroup = svg.append('g')
.attr('transform','translate(' + (center + margin) + ',' + (center + margin) + ')');
labelGroup.selectAll('.hour-label')
.data([12,3,6,9])
.enter()
.append('text')
.attr('class', 'hour-label')
.attr('text-anchor','middle')
.style('font-size','16pt')
.attr('x',function(d){
return outerRadius * Math.sin(hourScale(d)*radians);
})
.attr('y',function(d){
return -outerRadius * Math.cos(hourScale(d)*radians);
})
.text(function(d){
return d;
});
Updated fiddle.

html file + d3.js script file + input data manually in html file

I am new in d3.js language. I am trying to built a simple application but I stuck some where. I have a separate .js file jack.js which makes pie chart when you link it with html page.
Problem I want to use that file in every html page with different data. But i cant find the perfect solution of this. whenever page loaded in browser, file load its pie chart visualization. So can you suggest me what should i need to do?
HTML page
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="lib/pie.js"></script>
<script>
dataset = [1,2,3,4,5];
</script>
</head>
<body>
</body>
</html> `
jack.js
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
<body>
<script type="text/javascript" src="lib/pie.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</body>
This way you can do this.
Hi Remove var dataset = [ 5, 10, 20, 45, 6, 25 ]; from jack.js and put them either in your html file like you did in the head of your html file. Call jack.js in the body.
This will ensure that the data is loaded first before jack.js.
Hence your code will look like this
Html
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</head>
<body>
<script type="text/javascript" src="lib/pie.js"></script>
</body>
</html>
pie.js
var w = 300;
var h = 300;
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
Alternatively, you place wrap you d3 code in a $( document ).ready( //your d3 code here ) http://learn.jquery.com/using-jquery-core/document-ready/
Alternatively
pie.js
$( document ).ready(
// d3 code here
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
....
)

Categories