D3 - move y-axis labels above line - d3.js

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

Related

In d3 selection method chaining, how can I reference the values of the selected element?

I have a simple horizontal bar chart, and I'm trying to place an image to the left of each horizontal bar to serve as a label for the bar.
At this point in the script, the bars have been created and are displayed.
I've taken a code sample for adding the labels to the right of the bars (which are included in the image) and tried to update it to place an image to the left.
bars.append("image")
.attr("class", "bar_image")
//y position of the image is halfway down the bar
.attr("y", function(d){
return y(d.Candidate) + y.rangeBand() / 2 + 4;
})
//x position to left of bar
.attr("x", function(d) {
return -10;
})
.attr('xlink:href', function(d){
return "/static/images/yang.png";
})
My understanding here is that I'm selecting each of the 'bar' elements and appending an image (which is the same image for all right now while I work on placement).
I'm setting the y attribute of the image element to midrange of each y range. This is how the label on the right has its y attr set. x, for now I'm just setting to left of the bar. Then I set the actual href to the image.
My problem now has to do with SIZING the image, and I'd like to be able to set its height/width dynamically based on the height of the 'bar' elements. These heights are obviously dependent on how many bars there are (this graph should scale up or down to any number of people)
Obviously the positioning isn't perfect, but for now I'd just be happy being able to resize the height/width attributes of the image based on the height of the bars in the chart.
Is there a way to reference in the selection and method chaining the attributes of the elements being selected?
Thanks for any help.
Not exactly what I was looking for, but I can set the
attr("height", x)
of the image element using the same function that sets the height attribute of the bars
.attr("height", y.rangeBand())

DC chart heatmap columns text rotation doesn't work [duplicate]

I am new to d3 and svg coding and am looking for a way to rotate text on the xAxis of a chart. My problem is that typically the xAxis titles are longer than the bars in the bar chart are wide. So I'm looking to rotate the text to run vertically (rather than horizontally) beneath the xAxis.
I've tried adding the transform attribute:
.attr("transform", "rotate(180)")
But when I do that, the text disappears altogether. I've tried increasing the height of the svg canvas, but still was unable to view the text.
Any thoughts on what I'm doing wrong would be great. Do I need to also adjust the x and y positions? And, if so, by how much (hard to troubleshoot when I can see it in Firebug).
If you set a transform of rotate(180), it rotates the element relative to the origin, not relative to the text anchor. So, if your text elements also have an x and y attribute set to position them, it’s quite likely that you’ve rotated the text off-screen. For example, if you tried,
<text x="200" y="100" transform="rotate(180)">Hello!</text>
the text anchor would be at ⟨-200,100⟩. If you want the text anchor to stay at ⟨200,100⟩, then you can use the transform to position the text before rotating it, thereby changing the origin.
<text transform="translate(200,100)rotate(180)">Hello!</text>
Another option is to use the optional cx and cy arguments to SVG’s rotate transform, so that you can specify the origin of rotation. This ends up being a bit redundant, but for completeness, it looks like this:
<text x="200" y="100" transform="rotate(180,200,100)">Hello World!</text>
Shamelessly plucked from elsewhere, all credit to author.
margin included only to show the bottom margin should be increased.
var margin = {top: 30, right: 40, bottom: 50, left: 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", ".15em")
.attr("transform", "rotate(-65)");
One problem with this rotating D3 axis labels is that you have to re-apply this logic each time you render the axis. This is because you do not have access to the enter-update-exit selections that the axis uses to render the ticks and labels.
d3fc is a component library that has a decorate pattern allowing you to gain access to the underling data join used by components.
It has a drop-in replacement for the D3 axis, where axis label rotation is performed as follows:
var axis = fc.axisBottom()
.scale(scaleBand)
.decorate(function(s) {
s.enter()
.select('text')
.style('text-anchor', 'start')
.attr('transform', 'rotate(45 -10 10)');
});
Notice that the rotation is only applied on the enter selection.
You can see some other possible uses for this pattern on the axis documentation page.

Bar chart that doesn't start at zero

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

D3js X axis rounds down ticks for some browser widths

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?

Separately controlling positioning of y-axis line and y-axis labels

I am creating a bar chart using d3. The bar chart accepts negative values. The chart I am creating is based on this chart here, and mostly have similar setup.
The change I like to make is shift the text labels of the y-axis to the absolute left of the chart, but keep the y-axis line at its original spot.
From the above link, the following are the lines of code to render the y-axis (they are at the bottom of the page, almost the last thing of the code)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + x(0) + ",0)")
.call(yAxis);
Now, if I adjust the above translate line to the following
.attr("transform", "translate(0,0)")
then BOTH the axis line AND the labels will be left aligned. I would like to keep the axis line at its position but move all the labels to the left.
How can I do that?
PS. A solution I thought about is to create second y-axis. The first y-axis is hidden with the labels shown, and is displayed to the left. The second y-axis is shown, but the labels are hidden, and is at the center. However, I do not like this solution, I do not think it is very clean.
Thanks.
Just increase the tick padding:
.tickPadding(width/2 - margin.left);

Resources