D3.js x-axis time scale - d3.js

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)]);

Related

Tooltip for d3 v4 is not responding to the bar graph

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>

Change chart colors

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>

extend x and y axis length in scatterplot, d3js

I am trying to extend the x and y axis length and add the arrow at the end. Here is my code and plunker. I need x axis to extend beyond 4.6 and y-axis beyond "AS" and add an arrow at the end. Kindly help.
https://plnkr.co/edit/tA6oyKQCCmhNadbARR89?p=preview
var margin = {top: 20, right: 20, bottom: 20, left: 40},
width = 420 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.ordinal().rangePoints([height, 0])
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").outerTickSize(0);
var yAxis = d3.svg.axis()
.scale(y).tickSize(-width).outerTickSize(0)
.orient("left");
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 + ")");
d3.tsv("data.tsv", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.sepalWidth = +d.sepalWidth;
});
x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice();
y.domain(data.map(function(d) { return d.sepalLength;}));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.sepalWidth); })
.attr("cy", function(d) { return y(d.sepalLength); })
.style("fill", function(d) { return color(d.species); });
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
Easiest way is to just tack on a custom path to the end of the axis:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.append("path")
// add extension arrow
.attr("d", "M" + width + ",0L" + (width + 20) + ",0L" + (width + 20) + ",-5L" + (width + 30) + ",0L" + (width + 20) + ",5L" + (width + 20) + ",0L");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("path")
// add extension arrow
.attr("d", "M0,0L0,-20L-5,-20L0,-30L5,-20,L0,-20Z");
Updated plunker.

In d3.js ticks are not showing in the x axis

I am trying to show a barchart using d3.js. Y axis contains the speed and x axis contains time. I am using the following code:
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 400 - margin.left - margin.right,
height = 250 - margin.top;
var x = d3.scale.ordinal().rangeRoundBands([ 0, width ], .1);
var y = d3.scale.linear().range([ height, 0 ]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(20);
x.domain(data.map(function(d) { return d.datetime; }));
y.domain([0, d3.max(data, function(d) { return d.speed; })]);
var svg=d3.select("#bar").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 transition = svg.transition().duration(750), delay = function(d, i) {
return i * 50;
};
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)" ).text("Time");
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("Speed");
svg.selectAll("rect")
.data(data)
.enter().append("rect").transition().delay(0)
.style("fill", "red")
.attr("x", function(d,i) { return 30*i+20; })
.attr("width", 25)
.attr("y", function(d) { return y(d.speed); })
.attr("height", function(d) { return height - y(d.speed); }); //function(d){return " "+d.datetime;}
transition.select(".y.axis").call(yAxis);
But unfortunately no ticks are showing in the x axis. Y axis ticks are working fine. Can anyone help me regarding this?
In your x-axis creation, this:
.attr("transform", "rotate(-90)" ).text("Time");
is just going to but the word "Time" on each tick. What you need is:
// define the time format you want
var format = d3.time.format("%Y-%m-%d");
// create x axis
...
.text(function(d){
return format(d);
});
Also in your rect placement:
svg.selectAll("rect")
...
.attr("x", function(d,i) { return 30*i+20; })
You are spacing them based on index. You need to match this to the axis position:
svg.selectAll("rect")
...
.attr("x", function(d, i) {
return x(d.datetime);
})
Here's an example.
Your problem may be where you set the domain for x:
x.domain(data.map(function(d) { return d.datetime; }));
You probably want something like:
x.domain([d3.min(data, function(d) { return d.datetime; }), d3.max(data, function(d) { return d.datetime; })]);

Limitting x and y axis ticks in bar graph with d3.js

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

Resources