I am currently building a graph using d3.js as well as HTML. I am trying to input interactivity by adding a selector which changes the displayed data based on your selection. I am not sure at all how to make the selector change which data is being used.
<!DOCTYPE html>
<html>
<head>
<meta><meta http-equiv="refresh" content="90">
<meta name="description" content="Drawing Shapes w/ D3 - " />
<meta charset="utf-8">
<title>Resources per Project</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
h1 {
font-size: 35px;
color: darkgrey;
font-family: Helvetica;
border-bottom-width: 3px;
border-bottom-style: dashed;
border-bottom-color: black;
}
h2 {
font-size: 20px;
color: black;
font-family: Helvetica;
text-decoration: underline;
margin-left: 290px;
margin-top: 2px;
}
</style>
</head>
<body>
<h1>Resources used per Project</h1>
<p>Choose Month:
<select id="label-option">
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
</select>
<script type="text/javascript">
var width = 800
var height = 500
var emptyVar = 0
var dataArrayProjects = ['2G','An','At','Au','AW','Ch','CI','CN']
var April = [0.35,1.66,3.04,1.54,3.45,2.56,2.29,1.37]
var May = [0.36,1.69,3.08,1.54,3.62,2.61,2.22,1.44]
var June = [0.34,1.7,3.08,1.63,3.66,2.68,2.24,1.51]
var July = [0.3,1.72,3.17,1.67,3.56,2.56,2.17,1.44]
var August = [0.28,1.79,3.18,1.71,3.62,2.73,2.26,1.54]
var September = [0.23,1.74,3.12,1.61,3.66,2.71,2.2,1.48]
var widthScale = d3.scale.linear()
.domain([0, 4])
.range([0, width-60]);
var heightScale = d3.scale.ordinal()
.domain(dataArrayProjects)
.rangePoints([10, height-85]);
var color = d3.scale.linear()
.domain([0,4])
.range(["#000066", "#22abff"])
var axis = d3.svg.axis()
.ticks("10")
.scale(widthScale);
var yAxis = d3.svg.axis()
.scale(heightScale)
.orient("left");
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40, 0)");
var bars = canvas.selectAll("rect")
.data(April)
.enter()
.append("rect")
.attr("width", emptyVar)
.attr("height", 50)
.attr("fill", function(d) { return color(d) })
.attr("y", function(d, i) { return i * 55 })
canvas.append("g")
.attr("transform", "translate(0, 430)")
.attr("font-family", "Helvetica")
.attr("font-size", "15px")
.call(axis);
canvas.append("g")
.attr("font-family", "Helvetica")
.attr("font-size", "15px")
.style("fill", "black")
.attr("class", "y axis")
.call(yAxis);
bars.transition()
.duration(1500)
.delay(200)
.attr("width", function(d) { return widthScale(d); })
</script>
<h2>Resources</h2>
</body>
</html>
So you know the variables April, May, June, July, August and September are the ones I would like it to change between and the .data selector in the "bars" variable is where the data should be changing between months.
Thanks in advance!
You can attach a listener to the select which will be notified on change of the select.
d3.select("#label-option").on("change", change);//attache listener
//on change update bars.
function change() {
var data = April;
if (this.selectedIndex == 1){
data = May;//return may Data
} else if (this.selectedIndex == 2){
data = June;//return June Data
} else if (this.selectedIndex == 3){
data = July;
} else if (this.selectedIndex == 4){
data = August;
} else if (this.selectedIndex == 5){
data = September;
}
//select all bars and set the new data
canvas.selectAll("rect")
.data(data)
.attr("width", emptyVar)
.attr("height", 50)
.attr("fill", function(d) {
return color(d)
})
.attr("y", function(d, i) {
return i * 55
})
bars.transition()
.duration(1500)
.delay(200)
.attr("width", function(d) {
return widthScale(d);//transition to new width
})
}
working code here
Related
I have this and I need to see a graph of the genre scatter plot. I know I'm a bit dumb, but I do not know how to play it well yet, no. One of the axes still appears if executed. This code is given by the teacher to correct us, I already got some things, but I do not understand any of this.
var margin = {top: 20, right: 10, bottom: 100, left: 40};
var width = 700 - margin.right - margin.left;
var height = 500 - margin.top - margin.bottom;
// o g para agrupar objetos juntos, agrupar as barras
var svg = d3.select('body')
.append('svg')
.attr({"width" : width + margin.right + margin.left,
"height" : height + margin.top + margin.bottom
});
//.append("g")
//.attr("transform", "translate(" + margin.left +"," + margin.right + ")");
//definição da posição do eixo xx e yy
var x_scale = d3.scaleLinear()
.range([0, width])
.domain([0, width]);
var y_scale = d3.scaleLinear()
.range([height, 0])
.domain([height, 0]);
//axis, definição do conteudo dos eixos
var x_axis = d3.axisBottom(x_scale);
d3.select("svg")
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height - margin) + ")")
.call(x_axis);
var y_axis = d3.axisLeft(y_scale);
d3.select("svg")
.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + margin + ", 0)")
.call(y_axis);
var years = [];
var suicides = [];
var taxaAno = new Object();
var taxaAno = {};
d3.csv("master.csv", function(error,data){
if(error) console.log("Erro no ficheiro csv");
data.forEach(function(d){
years = +d.year;
suicides = +d.suicides_no;
if (taxaAno[years]==null){
taxaAno[years] = suicides;
}
else{
taxaAno[years] += suicides;
}
});
console.log(taxaAno);
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) {
return x_scale(taxaAno[years]);
})
.attr("cy", function (d) {
return y_scale(taxaAno[suicides]);
})
.attr("r", function (d) {
return 10;
});
var line = d3.line()
.x(function (){ return x_scale(taxaAno[years])})
.y(function (){ return y_scale(taxaAno[suicides])
});
d3.select("svg")
.append("path")
.attr("d", line(data))
.attr("class", "line_death");
d3.select("svg")
.append("text")
.text("Anos")
.attr("x", (width / 2) - margin)
.attr("y", height - margin / 3);
d3.select("svg")
.append("text")
.text("N. de suicidios")
.attr("x", 0)
.attr("y", 0)
.attr("transform", "rotate (90, 0, 0) translate(100, -10)");
});
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
.topnav {
overflow: hidden;
background-color: #333;
}
.topnav a {
float: left;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
}
.topnav a:hover {
background-color: #ddd;
color: black;
}
.topnav a.active {
background-color: #4CAF50;
color: white;
}
IMG.displayed {
display: block;
margin-left: auto;
margin-right: auto
}
h1 {
color: #069;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
</style>
</head>
<body>
<div class="topnav">
<a class="active" href="index.html">Home</a>
Mapa
Evolucaoo por ano
<!-- About -->
</div>
<body><br><br>
<!-- <IMG class="displayed" src="home.png" alt="some text" width=600 height=400> -->
<h1 style="text-align: center">Taxa de suicidio por ano</h1>
<script src="http://d3js.org/d3.v4.js"></script>
<script>
</script>
</body>
</html>
With this code I want to see a graph of the genre scatter plot with a line joining the points.
Error in console is this:
your data is only defined inside this block:
d3.csv("master.csv", function(error,data){
if(error) console.log("Erro no ficheiro csv");
data.forEach(function(d){
years = +d.year;
suicides = +d.suicides_no;
if (taxaAno[years]==null){
taxaAno[years] = suicides;
}
else{
taxaAno[years] += suicides;
}
});
console.log(taxaAno);
});
so you need to move everything that depends on data to within that block:
d3.csv("master.csv", function(error,data){
if(error) console.log("Erro no ficheiro csv");
data.forEach(function(d){
years = +d.year;
suicides = +d.suicides_no;
if (taxaAno[years]==null){
taxaAno[years] = suicides;
}
else{
taxaAno[years] += suicides;
}
});
console.log(taxaAno);
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) {
return x_scale(taxaAno[years]);
})
.attr("cy", function (d) {
return y_scale(taxaAno[suicides]);
})
.attr("r", function (d) {
return 10;
});
var line = d3.line()
.x(function (){ return x_scale(taxaAno[years])})
.y(function (){ return y_scale(taxaAno[suicides])
});
d3.select("svg")
.append("path")
.attr("d", line(data))
.attr("class", "line_death");
d3.select("svg")
.append("text")
.text("Anos")
.attr("x", (width / 2) - margin)
.attr("y", height - margin / 3);
d3.select("svg")
.append("text")
.text("N. de suicidios")
.attr("x", 0)
.attr("y", 0)
.attr("transform", "rotate (90, 0, 0) translate(100, -10)");
});
I am new to java script and I am trying to draw a radar chart. Everything works well except title. Can u please tell me what is wrong? I attached the code below. First I create text var and call it to show.
<style>
body {
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: "Helvetica Neue", Helvetica;
}
#chart {
position: absolute;
top: 60px;
left: 20px;
}
</style>
<script type="text/javascript" src="<c:url value='/js/radar.js'/>"></script>
<div id="body">
<div id="chart"></div>
</div>
<script>
var w = 200;
var h = 200;
var colorscale = d3.scale.category10();
//Legend, titles
var LegendOptions = ['Try Count','Succcess Count', 'Success Rate'];
////////////////////////////////////////////
/////////// Initiate legend ////////////////
////////////////////////////////////////////
var svg = d3.select('#body')
.selectAll('svg')
.append('svg')
.attr("width", w+300)
.attr("height", h)
//Create the title for the legend
var text = svg.append("text")
.attr("class", "title")
.attr('transform', 'translate(90,0)')
.attr("x", w - 70)
.attr("y", 10)
.attr("font-size", "12px")
.attr("fill", "#404040")
.text("What % of owners use a specific service in a week");
//Initiate Legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("height", 100)
.attr("width", 200)
.attr('transform', 'translate(90,20)')
;
//Create colour squares
legend.selectAll('rect')
.data(LegendOptions)
.enter()
.append("rect")
.attr("x", w - 65)
.attr("y", function(d, i){ return i * 20;})
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d, i){ return colorscale(i);})
;
//Create text next to squares
legend.selectAll('text')
.data(LegendOptions)
.enter()
.append("text")
.attr("x", w - 52)
.attr("y", function(d, i){ return i * 20 + 9;})
.attr("font-size", "11px")
.attr("fill", "#737373")
.text(function(d) { return d; })
;
//Options for the Radar chart, other than default
var mycfg = {
w: w,
h: h,
maxValue: 0.6,
levels: 6,
ExtraWidthX: 300
}
Try changing:
var svg = d3.select('#body')
.selectAll('svg')
.append('svg')....
To:
var svg = d3.select('#body')
.append('svg')....
As you are only appending one svg, you do not need the selectAll() portion. The following takes your code and makes that one change:
var w = 200;
var h = 200;
var svg = d3.select('#body')
.append('svg')
.attr("width", w+300)
.attr("height", h)
var text = svg.append('g').append("text")
.attr("class", "title")
.attr('transform', 'translate(90,0)')
.attr("x", w - 70)
.attr("y", 10)
.attr("font-size", "12px")
.attr("fill", "#404040")
.text("What % of owners use a specific service in a week");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="body"></div>
I am currently making a Bar Graph which shows data in the form of a horizontal bar which grows based on the data put into the code. What I am trying to do here is make text appear next to the bars when they appear and change as the data does. I have already made a listener which changes the data appearing I just do not know how to make the data appear and change.
<!DOCTYPE html>
<html>
<head>
<meta>
<meta name="description" content="Drawing Shapes w/ D3 - " />
<meta charset="utf-8">
<title>Resources per Project</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
h1 {
font-size: 35px;
color: darkgrey;
font-family: Helvetica;
border-bottom-width: 3px;
border-bottom-style: dashed;
border-bottom-color: black;
}
h2 {
font-size: 20px;
color: black;
font-family: Helvetica;
text-decoration: underline;
margin-left: 350px;
margin-top: 0px;
}
</style>
</head>
<body>
<h1>Resources used per Project</h1>
<p>Choose Month:
<select id="label-option">
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
</select>
<script type="text/javascript">
var width = 800
var height = 500
var emptyVar = 0
var dataArrayProjects = ['2G', 'An', 'At', 'Au', 'AW', 'Ch', 'CI', 'CN']
var April = [0.35, 1.66, 3.04, 1.54, 3.45, 2.56, 2.29, 1.37]
var May = [0.36, 1.69, 3.08, 1.54, 3.62, 2.61, 2.22, 1.44]
var June = [0.34, 1.7, 3.08, 1.63, 3.66, 2.68, 2.24, 1.51]
var July = [0.3, 1.72, 3.17, 1.67, 3.56, 2.56, 2.17, 1.44]
var August = [0.28, 1.79, 3.18, 1.71, 3.62, 2.73, 2.26, 1.54]
var September = [1.23, 1.74, 3.12, 1.61, 3.66, 2.71, 2.2, 1.48]
d3.select("#label-option").on("change", change)
function change() {
var data = April;
if (this.selectedIndex == 1){
data = May;
} else if (this.selectedIndex == 2){
data = June;
} else if (this.selectedIndex == 3){
data = July;
} else if (this.selectedIndex == 4){
data = August;
} else if (this.selectedIndex == 5){
data = September;
}
canvas.selectAll("rect")
.data(data)
.attr("width", emptyVar)
.attr("height", 50)
.attr("fill", function(d) {
return color(d)
})
.attr("y", function(d, i) {
return i * 55
})
bars.transition()
.duration(1500)
.delay(200)
.attr("width", function(d) {
return widthScale(d);
})
}
var widthScale = d3.scale.linear()
.domain([0, 4])
.range([0, width - 60]);
var heightScale = d3.scale.ordinal()
.domain(dataArrayProjects)
.rangePoints([10, height - 85]);
var color = d3.scale.linear()
.domain([0, 4])
.range(["#000033", "#22cdff"])
var xAxis = d3.svg.axis()
.ticks("30")
.scale(widthScale);
var yAxis = d3.svg.axis()
.scale(heightScale)
.orient("left");
var canvas = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40, 0)");
var bars = canvas.selectAll("rect")
.data(April)
.enter()
.append("rect")
.attr("width", emptyVar)
.attr("height", 50)
.attr("fill", function(d) {
return color(d)
})
.attr("y", function(d, i) {
return i * 55
})
canvas.append("g")
.attr("transform", "translate(0, 430)")
.attr("font-family", "Helvetica")
.attr("font-size", "15px")
.call(xAxis);
canvas.append("g")
.attr("font-family", "Helvetica")
.attr("font-size", "15px")
.style("fill", "black")
.attr("class", "y axis")
.call(yAxis);
bars.transition()
.duration(1500)
.delay(200)
.attr("width", function(d) {
return widthScale(d);
})
var yAxisLine = canvas.append("line")
.attr("x1", -3)
.attr("y1", 0)
.attr("x2", -3)
.attr("y2", 436)
.attr("stroke-width", 6)
.attr("stroke", "black");
canvas.selectAll("text")
.data(April)
.enter()
.append("text")
.text(function(d) {
return April;
})
.attr("x", function(d, i) {
return i * (width / April.length);
})
.attr("y", function(d) {
return height - (April * 4);
});
</script>
<h2>Resources</h2>
</body>
</html>
As you can see the data is not easily readable and hard to understand without knowing the precise number within the data. How do I make numbers appear next to the bars which say the exact amount of data being displayed. Please do not link other bar graphs with their own tooltips as I am not very good with d3.js and do not understand other graphs as well.
You can achieve that by first creating labels like below:
var texts = canvas.selectAll(".label")//select all DOMs with class label.
.data(April)
.enter()
.append("text")
.attr("class", "label")
.attr("x", function(d) {
return widthScale(d) + 10;//x location of the label
})
.attr("fill", function(d) {
return color(d)
})
.attr("y", function(d, i) {
return (i * 55) + 25; //y location of the label
})
.text(function(d, i) {
return d;
})
Finally in the update section do the following to update the labels.
texts = canvas.selectAll(".label")
.data(data)
.attr("x", function(d) {
return widthScale(d) + 10;
})
.attr("fill", function(d) {
return color(d)
})
.attr("y", function(d, i) {
return (i * 55) + 25
})
.text(function(d, i) {
return d;
})
working code here
I have a simple stacked bar chart :
The code is here.
I would like to have scroll-bar on the axis but as you can see in the link the scroll appears for the div container with the help of CSS.
But i need something like this chart with scroll!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.goquery.min.js"></script>
<style>
.axis path,
.axis line {
fill: none;
stroke: #BDBDBD;
}
.axis text {
font-family: 'Open Sans regular', 'Open Sans';
font-size: 13px;
}
.y.axis{
direction: ltr;
}
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
}
.grid path {
stroke-width: 0;
}
.rect {
stroke: lightgrey;
fill-opacity: 0.6;
}
.wrapperDiv {
Width: 984px;
height: 35px;
border: thin solid black;
#margin-top: 36px;
#margin-bottom: 48px;
#margin-right: 20px;
#margin-left: 0px;
}
.divChart {
float:left;
font-size:13px;
color : #424242;
font-family: 'Open Sans regular', 'Open Sans';
#border: thin solid white;
margin-top: -0px;
#margin-bottom: 48px;
#margin-right: 150px;
margin-left: 50px;
#background-color: lightgrey;
width: 984px;
height: 500px;
#padding: 25px;
border: thin solid navy;
#margin: 25px;
#max-height:500px;
overflow-y:scroll;
direction: rtl;
}
</style>
</head>
<body>
<div class="divChart" id="wrapper-chart">
<div id ="chartID" ></div>
</div>
<script src="http://d3js.org/d3.v3.min.js"></script><script>
<script>
var dataset = [{"key":"Completion","values":[{"name":"Module 1","value":0},{"name":"Module 2","value":0},{"name":"Module 3","value":0},{"name":"Module 4","value":0},{"name":"Module 5","value":0},{"name":"Module 6","value":0},{"name":"Module 7","value":0},{"name":"Module 8","value":0.56},{"name":"Module 9","value":13.24},{"name":"Module 10","value":12.66}]},{"key":"NonCompletion","values":[{"name":"Module 1","value":100},{"name":"Module 2","value":100},{"name":"Module 3","value":100},{"name":"Module 4","value":100},{"name":"Module 5","value":100},{"name":"Module 6","value":100},{"name":"Module 7","value":100},{"name":"Module 8","value":99.44},{"name":"Module 9","value":86.76},{"name":"Module 10","value":87.34}]}];
function intChart(chartID, dataset) {
var margins = {top: 20, right: 20, bottom: 30, left: 120};
var width = 880 - margins.left -margins.right;
var height = 5250- margins.top - margins.bottom;
var old_width = width,old_height= height;
var module_fixed = 80;
height = Math.floor((dataset[0].values.length * height)/module_fixed)
var x = d3.scale.ordinal().rangeRoundBands([0, width], .1,.1)
var y = d3.scale.linear().rangeRound([height, 0], .1);
var series = dataset.map(function(d) {
return d.key;
});
dataset = dataset.map(function(d) {
return d.values.map(function(o, i) {
// Structure it so that your numeric
// axis (the stacked amount) is y
return {
y: o.value,
x: o.name
};
});
});
var stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function(
group) {
return group.map(function(d) {
// Invert the x and y values, and y0 becomes x0
return {
x: d.y,
y: d.x,
x0: d.y0
};
});
});
var xMax = d3.max(dataset, function(
group) {
return d3.max(group, function(d) {
return d.x + d.x0;
});
});
var xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]);
var moduleName = dataset[0]
.map(function(d) {
return d.y;
});
var yScale = d3.scale.ordinal()
.domain(moduleName)
.rangeRoundBands([height,0]);
var svg = d3.select('#chartID')
.append('svg')
.attr("width", width + margins.left +
margins.right)
.attr("height", height + margins.top +
margins.bottom)
.append('g')
.attr('transform', 'translate(60,' + margins.top +
')');
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.ticks(2)
.tickSize(0)
.tickPadding(20)
.tickFormat(function(d) {
return d + "%";
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(0);
var colours = d3.scale.ordinal().range(
["#8bc34a", "#ff8a65"]);
var groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g').attr('class', 'stacked')
.style('fill', function(d, i) {
return colours(i);
});
var rects = groups.selectAll(
'stackedBar')
.data(function(d, i) {
return d;
})
.enter()
.append('rect')
.attr('class', 'stackedBar')
.attr('x', function(d) {
return xScale(d.x0);
})
.attr('y', function(d, i) {
return yScale(d.y);
})
.attr('height', 48)
.attr('width', 0)
rects.transition()
.delay(function(d, i) {
return i * 50;
})
.attr("x", function(d) {
return xScale(d.x0);
})
.attr("width", function(d) {
return xScale(d.x);
})
.duration(3000);
//Added
x.domain(dataset.map(function(d) {
return d.value;
}));
y.domain([0, d3.max(dataset, function(
d) {
return d.name;
})]);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' +height + ')')
.call(xAxis)
.append("text")
.attr("transform", "rotate(360)")
.attr("y",10)
.attr("x", 140)
.attr("dy", ".30em")
.text("Percentage of Students");
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.5em")
.attr("dy", ".15em")
.attr("y", "-")
.attr("opacity", 1)
.attr("transform", function(d) {
return "rotate(-40)"
})
// Draw Y-axis grid lines
svg.selectAll("line.y")
.data(y.ticks(2))
.enter().append("line")
.attr("class", "y")
.attr("x1", 0)
.attr("x2", 450)
.attr("y1", y)
.attr("y2", y)
.style("stroke", "#ccc");
}
$(document).ready(function(){
intChart("chartID", dataset);
});
</script>
Would appreciate any help.
Thanks in advance.
I don't think this can be done using D3 only. If you want to use CSS, you need to fix the position of the x-axis. You can add a separate DIV and SVG container for the X axis (these are not scrollable), and the rest of the chart in another.
I modified you code to do this see here. Please note that you code needs a lot of cleaning, as there are several non-functional parts that makes it really confusing.
The modifications are as follows:
HTML
Added a new DIV (xaxis)
<div id="wrapper-chart">
<div class="divChart" id="chartID"></div>
<div id="xaxis"></div>
</div>
CSS
Added styling for the new div (same as divChart but without the scrolling)
#xaxis {
float: left;
font-size: 13px;
color: #424242;
font-family: 'Open Sans regular', 'Open Sans';
width: 984px;
direction: rtl;
}
JS
A new SVG container for the x-axis. Notice the height attribute.
var xaxis_svg = d3.select('#xaxis')
.append('svg')
.attr("width", width + margins.left + margins.right)
.attr("height", margins.bottom)
.append('g')
.attr('transform', 'translate(60,0)');
Append the x-axis to the container.
xaxis_svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + 0 + ')')
.call(xAxis)
.append("text")
.attr("y", 10)
.attr("x", 140)
.attr("dy", ".30em")
.text("Percentage of Students");
Hope this helps.
I hope you can help. I am building a bar chart with D3 that I need to add labels to as well as append a path to show trends and goals. I added a line for the path but it doesn't seem to be generating. My CSV file with the data is structured like so:
date,projectCode,numberOfSchools,newSchools
2011-12-1,"PRJ2.1",1188,0
And code is below:
<!Doctype html>
<html>
<head>
<title>D3 bar and line chart for Aphellion</title>
<meta charset="utf-8">
<script type="text/javascript" src="js/d3.v3.js"></script>
<!-- <script type="text/javascript" src"//cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min.js"></script> -->
<style type="text/css">
/* the style for the page and charts goes here */
.axis {
font: 10px sans-serif;
}
.axis path
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.rect:hover {
fill: orange;
}
#tooltip {
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
</style>
</head>
<body>
<div id="lineChart"></div>
<script type="text/javascript">
"Use strict"
//The script for the bar chart and line charts goes here
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom
barPadding = 3;
//parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").parse;
//set up the scales
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
//set up the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%Y-%m"));
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var svg = d3.select("body").append("svg")
.attr("class", "barChart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("Data/data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date.toString());
d.numberOfSchools = +d.numberOfSchools;
});
x.domain(data.map(function(d) {return d.date;}));
y.domain([0, d3.max(data, function(d) {return d.numberOfSchools;})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.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("Schools");
svg.selectAll("bar")
.data(data)
.enter()
.append("rect")
.style("fill", function(d) {
if(d.numberOfSchools < 1200) {
return "#ff0000";
} else if (d.numberOfSchools === 2000) {
return "#33cc33";
} else {return "steelblue";}
})
.attr("class", "rect")
.attr("x", function(d) {return x(d.date);})
.attr("width", x.rangeBand() - barPadding)
.attr("y", function(d) {return y(d.numberOfSchools);})
.attr("height", function(d) {return height - y(d.numberOfSchools);})
.on("mouseover", function(d) {
//Get this bar's x/y values, then augment for the tooltip
var xPosition = parseFloat(d3.select(this).attr("x")) + x.rangeBand() / 2;
var yPosition = parseFloat(d3.select(this).attr("y")) + 14;
//Create the tooltip label
svg.append("text")
.attr("id", "tooltip")
.attr("x", xPosition)
.attr("y", yPosition)
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("font-weight", "bold")
.attr("fill", "black")
.text(d.numberOfSchools + " current schools.");
})
.on("mouseout", function() {
//Remove the tooltip
d3.select("#tooltip").remove();
});
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) {
return d.numberOfSchools;
})
.attr("x", function(d) {return x(d.date);})
.attr("y", function(d) {return y(d.numberOfSchools);});
})
//add a path to interpolate through the bars
var line = d3.svg.line()
.x(function(d) {return x(d.date)})
.y(function(d) {return y(d.numberOfSchools)});
//add the path
/*d3.select("svg")
.append("path")
.attr("d", line(data.numberOfSchools))
.attr("class", "numberOfSchools");
});*/
console.log("This code works");
</script>
</body>
</html>
Also theoretically can I use the same code to create a line chart with the bars? I tried creating a fiddle but my CSV can't be added. Here it is though: http://jsfiddle.net/siyafrica/bfVHU/
Maybe this will help:
jsFiddle: http://jsfiddle.net/reblace/bfVHU/7/
I had to make a bunch of changes to get it working, but basically it's hard to get the rangeBands method working with bar charts using time data. There's a bunch of stuff written on this subject, here's a good (brief) convo about it: https://groups.google.com/forum/#!topic/d3-js/7GsDmnB4kdE
I switched it to use a date scale, which will generally work, but you'll have to do some work to get the bar widths and positioning to be correct.
var x = d3.time.scale().range([0, width]);
x.domain(d3.extent(data, function(d) { return d.date; }));
Also, your line generator needs to be passed the data array...
var line = d3.svg.line()
.x(function(d) {return x(d.date)})
.y(function(d) {return y(d.value)});
//add the path
svg.append("path")
.attr("d", line(data))
.attr("class", "numberOfSchools");
If you want to stick with the ordinal x scale and use rangebands, you may need a secondary time scale for drawing the path and you will want to add all the dates in the extent of the domain, otherwise "empty" days will not show up on your chart.