最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Creating a Text Labeled x-Axis with an Ordinal Scale in D3.js - Stack Overflow

programmeradmin0浏览0评论

I'm building a bar chart in d3.js with an ordinal x-axis whose ticks should label the chart with text. Could anyone explain how the ordinal scale "maps" x ticks to the corresponding bar positions? Specifically, if I want to designate the x tick labels with an array of text values to the corresponding bars in a bar chart.

Currently I'm setting the domain as the following:

    var labels = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"];
    var xScale = d3.scale.ordinal()
                .domain(labels)

However, values of 1-19 are showing after the text labels.

As seen in this fiddle:

/

Associated Fiddle Source Code:

//Width and height
            var margin = {top: 20, right: 20, bottom: 30, left: 40};           
            var width = 600 - margin.left - margin.right;
            var height= 500-margin.top -margin.bottom;
            var w = width;
            var h = height;


            var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                            11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

            var labels = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"];
            var xScale = d3.scale.ordinal()
            .domain(labels)
                            .rangeRoundBands([margin.left, width], 0.05);
            var xAxis = d3.svg.axis().scale(xScale).orient("bottom");


            var yScale = d3.scale.linear()
                            .domain([0, d3.max(dataset)])
                            .range([h,0]);


            //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            //Create bars
            svg.selectAll("rect")
               .data(dataset)
               .enter()
               .append("rect")
               .attr("x", function(d, i) {
                    return xScale(i);
               })
               .attr("y", function(d) {
                    return yScale(d);
               })
               .attr("width", xScale.rangeBand())
               .attr("height", function(d) {
                    return h - yScale(d);
               })
               .attr("fill", function(d) {
                    return "rgb(0, 0, 0)";
               });

            svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + 0 + ")")
      .call(xAxis);

            //Create labels
            svg.selectAll("text")
               .data(dataset)
               .enter()
               .append("text")
               .text(function(d) {
                    return d;
               })
               .attr("x", function(d, i) {
                    return xScale(i) + xScale.rangeBand() / 2;
               })
               .attr("y", function(d) {
                    return h - yScale(d) + 14;
               });

I'm building a bar chart in d3.js with an ordinal x-axis whose ticks should label the chart with text. Could anyone explain how the ordinal scale "maps" x ticks to the corresponding bar positions? Specifically, if I want to designate the x tick labels with an array of text values to the corresponding bars in a bar chart.

Currently I'm setting the domain as the following:

    var labels = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"];
    var xScale = d3.scale.ordinal()
                .domain(labels)

However, values of 1-19 are showing after the text labels.

As seen in this fiddle:

http://jsfiddle.net/chartguy/FbqjD/

Associated Fiddle Source Code:

//Width and height
            var margin = {top: 20, right: 20, bottom: 30, left: 40};           
            var width = 600 - margin.left - margin.right;
            var height= 500-margin.top -margin.bottom;
            var w = width;
            var h = height;


            var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
                            11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

            var labels = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"];
            var xScale = d3.scale.ordinal()
            .domain(labels)
                            .rangeRoundBands([margin.left, width], 0.05);
            var xAxis = d3.svg.axis().scale(xScale).orient("bottom");


            var yScale = d3.scale.linear()
                            .domain([0, d3.max(dataset)])
                            .range([h,0]);


            //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            //Create bars
            svg.selectAll("rect")
               .data(dataset)
               .enter()
               .append("rect")
               .attr("x", function(d, i) {
                    return xScale(i);
               })
               .attr("y", function(d) {
                    return yScale(d);
               })
               .attr("width", xScale.rangeBand())
               .attr("height", function(d) {
                    return h - yScale(d);
               })
               .attr("fill", function(d) {
                    return "rgb(0, 0, 0)";
               });

            svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + 0 + ")")
      .call(xAxis);

            //Create labels
            svg.selectAll("text")
               .data(dataset)
               .enter()
               .append("text")
               .text(function(d) {
                    return d;
               })
               .attr("x", function(d, i) {
                    return xScale(i) + xScale.rangeBand() / 2;
               })
               .attr("y", function(d) {
                    return h - yScale(d) + 14;
               });
Share Improve this question asked Jun 21, 2013 at 1:55 aretearete 1,9334 gold badges17 silver badges24 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 15

You can set the tick values of an ordinal axis explicitly using d3.svg.axis().tickValues(*array*).

But this is an odd way to do it because it dangerously separates your keys and values, meaning you have to take care to manually align the scales and make sure that your data corresponds correctly. It helps to group the keys and values in a single object and then use the format:

       axis.domain(array.map(function (d) { return d.value; }))

to map your axis domains.

I have reworked your data and fiddle to do it in what I see as the more d3 way. (Also note that I made some other changes just for fun, namely improved the margins and cleaned up the axis alignment, etc.)

发布评论

评论列表(0)

  1. 暂无评论