d3.js How to draw line chart with vertical x axis labels?
My Fiddle:
https://jsfiddle.net/nitinjs/p1r49qeg/
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
UPDATE
I have few questions,
1. how to make this graph resposive in bootstrap ie. without hardcoding width and height
2. how to update this graph on button click
3. how do I start y axis at 0 to any value e.g. 0 to 9100
Updated answer: to change the label rotation just select all text elements and apply rotate through transform attribute, and adjust the location using dx and dy, also if you notice I changed the padding bottom value in margin variable to be able to view the tick text since this will make them half visible with rotation.
...
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
...
or a working snippet:
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y))
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
svg
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<div id="my_dataviz"></div>
updated answer for, I added responsive to the chart and change the label of the first element in the left axis, I will leave the data update to you, also some notes there are better ways to make responsive d3 charts one of them is to use viewport attribute but I didn't test it myself, also the first the element to start from 0 I did it as a hack, I'm sure there is a better way of doing it without select and change, those are a starting point for you, I hope my change give some insights on where to look for here:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div id="my_dataviz"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 60, left: 60},
width = 1280 - margin.left - margin.right,
height = 650 - margin.top - margin.bottom - 45;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr('class', 'main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/connectedscatter.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
var axisBottom = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
// Add Y axis
var y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
var axisLeft = svg.append("g")
.call(d3.axisLeft(y));
// Add the line
var line = svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the points
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2")
function drawChart() {
// reset the width
width = parseInt(d3.select('body').style('width'), 10) - margin.left - margin.right;
height = (width * 0.45) - margin.top - margin.bottom;
d3.select("#my_dataviz svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
d3.select('.main-container')
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
axisBottom.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.attr('class', 'axis-bottom')
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", "rotate(-90)");
// Add Y axis
y = d3.scaleLinear()
.domain( [8000, 9200])
.range([ height, 0 ]);
axisLeft.call(d3.axisLeft(y)).attr('class', 'axis-left');
//this is shiit!! there must be a better way.
d3.selectAll('.axis-left text').filter((d, i) => { return i === 0}).text('0,000');
line.datum(data)
.attr("fill", "none")
.attr("stroke", "#69b3a2")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
);
d3.select('.dots').remove();
var dots = svg
.append("g")
.attr('class', 'dots')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return x(d.date) } )
.attr("cy", function(d) { return y(d.value) } )
.attr("r", 5)
.attr("fill", "#69b3a2");
}
// call this once to draw the chart initially
drawChart();
//////////////////////////////////////////////
// Resizing //////////////////////////////////
//////////////////////////////////////////////
// redraw chart on resize
window.addEventListener('resize', drawChart);
})
</script>
</body>
</html>
Related
I'm an absolute beginner and created a line chart - the yaxis tick increment in 1000,2000,3000,4000 - I wolud like to find the SVG co-ordinates of for instance - the 2000 tick, how would i do this?
This is an image of the graph
Here are the Values:
time,value
11:00,1600
11:30,2000
12:00,1000
12:30,1100
13:00,4300
13:30,3140
14:00,4800
14:30,1720
15:00,1000
15:30,960
16:00,3210
Here is the code, (you can tell i'm new to this - any suggestions welcome)
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.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 + ")");
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
//Read the data
d3.csv("file://Values.csv",
// When reading the csv, I must format variables:
function(d){
return { date : d3.timeParse("%I:%M")(d.time), value : d.value }
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
var x = d3.scaleTime()
.domain(d3.extent(data, function(d) { return d.date; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.style("font-size", "16px");
var formatTime = d3.timeFormat("%H:%M");
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 5000])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y))
.style("font-size", "16px");
// Horixontal Grid Lines
svg.selectAll("line.horizontalGrid").data(y.ticks(18)).enter()
.append("line")
.attr("class","horizontalGrid")
.attr("x1" , 0)
.attr("x2" , width)
.attr("y1" , function(d){ return y(d);})
.attr("y2" , function(d){ return y(d);})
.attr("fill","none")
.attr("shape-rendering","crispEdges")
.attr("stroke", "#ccc")
.attr("stroke-width", "0.5px")
//Vertical Grid Lines
svg.selectAll("line.verticalGrid").data(x.ticks(18)).enter()
.append("line")
.attr("class","verticalGrid")
.attr("y1" , 0)
.attr("y2" , height)
.attr("x1" , function(d){ return x(d);})
.attr("x2" , function(d){ return x(d);})
.attr("fill","none")
.attr("shape-rendering","crispEdges")
.attr("stroke", "#ccc")
.attr("stroke-width", "0.5px")
// Add the line
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
)
// Add the scatter plot
svg.selectAll("myCircles")
.data(data)
.enter()
.append("circle")
.attr("fill", "Black")
.attr("stroke", "none")
.attr("cx", function(d) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.attr("r", 3)
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html("X: " +(d3.event.pageX) + "px" + " Y: " + (d3.event.pageY - 28) + "px" + "<br/>")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
})
</script>
</body>
</html>
Thanks in advance,
I am hoping to make my bar changes color and display the year and value as the mouse hooves over it. I have the "mouseover, mouseout, and mousemove" but doesn't seem to work. Any help would be great. When I click on the bar, the key and value appear in the console. The values are nested. Thank you
Js:
//set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 70
},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom,
padding = 15;
// Fomat timeStamp to year
var dateFormat = d3.timeFormat("%Y");
//append the svg object to the body of the page
var svg = d3.select("#graph").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 + ")");
// Get the data
d3.json("https://moto.data.socrata.com/resource/jfwn-iu5d.json?
$limit=500000",
function(data) {
// Objects
data.forEach(function(data) {
data.incident_description = data.incident_description;
data.incident_datetime = dateFormat(new Date(data.incident_datetime));
});
// Nest data by year of incident
var NestbyDate = d3.nest()
.key(function(d) {
return d.incident_datetime;
})
.key(function(d) {
return d.incident_description + " " + d.incident_datetime;
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return (d.incident_description)
});
})
.entries(data);
var y_domain = d3.max(NestbyDate, function(d) {
return d.values.length;
});
console.log(NestbyDate) /
NestbyDate.sort((a, b) => a.key - b.key);
// set the ranges
var x = d3.scaleBand().domain(NestbyDate.map(d =>
d.key)).range([padding, width]);
var y = d3.scaleLinear().domain([0, y_domain]).range([height,
10]);
// Add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(6));
// Add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y));
// Text label for the x-axis
svg.append("text")
.attr("x", width / 2)
.attr("y", height + margin.top + 7)
.style("text-anchor", "center")
.text("Day Date Format")
.text("Year");
// Text Label for y-axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Number of crime incidents");
// Draw the bars
svg.selectAll("rect")
.data(NestbyDate)
.enter()
.append("rect")
.attr("class", "rect")
.attr("x", function(d) {
return x(d.key);
})
.attr("y", function(d) {
return y(d.values.length);
})
.attr("fill", "darkblue")
.attr("width", x.bandwidth())
.attr("height", function(d) {
return y(0) - y(d.values.length);
})
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
console.log(d);
var xPosition = d3.mouse(this)[0] - 15;
var yPosition = d3.mouse(this)[1] - 55;
tooltip.attr("transform", "translate(" + xPosition +
"," + yPosition + ")");
tooltip.select("text").text(d.key +":" + y_domain);
});
// tooltips
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("text")
.attr("dy", "1.2mm")
});
graph portion of html:
<div>
<h3> Number of crimes per year</h3>
<p>Below is a bar graph of the total number of crimes per year
from 2011 to 2018. The most crime incidents occur in 2017, with a total of
101,478 crimes.</p>
<div id="graph" class="responsive-plot"></div>
</div>
</div>
I have a bar chart/histogram, all working fine.
I need to change the text and lines on the chart is on a black background.I
Also, the bar colors need to be orange.
I have had a look around the web, and seen some references to .attr("style":...); and have tried this without success.
Any pointers gratefully received.
<script>
// set the dimensions of the canvas
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 1890 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
// add the SVG element
var svg = d3.select("body").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 + ")");
// load the data
d3.json("/assets/js/risk_hist_values.json", function(error, data) {
// the number of columns in this chart
var numCols = data.length;
data.forEach(function(d) {
d.Letter = d.bin_no;
d.Freq = +d.count;
});
// scale the range of the data
x.domain(data.map(function(d) { return d.Letter; }));
y.domain([0, d3.max(data, function(d) { return d.Freq; })]);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Count:</strong> <span style='color:red'>" + d.count + "</span>";
})
// call the tips
svg.call(tip);
// add axis
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", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Count");
// Add bar chart
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.Freq); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.on('click', drill)
.attr("id", function(d, i){ return 'b_'+i+''; })
.attr("height", function(d) { return height - y(d.Freq); });
});
function drill(){
alert( 'drilling' );
}
</script>
i'm trying to generate multiple charts into multiple divs, as i try to duplicate the barchart in another div , the second barchart goes out of position and generates the chart at random location
i have posted js in two script tags
<script>
function intermediate(selected){
console.log(selected);
d3.select("svg").remove();
var metric = selected;
console.log(metric);
var dataFile = metric + '.csv';
d3.csv(dataFile,function(data){
console.log(data);
updateData(data);
});
}
var dataFile="SP_Sterling.csv";
d3.csv(dataFile,function(data){
// console.log(data);
updateData(data);
})
function updateData(data){
var margin = {top: 20, right: 20, bottom: 30, left: 80},
padding = {top: 60, right: 60, bottom: 60, left: 60},
width = 860 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#groupedbarchart").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 + ")");
// Update the bar chart
//i'm trying to Update the bar chart based on array objects and it seems that my bar is not getting refreshed
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#00a65a", "#f56954"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d,i) {
return "<strong>Count:</strong> <span style='color:red';>" + d.value + "</span>";
});
var monthvalues = d3.keys(data[0]).filter(function(key) { return key !== "Month"; });
data.forEach(function(d) {
d.monthdata = monthvalues.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Month; }));
x1.domain(monthvalues).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.monthdata, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Count");
svg.call(tip);
//enter
var bar = svg.selectAll(".bar")
.data(data);
bar.enter()
.append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x0(d.Month) + ",0)"; });
//update()
bar.selectAll("rect")
.data(function(d) { return d.monthdata; })
.enter()
.append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.style("fill", function(d) { return color(d.name); });
//remove()
var legend = svg.selectAll(".legend")
.data(monthvalues.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color)
.append("rect");
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
}
</script>
<script>
function longrunning(selected){
console.log(selected);
d3.select("svg").remove();
var metric = selected;
console.log(metric);
var dataFile1 = metric +'_long' + '.csv';
console.log(dataFile1);
d3.csv(dataFile1,function(data){
console.log(data);
updateData(data);
});
}
var dataFile1="SP_Sterling_long.csv";
d3.csv(dataFile1,function(data){
// console.log(data);
updateData(data);
})
function updateData(data){
var margin = {top: 20, right: 20, bottom: 30, left: 80},
padding = {top: 60, right: 60, bottom: 60, left: 60},
width = 860 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("#barchart").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 + ")");
// Update the bar chart
//i'm trying to Update the bar chart based on array objects and it seems that my bar is not getting refreshed
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#00a65a", "#f56954"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d,i) {
return "<strong>Count:</strong> <span style='color:red';>" + d.value + "</span>";
});
var monthvalues = d3.keys(data[0]).filter(function(key) { return key !== "Month"; });
data.forEach(function(d) {
d.monthdata = monthvalues.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Month; }));
x1.domain(monthvalues).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.monthdata, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
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("Count");
svg.call(tip);
//enter
var bar = svg.selectAll("barchart")
.data(data);
bar.enter()
.append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x0(d.Month) + ",0)"; });
//update()
bar.selectAll("rect")
.data(function(d) { return d.monthdata; })
.enter()
.append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.style("fill", function(d) { return color(d.name); });
//remove()
var legend = svg.selectAll(".legend")
.data(monthvalues.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color)
.append("rect");
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
}
</script>
<div class="groupedbarchart;visible-*-block" id="groupedbarchart" style="height: 600px;border: red 2px solid;">
<select class="selectpicker" data-live-search="false" data-size="7">
<option>SP_Sterling</option>
<option>IWH</option>
<option>IWH_BreakFix</option>
</select>
</div>
<div class="barchart;visible-*-block" id="barchart" style="height: 500px; border:red solid 2px;">
<select class="longrunning" data-live-search="false" data-size="7">
<option>SP_Sterling</option>
<option>IWH</option>
<option>IWH_BreakFix</option>
</select>
</div>
Ok, so I fixed it so you can have multiple barcharts which different id attributes. They will have the same functionality. I am sorry to say, but I really hate the jsbin editor, as it seems to very crowded and not really easy to use. Therefor, i have made a plunker, just so I could faster figure out your code. You can find it here.
Let me explain what I did:
First, i added the functionality of the select box in your html to another barchart container. Here I added the select to the div with id "bar-chart":
<div class="box-body chart-responsive">
<div class="chart" id="bar-chart" style="height: 500px;">
<select class="selectpicker" data-live-search="false" data-size="7">
<option>SP_Sterling</option>
<option>IWH</option>
<option>IWH_BreakFix</option>
</select>
</div>
</div>
Then I changed the calling function at the end of your html, the one where you build charts on the change events:
$('.selectpicker').on('change', function(){
var parent = $(this).parent();
console.log(parent);
var selected = $(this).find("option:selected").val();
//alert(selected);
intermediate(selected, parent);
});
As you can see, I am looking for the parent here (the parent of each select picker is the div to which you want to append your chart, I noticed). I pass that element as parameter to your intermediate function.
Then as last, I have changed the intermediate function. I will only show the beginning, as that is where i did my changes:
function intermediate(data, element){
d3.select("svg").remove();
var newData=[
{
"Month": "Feb",
"Success_Count": 49,
"Failure_Count": 20
},
{
"Month": "Jan",
"Success_Count": 35,
"Failure_Count": 3
}
];
updateData(newData, element);
}
function updateData(data, element){
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 760 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var selection = d3.select(element);
console.log("d3 selection", element[0]);
var svg = d3.select(element[0]).append("svg") // THIS IS VERY IMPORTANT!!
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
So basically, I have added a new parameter to your functions (the one which will pass the parent element). Then I also cleaned up your "old data". For this example, you don't need it.
Then, and this is the most important part, I have changed the d3 selection. The plunk works, if you have more questions, shoot! :-)
************* EDIT ****************
I did notice that the charts do not really update the way they should and if you change one barchart, the other one disappears. I have fixed that now. The plunker code has been update (the link should still be the same).
What have I changed:
d3.select("svg").remove();
This has been removed from the code. You don't need it.
Then, I also had to change the update data function:
function updateData(data, element){
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 760 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg;
//check if there already is an svg element
if(d3.select(element[0]).select("svg").empty()) {
svg = d3.select(element[0]).append("svg") // THIS IS VERY IMPORTANT!!
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
As you can see, it now checks if there is already an svg. If so, it just updates the data and the graph if necessary. You also need this:
...
else {
svg = d3.select(element[0]).select("svg");
}
in case there already is an svg element. The graph and its axes is created entirely in that first "if" statement.
This whole thing of enter selections, updating and the exit selection might look very complicated. I have written about it in a previous post, which you can find here. If you have more questions, please let me know!
I am developing bar graph using d3.js integrating with angular js.I am new to d3.js. I dont know how we can limt the the no.of x and y axis ticks.
The working is given below
mainApp.directive('ngTest', function() {
return {
restrict: 'AE',
scope: {
data: '='
},
link: function (scope, element) {
var margin = {top: 20, right: 30, bottom: 30, left: 60},
width = 410 - margin.left - margin.right,
height = 230 - margin.top - margin.bottom;
var chart = d3.select(element[0])
.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 x = d3.scale.ordinal().rangeRoundBands([0, width], .1);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:red'>" + d.value + "</span>";
});
chart.call(tip);
//Render graph based on 'data'
scope.render = function(data) {
var y = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(data, function(d) { return d.value; }))
.nice();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
x.domain(data.map(function(d) { return d.name; }));
//Redraw the axes
chart.selectAll('g.axis').remove();
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-20)";
});
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0-margin.left)
.attr("x",0-(height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) { return d.value < 0 ? "bar negative" : "bar positive"; })
.attr("x", function(d) { return x(d.name); })
.attr("y", height)
.attr("height", 0)
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.transition().duration(2000)
.attr("y", function(d) {return y(Math.max(0, d.value)); })
.attr("height", function(d) {return Math.abs(y(d.value) - y(0)); })
// .attr("width", x.rangeBand());
.attr("width", Math.min.apply(null, [x.rangeBand()-2, 100]));
};
scope.$watch('data', function() {
scope.render(scope.data);
}, true);
}
};
});
The working example is given in following fiddle adderss
http://jsfiddle.net/HB7LU/9000/
Use ticks method of d3 axis. Since tick format of x axis is time, you might specify both a count and a tick format.
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(d3.time.day, 2);
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5);
You can refer more about d3 svg axis from here and about time formats from here