I have a bar chart with the X axis, which have ticks that include the month and year. The month and year are in the single row now.
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(RU.timeFormat("%b %Y"));
I need to leave the month in the first line and move the year in the second one.
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
Here is my jsfiddle: https://jsfiddle.net/anton9ov/uaygrmLo/
There is this nice "wrap text function", written by Bostock: https://bl.ocks.org/mbostock/7555321
Using this function, I just modified your axis:
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis)
.selectAll(".tick text")
.call(wrap, 40);
Check the fiddle: https://jsfiddle.net/gerardofurtado/aLc8t6yq/
PS: I used 40 here as a magic number, change it according to your needs.
Related
var vis = d3.select("#visualisation");
xAxis = d3.axisBottom(xScale)
.ticks(numberOfRecords);
vis.append("svg:g")
.attr("class", "axis")
.attr("height", 30)
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
hi guys,
since i updated from d3.js version 3.5 to 4.2.1 the thickness of my x-axis is wrong.
with the version 3.5 i could just set the height but it is not working anymore.
any ideas?
thanks!
I'm trying to have the tick marks show up on both sides of the y axis. As the code is shown below, I'm able to extend the tick marks based on length -width which draws the tick mark from a starting point from left to right.
Is it possible to move the starting point of the tick mark further to the left?
My intent is aesthetics, but to have the tick values be directly over a length of the tick marks.
I have a grid set up, made up of container-length tick marks:
// Axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSize(-width)
.tickFormat(d3.format("s"));
Based on these scales:
// Scale
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
My axis are appended to the svg like this:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.call(adjustXLabels);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.call(adjustYLabels);
I'm a little confused about what you're after. Do you want the tick labels to overlap with the ticks themselves? If so you can select the text after the axis is drawn and then translate the ticks.
See the fiddle here: https://jsfiddle.net/6q3rpw6j/
The key bit is:
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll(".tick text")
.attr("transform", "translate(15,0)");
EDIT
To move the ticks themselves:
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll(".tick line")
.attr("transform", "translate(15,0)");
And to remove the top and bottom end ticks, make sure you set the .outerTickSize(0)
I have been developing an area chart for year(x axis) vs Revenue (y axis) in D3 Js.The data is as:
localData=[
{"Revenue":"4.5","Year":"2011"},
{"Revenue":"5.5","Year":"2010"},
{"Revenue":"7.0","Year":"2012"},
{"Revenue":"6.5","Year":"2013"}
]
I want year at x axis and revenue at y axis for an area chart.Currently I am using time scale for x axis but i dont know how to use it as I have not date format I have only Years to represent.
My Current code is:
var margin = { top: 20, right: 20, bottom: 30, left: 50 },
width = 500 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y").parse;
var x = d3.time.scale()
.range([0, width]);
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");
var area = d3.svg.area()
.x(function (d) { return x(d.Year); })
.y0(height)
.y1(function (d) { return y(d.Revenue); });
$("#chartArea").html("");
var svg = d3.select("#chartArea").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 + ")");
x.domain(d3.extent(localData, function (d) { return d.Year; }));
y.domain([0, d3.max(localData, function (d) { return d.Revenue; })]);
svg.append("path")
.datum(localData)
.attr("class", "area")
.attr("d", area)
.attr("fill",color);
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("Revenue (M)");
Currently I am getting on my X axis as .011,.012,013,.014 I need as 2011,2012,2013,2014
I am new to D3 js so dnt know much about how to use scales??Please Help anyone..Thanks in advance.
Just add tick Format to your x Axis definition:
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.time.format("%Y")); // <-- format
In v4, it'd be something like this:
d3.axisBottom(x).ticks(d3.timeYear.every(1))
huan feng is right. The time scale is treating your year(implicitly converted to an int) as timestamps. To force the scale to operate on the year, create Date objects specifying the year in it. Basically change the following line:
x.domain(d3.extent(localData, function (d) { return d.Year; }));
to
x.domain(d3.extent(localData, function (d) { return new Date(parseInt(d.Year),0); }));
You may then use Klaujesi's solution to change the tickFormat.
I have two axes in my graph right now, that are stuck at the very left and bottom of the graph. I want to make the axes line up with the (0,0) coordinate, or in other words I want the axes to be at x=0 and y=0
Here's my axes code:
//setup x
var xAxis = d3.svg.axis()
.scale(xRange)
.tickSize(5)
.tickSubdivide(true),
//setup y
yAxis = d3.svg.axis()
.scale(yRange)
.tickSize(5)
.orient("left")
.tickSubdivide(true);
I was thinking that the way to do it might just be to make a smaller svg underneath the one that I have, that starts at zero, and put the axes there, and remove them from the one I have right now.
Here's the full code: http://jsfiddle.net/v92q26L8/
The key part of your code is the bit where you attach the axes
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
At the moment you are positioning the axes bottom and left using transforms on the groups (svg:g nodes) which contain them.
To reposition the axes you simply need to adjust these transforms using your defined scales.
For your x axis
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
becomes
.attr("transform", "translate(0," + yRange(0) + ")")
for your y axis
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
becomes
.attr("transform", "translate(" + xRange(0) + ",0)")
Additionally, it may be sensible to change the names of your scales. The term 'range' has a very particular meaning in D3, I'd suggest xScale and yScale.
JS Fiddle
I am trying to develop a scatterplot using d3 but the domain for y-axis is confusing me. y-axis are gonna display patient names and x-axis display their appointment dates. x-axis are working fine, but y-axis are displaying only two patient names.
function graph() {
var num_patient = Object.keys(patientList).length;
var patient_names = Object.keys(patientList);
console.log(patient_names);
var x = d3.time.scale().range([0, width]);
var y = d3.scale.ordinal().range([height, 0]);
x.domain(d3.extent(data, function(d) {return parseDate(d.dates); }));
//y.domain(patient_names.map(function(d) { return d.name;}));
y.domain(patient_names);
console.log(y.domain());
var xAxis = d3.svg.axis()
.scale(x)
.ticks(d3.time.year, 1)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("#punchcard")
.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 + ")");
svg.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.value); });
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
}
console.log(patient_names) display the names correctly:
`["Andrew","Fred","Steve","John"]`
console.log(y.domain()) displays an extra undefined object:
["Andrew", "Fred","Steve" , "John", undefined]
But the y-axis only display Andrew at 0 and Fred at height h. How can I get to display all four names? I cannot hard code them as they are user input values. BTW: I am a beginner with d3 and js.
Thanks in advance!
With ordinal scales, you need to define the range points for the inputs explicitly (see the documentation). That is, you need to tell the scale explicitly which input value to map to which output. For example:
var y = d3.scale.ordinal()
.domain(["Andrew","Fred","Steve","John"])
.range([height, height * 2/3, height * 1/3, 0]);
You probably want to use the .rangePoints() method instead, which allows you to specify an interval that D3 automatically divides based on the number of values in the domain:
var y = d3.scale.ordinal()
.domain(["Andrew","Fred","Steve","John"])
.rangePoints([height, 0]);
Note that for .rangePoints() to work properly, you need to set the domain before the output range.