D3 js chart inverted issue - javascript

My Fiddle
I am studying d3js,i got this implementation of a bar chart with some data.
I need the chart to be inverted.
I tried adding:
var y = d3.scale.linear()
.domain([0, d3.max(jsonData.year)])
.range([500, 0]);
and calling that on the bars:
.attr("y", function(d) {
return y(d);
});
Didnt work..
How do i get around this? I think am missing something..
This is what i want along with the axis:

how's this? http://jsfiddle.net/jTs9A/3/
the problem was your transform, translate coordinates on appending the x and y axes at the bottom.
canvas.append("g")
.call(xAxis)
.attr("transform", "translate(0,0)");
canvas.append("g")
.call(yAxis)
.attr("transform", "translate(-10,0)");
you had (0,250) and (-10,-50) before
EDIT:
http://jsfiddle.net/jTs9A/4/
you needed to add this:
.attr("y", function(d) {
return (h- d.year*10); //Height minus data value
})
where h is the height of your graph area. check the tut in the comments (not enough rep yet)

Related

Best way to show Y axis values in Millions of £

I have data in this format:
[{"EndDate":"2012","Value":26473660},
{"EndDate":"2013","Value":54296732},
{"EndDate":"2014","Value":64063400},
{"EndDate":"2015","Value":81812464},
{"EndDate":"2016","Value":86899274}]
And I have managed to successfully render a bar chart. However, The Y-Axis Values are showing just "000" up and down the scale.
Here is the relevant code parts for the y axis.
var y = d3.scale.linear()
.range([height, 0]);
....
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
....
y.domain([0, d3.max(dataset, function(d) { return d.Value; })]);
....
svg.append("g") //Y AXIS ENTER
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value in £");
I've looked into d3.ticks/d3.tickFormat functions on bostocks website but not following what is actually going on. Essentially, I'd like to display a short hand way for displaying Millions: 0M, 10M, 20M, 30M.. for a simple solution.
Apologies if a duplicate. It probably is but can't seem to find the solution that applies to my style of dataset :/
Thanks in Advance.
Add .tickFormat('.0s') to your yAxis definition.
See:
Format Y axis values, original figures in millions, only want to show first three digits
D3: Formatting tick value. To show B (Billion) instead of G (Giga)

In D3 v4, how do I keep the width of a bar centered around a tick mark?

I am using D3 v4 (most, if not all, of the examples out there are for v3). Back in v3, they had something called rangeBand() which would be able to dynamically position everything neatly on the x-axis for me.
Now, in v4, I am wondering how to do that.
I have a bar chart:
var barEnter = vis.selectAll("g")
.data(rawdata)
.enter()
.append('g')
.append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.key); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", canvas_width / rawdata.length);
It is the width of this bar this is messing me up. If I set it to canvas_width / rawdata.length, it nicely positions the bars centered around each tick on the x-axis. The problem is that all the bars are pressed together and there is no padding in between.
So, naturally, I tried to do x.paddingInner(.5) which does add some padding but now the bars are not centered around the tick marks. Doing anything with x.paddingOuter() messes things up even more.
After searching around, I found that rangeBand() is what I want but that's only for v3. In the v4 docs, there is nothing that quite looks like it. Is it rangeRound()? Is it align()? I'm not sure. If anyone can point me in the right direction, it'd be greatly appreciated.
Without seeing your code for the axis, I suppose you're using scaleOrdinal(). If that's the case, you can change for scaleBand(), in which it's very easy to center the bar around the tick.
All you need is:
band.paddingInner([padding]): Sets the inner padding of the bars
band.bandwidth(): Gives you the bandwidth of each bar.
Then, you set the x position using the corresponding variable in your data and the width using bandwidth().
This is a small snippet to show you how it works:
var w = 300, h = 100, padding = 20;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var data = [{name: "foo", value:50},
{name: "bar", value:80},
{name: "baz", value: 20}];
var xScale = d3.scaleBand()
.range([0,w])
.domain(data.map(function(d){ return d.name}))
.paddingInner(0.2)
.paddingOuter(0.2);
var xAxis = d3.axisBottom(xScale);
var bars = svg.selectAll(".bars")
.data(data)
.enter()
.append("rect");
bars.attr("x", function(d){ return xScale(d.name)})
.attr("width", xScale.bandwidth())
.attr("y", function(d){ return (h - padding) - d.value})
.attr("height", function(d){ return d.value})
.attr("fill", "teal");
var gX = svg.append("g")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>

D3 show values as label on right axis

I am doing a dot plot in D3 and I want to add the values along a right Y axis. I have done this before in many charts, adding labels is straightforward, but for some reason this particular chart is giving a lot of problems.
I cant get the values of the dots to show on the right axis.
jsfiddle:
The chart appears on click.
The relevant code for the value labels attached to the right axis:
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + (width + 10) + " ,0)")
.call(yAxis1)
.selectAll('text')
.text(function(d){ return xScale(d.value); });
With an ordinal axis you are binding your domain values to the axis ticks. So, the scale domain should be:
var yScale1 = d3.scale.ordinal()
.domain(data.map(function(d) { return d.value; })) //<-- use '.value'
.rangeRoundPoints([0, height]);
Then your y-axis call just becomes:
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + (width + 10) + " ,0)")
.call(yAxis1);
Updated fiddle.

d3.js right align nested bar chart

I'm working with this d3.js example and am looking to change the charts entire orientation to go instead from right to left.
I was able to reverse the x-axis scale:
var x = d3.scale.linear().range([width, 0]);
and the placement of the y axis:
svg.append("g").attr("class", "y axis")
.attr("transform", "translate("+width+", 0)")
.append("line").attr("y1", "100%");
I believe I have to set the transform on each bar to the chart width - the bar width however applying ANY transform to the containing g has no effect.
function bar(d) {
var bar = svg.insert("g", ".y.axis")
.attr("class", "enter")
.attr("transform", "translate(0,5)")
.selectAll("g")
.data(d.children)
.enter().append("g");
//DOESNT WORK
bar.attr("transform", function(n){ return "translate("+ (width - x(n.value)) +", 0)"; })
.style("cursor", function(d) { return !d.children ? null : "pointer"; })
.on("click", down);
bar.append("text")....
bar.append("rect")....
return bar;
}
No transform is set on bar even if I just do a test with a fixed value, the result is translate(0,0) in the resulting page.
Why doesnt the transform not get applied here and is this even the correct way to make the bars right align? I also need the text to be on the right side of the bar instead of on the left and it seems that changing the order of appending makes no difference in this regard.
The problem with this particular example is that the code is a bit confusing -- the positions of the rect elements are set in various non-obvious places. In particular, the transform you are setting is overwritten immediately by other code.
I've modified the example to do what you want here. The key points are that I'm moving the g element containing all bars to the right
var bar = svg.insert("g", ".y.axis")
.attr("class", "enter")
.attr("transform", "translate("+width+",5)")
.selectAll("g")
// etc
and setting the x position of the rect elements to be their negative width
bar.append("rect")
.attr("x", function(d) { return width-x(d.value); })
.attr("width", function(d) { return x(d.value); })
.attr("height", barHeight);
The x position needs to be set in a few other places in the code in this way -- there're almost certainly more elegant ways to do this.

d3 axis labeling

How do I add text labels to axes in d3?
For instance, I have a simple line graph with an x and y axis.
On my x-axis, I have ticks from 1 to 10. I want the word "days" to appear underneath it so people know the x axis is counting days.
Similarly, on the y-axis, I have the numbers 1-10 as ticks, and I want the words "sandwiches eaten" to appear sideways.
Is there a simple way to do this?
Axis labels aren't built-in to D3's axis component, but you can add labels yourself simply by adding an SVG text element. A good example of this is my recreation of Gapminder’s animated bubble chart, The Wealth & Health of Nations. The x-axis label looks like this:
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width)
.attr("y", height - 6)
.text("income per capita, inflation-adjusted (dollars)");
And the y-axis label like this:
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", 6)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("life expectancy (years)");
You can also use a stylesheet to style these labels as you like, either together (.label) or individually (.x.label, .y.label).
In the new D3js version (version 3 onwards), when you create a chart axis via d3.svg.axis() function you have access to two methods called tickValues and tickFormat which are built-in inside the function so that you can specifies which values you need the ticks for and in what format you want the text to appear:
var formatAxis = d3.format(" 0");
var axis = d3.svg.axis()
.scale(xScale)
.tickFormat(formatAxis)
.ticks(3)
.tickValues([100, 200, 300]) //specify an array here for values
.orient("bottom");
If you want the y-axis label in the middle of the y-axis like I did:
Rotate text 90 degrees with text-anchor middle
Translate the text by its midpoint
x position: to prevent overlap of y-axis tick labels (-50)
y position: to match the midpoint of the y-axis (chartHeight / 2)
Code sample:
var axisLabelX = -50;
var axisLabelY = chartHeight / 2;
chartArea
.append('g')
.attr('transform', 'translate(' + axisLabelX + ', ' + axisLabelY + ')')
.append('text')
.attr('text-anchor', 'middle')
.attr('transform', 'rotate(-90)')
.text('Y Axis Label')
;
This prevents rotating the whole coordinate system as mentioned by lubar above.
If you work in d3.v4, as suggested, you can use this instance offering everything you need.
You might just want to replace the X-axis data by your "days" but remember to parse string values correctly and not apply concatenate.
parseTime might as well do the trick for days scaling with a date format ?
d3.json("data.json", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.year = parseTime(d.year);
d.value = +d.value;
});
x.domain(d3.extent(data, function(d) { return d.year; }));
y.domain([d3.min(data, function(d) { return d.value; }) / 1.005, d3.max(data, function(d) { return d.value; }) * 1.005]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(6).tickFormat(function(d) { return parseInt(d / 1000) + "k"; }))
.append("text")
.attr("class", "axis-title")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.attr("fill", "#5D6971")
.text("Population)");
fiddle with global css / js
D3 provides a pretty low-level set of components that you can use to assemble charts. You are given the building blocks, an axis component, data join, selection and SVG. It's your job to put them together to form a chart!
If you want a conventional chart, i.e. a pair of axes, axis labels, a chart title and a plot area, why not have a look at d3fc? it is an open source set of more high-level D3 components. It includes a cartesian chart component that might be what you need:
var chart = fc.chartSvgCartesian(
d3.scaleLinear(),
d3.scaleLinear()
)
.xLabel('Value')
.yLabel('Sine / Cosine')
.chartLabel('Sine and Cosine')
.yDomain(yExtent(data))
.xDomain(xExtent(data))
.plotArea(multi);
// render
d3.select('#sine')
.datum(data)
.call(chart);
You can see a more complete example here: https://d3fc.io/examples/simple/index.html
chart.xAxis.axisLabel('Label here');
or
xAxis: {
axisLabel: 'Label here'
},

Categories