Skip to content

D3.js Axis — Creating and Customizing Chart Axes

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about D3.js Axis. We cover key concepts, practical examples, and best practices to help you master this topic.

D3.js axis component generates SVG elements for chart axes based on scales, providing tick marks, labels, and lines for data visualization.

What You'll Learn

By the end of this guide, you will create bottom, left, top, and right axes, customize tick count and format, rotate labels, add grid lines, and style axes with CSS and attributes.

Why Axes Matter

Charts without axes are meaningless. In Durga Antivirus Pro, the threat timeline chart uses D3 axes to show time on the X axis and threat count on the Y axis, giving analysts context for data spikes.

flowchart LR
    A[Scale] --> B[d3.axisBottom]
    A --> C[d3.axisLeft]
    B --> D[SVG Group]
    C --> D
    D --> E[Tick Marks]
    D --> F[Tick Labels]
    D --> G[Axis Line]

Creating a Basic Axis

var margin = { top: 20, right: 30, bottom: 40, left: 50 };
var width = 600 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;

var svg = d3.select('#chart')
    .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 + ')');

var xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([0, width]);

var xAxis = d3.axisBottom(xScale);

svg.append('g')
    .attr('transform', 'translate(0,' + height + ')')
    .call(xAxis);

Expected output: An SVG chart area with a bottom X axis showing ticks from 0 to 100 along the bottom edge.

Left and Right Axes

var yScale = d3.scaleLinear()
    .domain([0, 100])
    .range([height, 0]);

// Left axis (default)
svg.append('g')
    .call(d3.axisLeft(yScale));

// Right axis
svg.append('g')
    .attr('transform', 'translate(' + width + ', 0)')
    .call(d3.axisRight(yScale));

Customizing Ticks

d3.axisBottom(xScale)
    .ticks(5)
    .tickSize(10)
    .tickPadding(8)
    .tickFormat(function(d) {
        return d + '%';
    });

// Or use d3.format
d3.axisBottom(xScale)
    .tickFormat(d3.format('.0f'));

Rotating Tick Labels

svg.append('g')
    .attr('transform', 'translate(0,' + height + ')')
    .call(d3.axisBottom(xScale))
    .selectAll('text')
    .attr('transform', 'rotate(-45)')
    .style('text-anchor', 'end');

Adding Grid Lines

// Horizontal grid lines
svg.append('g')
    .call(d3.axisLeft(yScale)
        .tickSize(-width)
        .tickFormat('')
    )
    .selectAll('.tick line')
    .style('stroke', '#ddd');

Common Mistakes

1. Forgetting to Append a Group Before Calling Axis

.call(axis) requires a group element. Always append g before applying the axis.

2. Axis Not Visible Outside the SVG

If margin is not accounted for, the axis may render outside the SVG viewBox. Always use margins.

3. Scales With Invalid Domains

If domain is empty or has wrong values, axis renders no ticks or incorrect labels.

4. Not Positioning Bottom Axis Correctly

Bottom axis must be translated to y = height (bottom of the chart area).

5. Overlapping Tick Labels

Long labels with default orientation overlap. Rotate labels or increase bottom margin.

Practice Questions

Q1: What is the difference between axisBottom and axisLeft? A: axisBottom places ticks below the axis line. axisLeft places ticks to the left. Their orientation determines tick direction.

Q2: How do you set the number of ticks on an axis? A: Use .ticks(count) where count is the approximate number of ticks. D3 chooses optimal values based on the scale domain.

Q3: Why must you append a group before .call(axis)? A: The axis generator creates path, line, and text elements inside a group. Without a group, there is no container.

Q4: How do you format tick labels as currency? A: .tickFormat(d3.format('$,.0f')) formats numbers as dollar amounts with commas.

Q5: How do you add grid lines using axis? A: Set .tickSize(-width) on the axis to extend ticks across the chart area, then style them.

Challenge: Build a bar chart with formatted Y axis (currency) and rotated X axis labels (category names). Add horizontal grid lines. Make it look like a financial dashboard.

FAQ

Can I have multiple axes on one chart?

Yes. Append multiple group elements and call different axis generators on each.

How do I update axes when data changes?

Re-call .call(axis) on the existing group after updating the scale domain.

What is the default tick format?

D3 automatically selects a human-readable format based on the scale domain and tick count.

How do I remove tick lines but keep labels?

Set .tickSize(0) and .tickSizeOuter(0) to hide tick marks.

Can I customize the axis line color?

Yes. Select .domain path after calling axis and apply stroke: d3.select('.domain').style('stroke', '#333').

Try It Yourself

Build a complete chart with styled axes, grid lines, and formatted labels.

<!DOCTYPE html>
<html>
<head>
    <title>D3 Axis Demo</title>
    <style>
        body { font-family: sans-serif; padding: 20px; background: #f5f5f5; }
        #chart { background: white; padding: 10px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
        .grid line { stroke: #eee; stroke-dasharray: 4; }
        .axis text { font-size: 12px; fill: #666; }
        .axis .domain { stroke: #333; }
    </style>
</head>
<body>
<svg id="chart" width="600" height="400"></svg>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
var margin = { top: 20, right: 30, bottom: 50, left: 60 };
var width = 600 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom;

var svg = d3.select('#chart')
    .append('g')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

var xScale = d3.scaleLinear().domain([0, 100]).range([0, width]);
var yScale = d3.scaleLinear().domain([0, 1000]).range([height, 0]);

// Grid lines
svg.append('g')
    .attr('class', 'grid')
    .call(d3.axisLeft(yScale).tickSize(-width).tickFormat(''));

svg.append('g')
    .attr('class', 'grid')
    .attr('transform', 'translate(0,' + height + ')')
    .call(d3.axisBottom(xScale).tickSize(-height).tickFormat(''));

// Axes
svg.append('g')
    .attr('class', 'axis')
    .attr('transform', 'translate(0,' + height + ')')
    .call(d3.axisBottom(xScale).ticks(10).tickFormat(function(d) { return d + '%'; }));

svg.append('g')
    .attr('class', 'axis')
    .call(d3.axisLeft(yScale).ticks(8).tickFormat(d3.format('$,.0f')));

// Labels
svg.append('text').attr('x', width/2).attr('y', height + 40)
    .attr('text-anchor', 'middle').style('fill', '#666').text('Completion %');
svg.append('text').attr('x', -height/2).attr('y', -45)
    .attr('text-anchor', 'middle').attr('transform', 'rotate(-90)')
    .style('fill', '#666').text('Revenue ($)');
</script>
</body>
</html>

What's Next

Build network visualizations with force layout.

Force Layout — Force-directed graph layout. Hierarchies — Hierarchical data visualization.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro