how to change x axis in D3? - javascript

I tried to create a bar chart showing days of each month in a year. I want to change the numbers in x-axis of bar chart, but it turns out that the number starts from 0 and ends with 11, instead of 1 to 12. How can I solve this problem?
//x
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, width - padding.left - padding.right]);
//y
var yScale = d3.scale.linear()
.domain([0,d3.max(dataset)])
.range([height - padding.top - padding.bottom, 0]);
//the define of x
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//define of y
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
/add x
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);

use tickformat() to format the axis labels as:
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(function(d) { return d + 1; }); //make changes here relevant to ur data

Related

How to have the same scale in both x and y

I have this graph : http://jsfiddle.net/thatOneGuy/Rt65L/94/
I can't seem to figure out how to get the same scale in both x and y. What I need is the same distance between the ticks on both but I need the x axis to be 600px long and y axis to be 300px high.
I have tried calling the same scale but obviously the x scale is too big for the y. Any ideas ?
<svg id='svgContainer' width="1000" height="700"> </svg>
var container = d3.select('#svgContainer')
.style('stroke', 'red')
var width = 600, height = 300;
var xScale = d3.scale.linear()
.range([0, width]);
var yScale = d3.scale.linear()
.range([0, height]);
var xTicks = width/50;
var yTicks = height/50;
var xAxis = d3.svg.axis()
.scale(xScale)
.innerTickSize(-(height)) // vertical grid lines
.outerTickSize(0)
.orient("bottom")
.ticks(xTicks);
var yAxis = d3.svg.axis()
.scale(yScale)
.innerTickSize(-(width)) // horizontal grid lines
.outerTickSize(0)
.orient("left")
.ticks(yTicks);
container.append("g")
.attr("class", "x axis")
.attr("transform", "translate(50," + (height+20) + ")")
.call(xAxis)
container.append("g")
.attr("class", "y axis")
.attr("transform", "translate(50,20)")
.call(yAxis)
If you don't set the domain, D3 will automatically set it as [0, 1]. So, I believe that, in your case, it's simply a matter of setting the domains:
var xScale = d3.scale.linear()
.range([0, width])
.domain([0,1]);
var yScale = d3.scale.linear()
.range([height, 0])
.domain([0,0.5]);
Here is the fiddle: http://jsfiddle.net/gerardofurtado/Rt65L/96/

How to Draw X-Axis with Dates from Array

Pre-emptive apologies for any novice mistakes made in the underlying code. I am attempting to generate a simple line chart with d3.js, with dates on the x-axis and integer values on the y-axis. The data is supplied by two arrays: xDataGet and yData from The issue I'm having is, from what I can gather, that the strings in xDataGet are not being properly converted to Dates. In tinkering with the code, I can manage to have the Y-Axis appear, but have had no such luck with the X-Axis. Could someone indicate where I'm going wrong?
var margin = [80, 80, 80, 80]; // margins
var width = 1000 - margin[1] - margin[3]; // width
var height = 400 - margin[0] - margin[2]; // height
var xDataGet = [ '03/18/2014', '03/01/2014', '02/15/2014', '02/01/2014', '01/18/2014', '12/07/2013', '11/16/2013' ]
function getDate(d) {
formatted = d3.time.format("%m-%d-%Y")
return formatted(new Date(d));
}
var xData = getDate(xDataGet)
var yData = [ 33, 36, 42, 27, 36, 21, 18 ]
var x = d3.time.scale()
.range([0, width])
.domain([d3.min(xData), d3.max(xData)])
var y = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(yData)]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var line = d3.svg.line()
.x(function(d) { return x(xData); })
.y(function(d) { return y(yData); })
.interpolate("linear");
var svg = d3.select("body").append("svg")
.attr("width", width + 80 + 80)
.attr("height", height + 80 + 80)
.append("g")
.attr("transform", "translate(" + 80 + "," + 80 + ")");
svg.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(-25,0)")
.call(yAxis);
svg.append("svg:path").attr("d", line);

Why d3 time scale only shows me 00:00?

I'm new to d3 and I'm trying to do some data visualization with it. I found some examples about how to create a time scale in d3, but when I followed the examples and try to create the time scale, it failed. I was frustrated because I couldn't figure out where it went wrong... the example is like this:
how to format time on xAxis use d3.js
So my code is like this:
boxplotdata =[]
boxplotdata.push(
{"datetime":"2013-10-30 01:47",length: 500, start:100,deep1_a:130,deep1:50,deep2_a:200,deep2:60,deep3_a:280,deep3:50,deep4_a:350,deep4:60},
{"datetime":"2013-10-31 01:45",length: 600, start:200,deep1_a:230,deep1:60,deep2_a:300,deep2:60,deep3_a:380,deep3:50,deep4_a:450,deep4:60},
{"datetime":"2013-11-01 02:11",length: 550,start:150,deep1_a:180,deep1:50,deep2_a:250,deep2:60,deep3_a:350,deep3:50,deep4_a:410,deep4:60},
{"datetime":"2013-11-02 01:59",length: 500,start:160,deep1_a:190,deep1:80,deep2_a:300,deep2:60,deep3_a:370,deep3:50,deep4_a:430,deep4:60},
);
//SET MARGIN FOR THE CANVAS
var margin = {top: 30, right: 10, bottom: 10, left: 10},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d %H:%M").parse;
//SET X AND Y
var x = d3.time.scale()
.domain([0,11])
.range([50, width]);
var y = d3.time.scale()
.domain([new Date(boxplotdata[0].datetime),d3.time.day.offset(new Date(boxplotdata[boxplotdata.length-1].datetime),1)])
.rangeRound([20, height-margin.top- margin.bottom]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top")
.tickFormat(d3.time.format("%H:%M"))
//.ticks(d3.time.minutes,15)
//.tickPadding(8);
var yAxis = d3.svg.axis()
.scale(y)
.orient('right')
.ticks(d3.time.days,1)
.tickFormat(d3.time.format('%m-%d'))
.tickSize(0)
.tickPadding(8);
var line = d3.svg.line()
.x(function(d) { return x(d.datetime); });
var w=960,h=1000;
d3.select("#chart").selectAll("svg").remove(); //Old canvas must be removed before creating a new canvas.
var svg=d3.select("#chart").append("svg")
//.attr("width",w).attr("height",h);
.attr("width",w+margin.right+margin.left).attr("height",h+margin.top+margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
boxplotdata.forEach(function(d) {
d.datetime = parseDate(d.datetime);
});
x.domain(d3.extent(boxplotdata, function(d) { return d.datetime; }));
bars = svg.selectAll("g")
.data(boxplotdata)
.enter()
.append("g");
some drawing codes here..., and at last:
svg.append("g")
.attr("class", "x axis")
//.attr('transform', 'translate(0, ' + (height - margin.top - margin.bottom) + ')')
.call(xAxis);
svg.append("g")
.attr('class', 'y axis')
.call(yAxis);
However, when I tried, I could only get a graph with all time on the xAxis shown as "00:00". What's going wrong here? Hope someone can help me out. Thanks!
Your example data is from different days, so what's happening here is that D3 is picking representative values (i.e. the boundaries between days) and making ticks for that. As your date format only shows hour and minute, 00:00 is all you get.
You have basically two options here. You could either change the date format to show days (which is what D3 intends), or you could set the tick values explicitly to whatever you want. For the first, you could use e.g. d3.time.format("%a"). For the second, see the documentation.
Hi You can use the tickFormat function on the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%H"));

D3 zoomable yAxis in hours

I am trying to figure out how to make a zoomable y axis that is in hours. I want the y axis to range from 7AM to 5PM. My x axis in days.
Currently, I have the y axis in hours but it only shows 12AM at the top of the y axis. I am unsure of where to get it to go from 7AM to 5PM. My code does zoom on both of the axis.
Any help would be appreciated :)
// Define the min and max date
var mindate = new Date(2013,0,20), // TODO: clip date
maxdate = new Date(2013,0,25);
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.time.scale()
.domain([mindate, maxdate])
.range([0, width]);
var y = d3.time.scale()
.domain([mindate, maxdate])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.days, 1)
.tickFormat(d3.time.format("%A : %d")); // d is for testing
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(d3.time.days, 12)
.tickFormat(d3.time.format("%I %p")); // For 12 hour time
var zoom = d3.behavior.zoom()
// .x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
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 + ")")
.call(zoom);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
I'm not 100% sure if this is what you're after, but I've interpreted your question as how to create a scale from 7am to 5pm on the same day with 1 hour steps. The first thing was to create a set of dates for the y-scale for the required time as in:
var ymindate = new Date(2013,0,20, 7), // TODO: clip date
ymaxdate = new Date(2013,0,20, 17);
The next step required only minor changes to your code. the ticks were set to d3.time.hours not days and the step was set to 1 hour, as shown below.
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(d3.time.hours, 1)
.tickFormat(d3.time.format("%I %p"));
If you want just 7am and 5pm to appear on multiple days you would have to create a custom set of ticks and use a time intervals
You would need to set the domain of the y scale accordingly. At the moment, your min and max dates are both full days, so you get only one value for the time. If you used for example
var mindate = new Date(2013,0,20, 7, 0, 0, 0),
maxdate = new Date(2013,0,25, 17, 0, 0, 0);
you should get the times you want on the y axis.

