SVG element not getting selected - Bar chart not being displayed - javascript

I am trying to create a simple bar chart using the following code. There seems to be some issue with svg element due to which the bar chart is not getting displayed in the browser window. The only output I get is "Bar Chart using D3.js". I am using MacOS+Chrome.
Also I am not sure if "<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.0.10/polyfills.js"></script>" is required
Following files are index.js and index.html respectively.
var dataset = [80, 100, 56, 120, 180, 30, 40, 120, 160];
var svgWidth = 500,
svgHeight = 300,
barPadding = 5; //ht and wt
var barWidth = (svg / dataset.length); //each bar wt
var svg = d3.select('svg') //give attr of wt and ht
.attr("width", svgWidth)
.attr("height", svgHeight);
var barChart = svg.selectAll("rect") //create bar chart with rect
.data(dataset) //provide dataset
.enter() //takes data from waiting state perform operation
.append("rect")
.attr("y", function(d) {
return svgHeight - d
})
.attr("height", function(d) {
return d;
})
.attr("width", barWidth - barPadding)
.attr("transform", function(d, i) {
var translate = [barWidth * i, 0]; //[x axis, y axis]
return "translate(" + translate + ")"; //translate one bar after another
<html>
<head>
<link rel="stylesheet" href="index.css">
<title>Basics of D3.js</title>
</head>
<body>
<h1>Bar chart using D3.js</h1>
<svg class="bar-chart"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.0.10/polyfills.js"></script>
<script src="index.js"></script>
</body>
</html>

Related

Pie chart not updating D3.JS

I know this question has been asked many times but I am not able to solve the problem of updating my pie chart. I am completely lost. Could you please tell me what seems to the problem here ?
I tried the following way but the chart doesn't seem to update. I added a function change that is supposed to update the chart. I am updating the data, redrawing the arcs and changing the labels but it is not working.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Load D3 -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="pie"></div>
<script>
var dataChart = { a: 9, b: 20, c: 30, d: 8, e: 12 };
var dataChart2 = { f: 9, g: 20, h: 30, i: 8 };
console.log(dataChart);
var width = 300,
height = 300,
// Think back to 5th grade. Radius is 1/2 of the diameter. What is the limiting factor on the diameter? Width or height, whichever is smaller
radius = Math.min(width, height) / 2;
var color = d3.scaleOrdinal()
.range(["#2C93E8", "#838690", "#F56C4E"]);
var pie = d3.pie()
.value(function (d) { return d.value; });
data = pie(d3.entries(dataChart));
var arc = d3.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var labelArc = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
var svg = d3.select("#pie")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // Moving the center point. 1/2 the width and 1/2 the height
var g = svg.selectAll("arc")
.data(data)
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function (d) { return color(d.data.key); });
g.append("text")
.attr("transform", function (d) { return "translate(" + labelArc.centroid(d) + ")"; })
.text(function (d) { return d.data.key; })
.style("fill", "#fff");
function change(dataChart) {
var pie = d3.pie()
.value(function (d) { return d.value; });
data = pie(d3.entries(dataChart));
path = d3.select("#pie").selectAll("path").data(data); // Compute the new angles
path.attr("d", arc); // redrawing the path
d3.selectAll("text").data(data).attr("transform", function (d) { return "translate(" + labelArc.centroid(d) + ")"; }); // recomputing the centroid and translating the text accordingly.
}
// calling the update functions
change(dataChart);
change (dataChart2);
</script>
</body>
</html>

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>

How do I make my bar chart's height be the data?

I made a bar chart from data from a .csv file. I am struggling to make the height of the bar chart. I would like the height to be taken from the data values of a specific column, in this case, the "NO OF RECORDS STOLEN" column in the file.
I have tried things like:
.attr("height", function(d) {return d["NO OF RECORDS STOLEN"];}
but it does not work.
This is my HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Bar Chart | Crime File</title>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script type="text/javascript">
var dataset = "data_breaches.csv";
var w = 960;
var h = 500;
var barPadding = 1;
var barWidth = w / dataset.length - barPadding;
// create canvas
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// create bar chart
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (barWidth + barPadding);
})
.attr("y", 0)
.attr("width", barWidth)
.attr("height", 100) // WORKING ON THIS
.attr("fill", function (d) {
return "rgb(200, 50, 50)";
});
// get data
d3.csv(dataset, function (data) {
// convert type from string to integer
data.forEach(function typeConv(d) {
// type conversion from string to number
d["YEAR"] = +d["YEAR"]; // for names with spaces
d["DATA SENSITIVITY"] = +d["DATA SENSITIVITY"];
d["NO OF RECORDS STOLEN"] = +d["NO OF RECORDS STOLEN"];
return d;
});
var arrayLength = data.length;
// fixed, should have been <, not <= bc n-1, not n
for (var i = 0; i < arrayLength; i++) {
var breachesData = data[i];
console.log(breachesData);
}
});
</script>
</body>
</html>
As mentioned in the comment at your question, you need to append the rectangles after the data is loaded. Also I reviewed your code and removed unnecessary parts for clarity. Pay attention to the comments that I've added and let us know if you have any questions. Good luck!
var dataset = "data_breaches.csv";
var w = 960;
var h = 500;
var barPadding = 1;
var barWidth = w / dataset.length - barPadding;
// create canvas
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// get data
d3.csv(dataset, function (data) {
// You need to create a "scale" to convert from your data values to pixels in the screen
var heightBy = "NO OF RECORDS STOLEN"
var scale = d3.scaleLinear()
.domain([0, d3.max(d => d[heightBy])])
.range([0, h])
// create bar chart
svg.selectAll("rect")
.data(data) // "dataset" is the filepath, "data" is the loaded file content
.enter()
.append("rect")
.attr("x", (d, i) => i * (barWidth + barPadding))
.attr("y", d => h - scale(d[heightBy])) // Remember that on SVG y=0 is at the bottom and the rect height grows down
.attr("width", barWidth)
.attr("height", d => scale(d[heightBy]))
.attr("fill", "rgb(200, 50, 50)");
});

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();
....
)

error in D3.js code regarding particular place

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 :)

Categories