D3.js V4 : How to create X axis with time and %H:%M:%S format - d3.js

I am trying to create a chart with X axis that shows timely progress of a trade with %H:%M:%S format.
I have tried following code but it shows years only. The seconds are very important to show on the x axis. I know timeParse needs to be used but I am not sure how to leverage it. I have searched a lot online but no examples.
// Add X axis
var parseDate=d3.timeParse("%H:%M:%S")
var x = d3.scaleTime()
.domain([new Date(0,0,0), new Date (12,59,59)])
.range([ 0, width ]);

You would need the following:
The desired scale.
var x = d3.scaleTime()
.domain([new Date(1554236172000), new Date(1554754572000)])
.range([0, width]);
The axis with the correct format and the number of desired ticks, you may want to use .ticks(d3.timeMinute.every(desiredMinutesToHandle)); for a better display of your data.
var xAxis = d3.axisBottom(x)
.tickFormat(d3.timeFormat("%H:%M:%S"))
.ticks(50);
Finally append your axis to your svg with certain transformations to have a nice look
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", -5)
.attr("x", 30)
.attr("transform", "rotate(90)")
Plunkr with working code

Related

How to include additional lines between x-axis values using d3.js?

I created x axis with the values ​​and the labels and applied a style in grid lines. The code is below:
let xScale = d3.scalePoint().domain(axisXValues).range([0, width]);
let xAxisGenerator = axisXLabels.length > 0
? d3.axisBottom(xScale).ticks(axisXValues.length).tickFormat((d,i) => axisXLabels[i])
: d3.axisBottom(xScale).ticks(axisXValues.length);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxisGenerator.tickSize(-height));
I would like to include more ticks between (green) the values ​​and apply a different style as in the example below:
Does anyone have an idea?
Thanks!
I would add a new linear scale with the same range and domain in the original point scale. (Keeping the original point scale and its rendered axis, of course)
Then calculate the values in between and plot the axis using axisBottom.tickValues()
Color of the tick line can be changed by accessing .tick line and applying the stroke attribute.
Do note that this would only work if the point scale's domain is equally spaced, i.e. linear.
Adding the following code to yours should work. Attaching a working codepen too.
const xScaleInBetween = d3.scaleLinear()
.range(xScale.range())
.domain(d3.extent(axisXValues));
let xTicks = xScale.domain();
let xTicksInBetween = Array.from({length: xTicks.length - 1},
(_, j) => ((xTicks[j] + xTicks[j+1]) /2));
chart.append("g")
.attr("class", "x-axis-between")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScaleInBetween)
.tickValues(xTicksInBetween)
.tickSize(-height))
.call(g => g.selectAll('.tick line').attr('stroke', 'green'))
.call(g => g.selectAll('.tick text').remove())

d3 bar chart scale reversed on y-axis, doesn't look like the classic problem, why is it acting odd?

Drawing a histogram in d3 (vertical bar chart), works fine except the y-axis scale is reversed. Here is the code that (almost) works:
let maxFrequency = d3.max(histData, d=> d.length);
let yScale = d3.scaleLinear()
.range([0,config.height - config.margin.top - config.margin.bottom])
.domain([0,maxFrequency]); //<-- this is wrong, right? It should be [maxFrequency,0]
let xScale = d3.scaleBand()
.range([0, (config.width - config.margin.left - config.margin.right)])
.domain(histData.map(d => d.Name))
.padding(0.2);
//Draw the histogram bars
let bars = config.svgContainer.selectAll("rect")
.data(histData);
bars.enter()
.append("rect")
.attr("width", xScale.bandwidth())
.attr("height", (d)=> yScale(d.length))
.attr("x", (d) => xScale(d.Name) + config.margin.left)
.attr("y", (d)=> config.height - config.margin.bottom - yScale(d.length))
.attr("fill", "red");//"#2a5599");
let axisX = d3.axisBottom(xScale)
config.svgContainer.append("g")
.style("transform", `translate(${config.margin.left}px,${config.height -
config.margin.bottom}px)`)
.call(axisX)
let axisY = d3.axisLeft(yScale)
config.svgContainer.append("g")
.style('transform',`translate(${config.margin.left}px,${config.margin.top}px)`)
.call(axisY);
This code produces this graph.
enter image description here
Normally you need to reverse the order of the domain attribute for the y-axis. Here is the graph when I use the ".domain([maxFrequency,0])" code with no other changes.
enter image description here
You can see that the y-axis now is correct but the bars look wonky. On closer inspection you can see that the data (1,9,40,80) is still being represented, but the bars are a now reversed. The bars are now height 79 (80-1), 71 (80-9), 40 (80-40), and 0 (80-80).
I hope this is something simple I'm not seeing. I can't find any posted solutions for something that sounds like this.

