here is an example of my code:
import React, {Component} from 'react';
import {scaleOrdinal, axisBottom, select} from 'd3';
export default class BarChart extends Component {
constructor(props) {
super(props)
this.renderSvg = this.renderSvg.bind(this);
}
componentDidMount() {
this.renderSvg();
}
renderSvg() {
const margin = 20;
const width = 400;
const height = 800;
const data = ["why", "aren't", "you", "working"]
.map((title) => ({title}));
// create scalar for x axis
const x = scaleOrdinal()
.domain(data.map(({title}) => title))
.range([0, width]);
const xAxis = axisBottom(x);
// create svg and append graph
const svg = select("svg")
.attr("width", width)
.attr("height", height + margin)
.append("g")
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
render() {
const {width, height, className} = this.props;
return <div className="body">
<svg className="svg" />
</div>
}
}
I have followed the example at this site: https://bl.ocks.org/mbostock/3259783 pretty closely as far as I can tell, but I can't get it to display the labels where they are expected to be at regular/even intervals. Any help would be appreciated, I'm new to using d3.
The problem is the conversion from d3v3 to d3v4/5.
The d3.scale.ordinal()
(v3) is used for a number of scale types and determined by the rangeX()
call you make.
In d3v5 d3.scaleOrdinal()
means an ordinal scale and maps an ordinal domain to an ordinal range. https://github.com/d3/d3-scale/#scaleOrdinal You have only set the range to a 2 value array. So each domain value is alternated on the 2 range values.
Here is a d3v5 example. I have adjusted the height to see something when run. Use the Developer Tools to see the alternating translation of the axis ticks.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="body">
<svg class="svg"/>
</div>
<script>
function renderSvg() {
const margin = 20;
const width = 400;
const height = 100;
const data = ["why", "aren't", "you", "working"]
.map((title) => ({title}));
// create scalar for x axis
const x = d3.scaleOrdinal()
.domain(data.map(({title}) => title))
.range([0, width]);
const xAxis = d3.axisBottom(x);
// create svg and append graph
const svg = d3.select("svg")
.attr("width", width)
.attr("height", height + margin)
.append("g");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
renderSvg();
</script>
</body>
</html>
The example code uses .rangePoints([0, width])
and that converts in d3v5 to d3.scalePoint()
. Now the ordinal domain is mapped to a continuous range.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div class="body">
<svg class="svg"/>
</div>
<script>
function renderSvg() {
const margin = 20;
const width = 400;
const height = 100;
const data = ["why", "aren't", "you", "working"]
.map((title) => ({title}));
// create scalar for x axis
const x = d3.scalePoint()
.domain(data.map(({title}) => title))
.range([0, width]);
const xAxis = d3.axisBottom(x);
// create svg and append graph
const svg = d3.select("svg")
.attr("width", width)
.attr("height", height + margin)
.append("g");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
}
renderSvg();
</script>
</body>
</html>