I'm using d3js v5, with an Ordinal scale for my X axis on a line chart.
this.x = scaleOrdinal()
.domain(axisXDataTruncated.labels)
.range(axisXDataTruncated.range);
When I draw my x axis using this:
this.root
.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(0, ${this.height})`)
.call(
axisBottom(this.x).tickFormat((data: string | number) =>
formatter(
this.graphDataMerged.lineChartOptions.axis.x.format,
data,
this.graphDataMerged.lineChartOptions.axis.x.currency
)
)
);
I'm using string labels (['Week 1'. 'Week 2',... 'Week 26'] as labels.
When I have a long number of labels, the x axis, discards the last labels and crops to a certain value. For example, with 26 values. Tha last label shows as 25, which is shown at the very end of the x axis.
Because the dots and lines of my chart includes the value at position 26, the axis and the dots don't match.
If I expand the browser's width, the last value of the x axis magically appears.
What could I be doing wrong? Is it a bug in v5?
Related
in dc.js line chart ,when all y value is zero corresponding to the x axis value line is not drawing. it just displying xaxis and y-axis without ticks.Is it possible to draw line on the x axis with corresponding y value as 0 with x-axis name(field name)?
I have a plunker here - https://plnkr.co/edit/3gikXOR8EydIcA3wcBMb?p=preview
The numbers on the y axis are in the centre of the grid line.
I can change the padding with
.tickPadding(5)
Can I change the vertical position of the numbers so they bottom of the number is on the same level as the grid line.
add a dy attribute to the text items
chart.append("g")
.classed('y-axis', true)
.call(y_axis)
.selectAll('text')
.attr('dy', '-0.3em');
I have a stackblitz here - https://stackblitz.com/edit/d3-start-above-zero?embed=1&file=index.js&hideNavigation=1
It's a super simple bar chart with one bar
The y axis shows values from 0-200
The values for the bar are start at 50 and finish at 150 so I wanted to draw the bars at these values so the bar would be somewhere in the center of the graph.
I sort of have the height but can't fix the y position.
You can make the range going from 0 to height...
scale.range([0, height])
...or from height to 0...
scale.range([height, 0])
...but this doesn't change the fact that, in an SVG, the coordinates system of the y axis goes from the top to the bottom of the page. Therefore, the y attribute has to be always smaller than the height for a rectangle.
That being said, you have to use finish for the y attribute:
.attr("y", function (d, i) {
return y(d.finish);
})
.attr("height", function(d,i){
return y(d.start) - y(d.finish);
});
Here is the updated code: https://stackblitz.com/edit/d3-start-above-zero-qnk7bl?file=index.js
I'm currently working on a quite basic graph using 2 ordinal axes. X axis shows 4 categories, Y axis shows 3. For some reason, the plotted circles don't align with the plotted axes.
An example can be seen at http://jsfiddle.net/SrdY6/. Problem seems to be translation-related, but the only translation in there is applied to the large containing <g> element:
var lunchgraph = svg.append("g")
.attr("class", "lunchgraph")
.attr("transform", "translate(" + lunchmargin.left + "," + lunchmargin.top + ")");
I've been looking at this for some time now, but can't spot where things go wrong... Anyone with more insight?
Nothing like putting a question out there and risking public shame, only to find out the answer within minutes after posting.
For ordinal axes configured with rangeBands or rangeRoundBands, the scale function returns the lower value of the given input. To have the plot align with the exact categorical labels, you need to add half of the rangeBand to the calculated coordinate.
So: no problem with the translations or anything, but with the computation of cx and cy coordinates for placing the circles in the graph.
Correct code:
.attr("cx", function(d) { return x(d.label) + x.rangeBand()/2 ;} )
.attr("cy", function(d) { return y(d.sqid) + y.rangeBand()/2 ; } )
I need to create a d3 bar chart that can have negative values. Ideally the axis zero position should be calculated based on the extent of the data, but I'd settle for a solution that assumes symmetric positive and negative extent, i.e. that it would be always in the middle of the chart.
Here's an example of what I'd like to achieve.
OK, let's say you have an array of numbers as your dataset, and this includes some positive and negative values:
var data = [-15, -20, -22, -18, 2, 6, -26, -18];
You'll want two scales to construct a bar chart. You need one quantitative scale (typically a linear scale) to compute the bar positions along the x-axis, and a second ordinal scale to compute the bar positions along the y-axis.
For the quantitative scale, you typically need to compute the domain of your data, which is based on the minimum and maximum value. An easy way to do that is via d3.extent:
var x = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width]);
You might also want to nice the scale to round the extent slightly. As another example, sometimes you want the zero-value to be centered in the middle of the canvas, in which case you'll want to take the greater of the minimum and maximum value:
var x0 = Math.max(-d3.min(data), d3.max(data));
var x = d3.scale.linear()
.domain([-x0, x0])
.range([0, width])
.nice();
Alternatively, you can hard-code whatever domain you want.
var x = d3.scale.linear()
.domain([-30, 30])
.range([0, width]);
For the y-axis, you'll want to use rangeRoundBands to divide the vertical space into bands for each bar. This also lets you specify the amount of padding between bars. Often an ordinal scale is used with some identifying data—such as a name or a unique id. However, you can also use ordinal scales in conjunction with the data's index:
var y = d3.scale.ordinal()
.domain(d3.range(data.length))
.rangeRoundBands([0, height], .2);
Now that you've got your two scales, you can create the rect elements to display the bars. The one tricky part is that in SVG, rects are positioned (the x and y attributes) based on their top-left corner. So we need to use the x- and y-scales to compute the position of the top-left corner, and that depends on whether the associated value is positive or negative: if the value is positive, then the data value determines the right edge of the bar, while if it's negative, it determines the left edge of the bar. Hence the conditionals here:
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d, i) { return x(Math.min(0, d)); })
.attr("y", function(d, i) { return y(i); })
.attr("width", function(d, i) { return Math.abs(x(d) - x(0)); })
.attr("height", y.rangeBand());
Lastly, you can add an axis to display tick marks on top. You might also compute a fill style (or even a gradient) to alter the differentiate the appearance of positive and negative values. Putting it all together:
Bar Chart with Negative Values