Unable to align ticks with d3.js

Working with one bar chart with d3.js I am unable to align ticks in x axis with bars.
In left and right verges the ticks are ok, but not in the middle.
Here is the code:
var formatDate = d3.time.format("%e %b");
var height = 325;
var xTimeScale = d3.time.scale()
.domain([new Date(data[0].date), d3.time.day.offset(new Date(data[data.length - 2].date), 1)])
.range([30, width]);
var xAxis = d3.svg.axis()
.scale(xTimeScale)
.orient("bottom")
.ticks(d3.time.days, .1)
.tickFormat(formatDate);
chart.append("g")
.attr("class", "xaxis axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.selectAll(".xaxis text")
.attr("transform", function(d) {return "translate(" + this.getBBox().height * -2 + "," + this.getBBox().height + ")rotate(-45)";});
What am I missing?
Thanks in advance.
Update: Here is the jsFiddle updated with chrtan suggestions.
My problem now is to align text with the center of bar and not in left.
From the looks of your graph, you lost a bar's worth of space. If all the bars are supposed to be left-aligned against a tick, that final bar you have should be to the right of the January 31st tick.
You might need to add the February 1st tick by perhaps changing the [data.length - 2] to [data.length - 1] in the domain() for your xTimeScale.
Then for display purposes, you could probably remove the last tick axis text with:
d3.select(chart.selectAll(".xaxis text")[0].pop()).remove();
The inner selectAll should get the array containing your xAxis tick texts and then pop the very last tick. This last tick should then be removed by the outer select.
An example with an auto time ticks with d3.js
// set domain for axis
var x_domain = d3.extent(data, function(d) { return new Date(d.date); });
//format date
var date_format = d3.time.format('%Y %B');
var vis = d3.select("#graph")
.append("svg:svg")
.attr('class', 'chart')
.attr("width", width)
.attr("height", height);
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.data; })]).nice()
.range([height - padding, padding]);
var xScale = d3.time.scale()
.domain(x_domain)
.range([padding, width - padding]);
// define the y axis
var yAxis = d3.svg.axis()
.orient("left")
.scale(yScale);
// define the x axis
var xAxis = d3.svg.axis()
.orient("bottom")
.scale(xScale)
.tickFormat(date_format);
// draw y axis with labels and move in from the size by the amount of padding
vis.append("g")
.attr("class", "axis")
.attr("transform", "translate("+padding+",0)")
.call(yAxis);
// draw x axis with labels and move to the bottom of the chart area
vis.append("g")
.attr("class", "xaxis axis")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(xAxis);
// and set data in graph...
a great example : http://bl.ocks.org/phoebebright/3061203

Categories

Resources