Related
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>
I have three charts in different positions. The tooltips look fine for my first chart, but for the other two the tooltips show in the first chart.
I've tried BBbox and getboundindclientrect(), and none of them work for d3.select(this).
// This is my chart module, I'm struggling to get xPosition and yPosition right.
function chart(selection) {
innerWidth = width - margin.left - margin.right,
innerHeight = height - margin.top - margin.bottom,
selection.each(function (data) {
// Select the svg element, if it exists.
var svg = d3.select(this).selectAll("svg").data([data]);
// Otherwise, create the skeletal chart.
var svgEnter = svg.enter().append("svg");
var gEnter = svgEnter.append("g");
gEnter.append("g").attr("class", "x axis");
gEnter.append("g").attr("class", "y axis");
// Update the outer dimensions.
svg.merge(svgEnter).attr("width", width)
.attr("height", height);
// Update the inner dimensions.
var g = svg.merge(svgEnter).select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
xScale.rangeRound([0, innerWidth])
.domain(data.map(xValue)); //xValue = function(d) { return d[0]; }
yScale.rangeRound([innerHeight, 0])
.domain([0, d3.max(data, yValue)]);
g.select(".x.axis")
.attr("transform", "translate(0," + innerHeight + ")")
.call(d3.axisBottom(xScale));
g.select(".y.axis")
.call(d3.axisLeft(yScale).ticks(10))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
var bars = g.selectAll(".bar")
.data(function (d) { return d; });
bars.enter().append("rect")
.attr("class", "bar")
.merge(bars)
.attr("x", X) // function X(d) {return xScale(xValue(d));}
.attr("y", Y)
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return innerHeight - Y(d); })
.attr("fill", "rgb(0, 18, 65") // International Klein blue
.on("mouseover", function(d) {
//Get this bar's x/y values, then augment for the tooltip
var xPosition = parseFloat(d3.select(this).attr("x")) + xScale.bandwidth()/2; // + parseFloat(bars.node().getBBox().x);
var yPosition = parseFloat(d3.select(this).attr("y"))/2 + innerHeight/2;
//Update the tooltip position and value
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select("#value")
.text(yValue(d));
//Show the tooltip
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function() {
//Hide the tooltip
d3.select("#tooltip").classed("hidden", true);
})
.on("click", onClick);
bars.exit().remove();
});
}
I'd like to get the tooltips on top of my rectangles when I place the mouse over them.
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
I'm trying to do a scatter plot in D3.js with date on the x-axis. The code below is based on the scatter plot example on the d3 site. I must be doing something wrong in the attr('cx'
area...
var data =[
{
"title":"SUNY GENESEO COLLEGE STADIUM PHASE 2",
"stage":"Biddate Set",
"naples_update_date":"2/9/2014",
"value":7500000,
"value_type":"Confirmed",
"ownership":"State",
"work_type":"Alteration",
"record_date":"1/21/2014",
"floors":null,
"floor_area":null,
"floor_units":"",
"land_area":null,
"land_units":"",
"structures":null,
"units":0,
"contract_type":"Open Bidding",
"address":"1 College Cir",
"city":"Geneseo",
"state":"NY",
"county":"Livingston",
"date":1390911781
},
{
"title":"KENTUCKY FAIR & EXPOSITION CENTER FREEDOM HALL-ROOFING",
"stage":"Post Bid Results Pending",
"naples_update_date":"2/10/2014",
"value":2662903,
"value_type":"Confirmed",
"ownership":"State",
"work_type":"Alteration",
"record_date":"10/29/2013",
"floors":2,
"floor_area":null,
"floor_units":"",
"land_area":null,
"land_units":"",
"structures":1,
"units":0,
"contract_type":"Open Bidding",
"address":"937 Phillips Ln",
"city":"Louisville",
"state":"KY",
"county":"Jefferson",
"date":1383132359
}
];
var format = d3.time.format("%d/%m/%Y");
var dateMin = format.parse("20/03/2001");
var dateMax = format.parse("7/02/2001");
var margin = {top: 20, right: 20, bottom: 30, left: 120},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xValue = function(d) {
return format.parse(d.record_date);
}, // data -> value
xScale = d3.time.scale().domain([dateMin,dateMax]).range([0, width]), // value -> display
xMap = function(d) { return xScale(xValue(d));}, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom");
var yValue = function(d) { return d.value;}, // data -> value
yScale = d3.scale.linear().range([height, 0]), // value -> display
yMap = function(d) { return yScale(yValue(d));}, // data -> display
yAxis = d3.svg.axis().scale(yScale).orient("left");
// setup fill color
var cValue = function(d) { return d.ownership;},
color = d3.scale.category10();
// add the graph canvas to the body of the webpage
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 + ")");
// add the tooltip area to the webpage
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// don't want dots overlapping axis, so add in buffer to data domain
xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]);
yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]);
//x-axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("Date");
// y-axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value");
// draw dots
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", xMap)
.attr("cy", yMap)
.style("fill", function(d) { return color(cValue(d));})
.on("mouseover", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", 0.9);
tooltip.html(d.title + "<br/> (" + xValue(d) + ", " + yValue(d) + ")")
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
})
.attr('data-title',function(e){
return e.title;
})
.attr('data-value',function(e){
return e.value;
})
.attr('data-date',function(e){
return e.record_date;
})
.attr('data-sqft',function(e){
return e.floor_area;
});
I've searched around and tried to follow the tips out there, making sure the dates for the .range() are objects of the same format at the dates inside attr(cx).
Demo: http://jsfiddle.net/EC6TL/
The problem was in line:
xScale.domain([d3.min(data, xValue) - 1, d3.max(data, xValue) + 1]);
You cannot add and subtract 1 from dates. :-)
Fix:
xScale.domain([d3.min(data, xValue), d3.max(data, xValue)]);