D3JS: unable to set only 5 ticks in x Axis

I've been unable to set only 5 ticks on my x Axis, by default it set 10 ticks, multiples of 5, I tried to use ´.ticks(5)´ but it's not working for me. If if visualize the chart on mobile, 10 ticks becomes almost unreadable. But as I mentioned ´.ticks(5)´ it's not working
this is the snippet which draws the x axis:
var xAxis = svg.append("g")
.style("font-size", textSetter())
.attr("class", "xAxis", "axis")
.attr("transform", "translate(" + 0 + "," + heightTwo + ")")
.call(d3.axisBottom(xScale).ticks(5)
.tickPadding(5).tickFormat(d => d + "%"))
How can I solve this? Thanks
You could set all the text in the axis to a particular class and then hide the ticks based on the number for example.
//Create the xAxis and assign x-axisticks class to the tick text
var xAxis = svg.append("g")
.style("font-size", textSetter())
.attr("class", "xAxis", "axis")
.attr("transform", "translate(" + 0 + "," + heightTwo + ")")
.call(d3.axisBottom(xScale)
.selectAll('text')
.attr('class', 'x-axisticks');
//remove the ticks which based on the multiples
var xticks = d3.selectAll('.x-axisticks');
xticks.attr('class', function (d, i) {
i = i + 1;
if (i % 5 !== 0) d3.select(this).remove();
});
Hope this helps. A more specific use-case answer would probably require some more code to be posted from your end so that I can tailor an answer, but this should work.

How to control the spacings of the x Axis label positions in a stacked bar chart?

I took bits from this and this solutions.
I then do the following to show my x axis label ticks:
var x = d3.scaleBand().range([0, width]).padding(.1).domain(d3.range(1993, 2002));
svg.append("g")
.attr('class', 'axis')
.attr('transform', 'translate(-10,' + (height - 20) + ')')
.call(d3.axisBottom(x));
However, I then get the following output where x axis ticks are shifted further to the right each time like if their gap doesn't match the bar's.
The following snippet shows how the rects and axis's ticks line up correctly.
Need to be careful on how d3.range generates arrays, in that d3.range(1993, 2002) will create [1993, 1994, ... , 2001].
Also, I'm not sure why the g element that contains the X axis was shifted left, so that is set to 0
var width = 800
var height = 100
//this makes an array 1993 to 2001. Is that what you want?
var data = d3.range(1993, 2002)
var x = d3.scaleBand()
.range([0, width])
.padding(.1)
.domain(data);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
svg.append("g")
.attr('class', 'axis')
//.attr('transform', 'translate(-10,' + (height - 20) + ')')
.attr('transform', 'translate(0,' + (height - 20) + ')')
.call(d3.axisBottom(x));
svg.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', d => x(d))
.attr('y', 0)
.attr('width', x.bandwidth())
.attr('height', x.bandwidth())
<script src="https://d3js.org/d3.v4.min.js"></script>
I don't have enough S.O to 'comment' but I think it may be helpful to use the xScale:
-in the xAxis (something like...
xAxis = d3.axisBottom()
.scale(xScale)
)
-in the x position of each bar ( something like...
'x', d => xScale(year)
)
-in the width of each bar, seems like you might need to use something like...
('width', x.bandwidth())
looks like the xScale in the (1)axis and (2)bars are not working as expected together.
Maybe this helps?!

d3 axis tick alignment

I have a d3 bar chart with, and the axis tick marks are centered below the bars (as I would expect). In this case, I would actually like to left align the axis ticks and have the ticks under the left edge of the bar. Is that possible?
EDIT: Javascript for constructing the axis
// note width is just the width of the chart
var xScale = d3.scale.ordinal().rangeRoundBands([0,width], .1);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
here is an example of left aligning the ticks.
http://bl.ocks.org/mbostock/6186172
the idea is that after you create the ticks you collect them and aligne them:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 6)
.attr("x", 6)
.style("text-anchor", "start");
Why not just create a new scale?
var padding = .1;
var axisScale = d3.scale.linear()
.domain([0, n])
.range([0 + padding, WIDTH + padding]);
Where n is the number of bars in your histogram.
I think that this should be adjusted when you add the axis to your graph.
Try (assuming your graph is called svg):
var bandSize = xScale.rangeBand();
svg.append("svg:g")
.attr("transform", "translate(-" + bandSize + "," + h + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "start")
.attr("transform", "translate(" + bandSize + ", 0)");
In my experiments, this shifts the ticks to the start of each band, and retains the text centered under each band.

Resources