简体   繁体   中英

d3js bar graph with x+y axes: x axis value distribution

I'm trying to show a vertical bar chart with x and y axes. I get the bar chart with y axis, however I'm struggling with the x-axis.

The x-axis text labels are equally distributed with the width of the bars, however: there are markers/vertical lines on the x-axis with varying width, particularly the first and last sections, even though I've specified the scaleBand and the domain .

My code:

<script src="https://d3js.org/d3.v5.min.js"></script>
<svg class="v5chart" width="960" height="500"></svg>

<style>
/*Rectangle bar class styling*/
.bar {
  fill: #0080FF
}
.bar:hover {
  fill: #003366
}

/*Text class styling*/
.text {
  fill: white;
  font-family: sans-serif
}
</style>

<script>

////VERTICAL BAR CHART WITH SVG AND NAMES
// Create data array of values to visualize
var dataArray = [{ "Player": "John Doe", "Points": 23 }, { "Player": "Jane Doe", "Points": 13 }, { "Player": "Mary Jane", "Points": 21 }, { "Player": "Debasis Das", "Points": 14 }, { "Player": "Nishant", "Points": 37 }, { "Player": "Mark", "Points": 15 }, { "Player": "Andrew", "Points": 18 }, { "Player": "Simon", "Points": 34 }, { "Player": "Lisa", "Points": 30 }, { "Player": "Marga", "Points": 20 }];

// Create variable for the SVG
var canvas = d3.select(".v5chart1").append("g").attr("transform", "translate(20,30)");

var canvasWidth = 500;


var maxValue = d3.max(dataArray, function (d) { return d.Points; });
var canvasHeight = maxValue*10;

var heightScale = d3.scaleLinear()
    .domain([0, d3.max(dataArray, function (d) { return d.Points; })])
    .range([canvasHeight, 0]); //use max value (37) * 10

var y_axis = d3.axisLeft()
    .scale(heightScale);

var x = d3.scaleBand()
    .rangeRound([0, canvasWidth], .1);

x.domain(dataArray.map(function (d) { return d.Player; }));

var x_Axis = d3.axisBottom(x);

// Select, append to SVG, and add attributes to rectangles for bar chart
canvas.selectAll("rect")
    .data(dataArray)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("height", function (d, i) { return (d.Points * 10) })
    .attr("width", canvasWidth/dataArray.length)    
    .attr("x", function (d, i) { return (i * (canvasWidth / dataArray.length)) })
    .attr("y", function (d, i) { return canvasHeight - (d.Points * 10) });

// Select, append to SVG, and add attributes to text
canvas.selectAll("text")
    .data(dataArray)
    .enter().append("text")
    .text(function (d) { return d.Points })
    .attr("class", "text")
    .attr("x", function (d, i) { return (i * (canvasWidth / dataArray.length)) + (canvasWidth / dataArray.length)/2 })
    .attr("y", function (d, i) { return canvasHeight + 20 - (d.Points * 10) });



canvas.append("g")
    .attr("transform", "translate(0,0)")
    .call(y_axis);

canvas.append("g")
    .attr("transform", "translate(0," + canvasHeight + ")")
    .call(x_Axis)
    .selectAll("text")
    .attr("x",40)
    .attr("transform", function (d) {
        return "rotate(65)"
    });

</script>

I already checked here: https://www.d3-graph-gallery.com/graph/custom_axis.html

You should have read properly the scaleBand example on the link that you provided:

  • scaleBand provides a convenient bandwidth() method to provide you with the width for each bar
  • the idea od axis in d3js is that you don't need to do calculations yourself, so in your case you can just pass the player name to the x function and it will do the coordinate calculations for you.
  • same applies to the y calculations, but I leave this for you to figure out, it should not be hard at all.
  • one more small thing about scaleBand , you were using rangeRound() method, which I am not familiar with, but if you use range() method combined with padding() as it is in the example you linked, then by adjusting the padding value you can control the width of the bar, without affecting the x axis. The higher value, the thinner will be the bar and more space would be between the bars.

 ////VERTICAL BAR CHART WITH SVG AND NAMES // Create data array of values to visualize var dataArray = [{ "Player": "John Doe", "Points": 23 }, { "Player": "Jane Doe", "Points": 13 }, { "Player": "Mary Jane", "Points": 21 }, { "Player": "Debasis Das", "Points": 14 }, { "Player": "Nishant", "Points": 37 }, { "Player": "Mark", "Points": 15 }, { "Player": "Andrew", "Points": 18 }, { "Player": "Simon", "Points": 34 }, { "Player": "Lisa", "Points": 30 }, { "Player": "Marga", "Points": 20 }]; // Create variable for the SVG var canvas = d3.select(".v5chart").append("g").attr("transform", "translate(20,30)"); var canvasWidth = 500; var maxValue = d3.max(dataArray, function (d) { return d.Points; }); var heightScale = d3.scaleLinear() .domain([0, d3.max(dataArray, function (d) { return d.Points; })]) .range([maxValue * 10, 0]); //use max value (37) * 10 var y_axis = d3.axisLeft() .scale(heightScale); var x = d3.scaleBand() .range([0, canvasWidth]).padding([0.1]); x.domain(dataArray.map(function (d) { return d.Player; })); var x_Axis = d3.axisBottom(x); // Select, append to SVG, and add attributes to rectangles for bar chart canvas.selectAll("rect") .data(dataArray) .enter().append("rect") .attr("class", "bar") .attr("height", function (d, i) { return (d.Points * 10) }) .attr("width", x.bandwidth()) .attr("x", function (d, i) { return x(d.Player); }) .attr("y", function (d, i) { return 370 - (d.Points * 10) }); // Select, append to SVG, and add attributes to text canvas.selectAll("text") .data(dataArray) .enter().append("text") .text(function (d) { return d.Points }) .attr("class", "text") .attr("text-anchor", "middle") .attr("x", function (d, i) { return x(d.Player)+x.bandwidth()/2; }) .attr("y", function (d, i) { return 390 - (d.Points * 10) }); canvas.append("g") .attr("transform", "translate(0,0)") .call(y_axis); canvas.append("g") .attr("transform", "translate(0,370)") .call(x_Axis);
 .bar { fill: #0080FF } .bar:hover { fill: #003366 } /*Text class styling*/ .text { fill: white; font-family: sans-serif }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg class="v5chart" width="960" height="500"></svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM