单个值时d3中心刻度线和x轴标签

时间:2017-07-03 17:11:10

标签: d3.js

我有以下d3代码:

                var json = [
                {
                    date: "05/17",
                    numTags: 23
                }
            ];

            d3.select('summary-graph').selectAll('*').remove();

            var svg = d3.select("summary-graph"),
                margin = {
                    top: 20,
                    right: 30,
                    bottom: 30,
                    left: 40
                },
                width = svg.attr("width") - margin.left - margin.right,
                height = svg.attr("height") - margin.top - margin.bottom;

            var parseTime = d3.timeParse("%m/%y");

            var svg = d3.select("summary-graph").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 + ")");

            // Get the data
            var data = json;

            // format the data
            data.forEach(function (d) {
                console.log(d);
                d.date = parseTime(d.date);
                d.numTags = +d.numTags;
            });

            // set the ranges
            var xScale = d3.scaleTime()
                            .range([0, width])
                            .domain(d3.extent(data, function (d) {
                                return d.date;
                            }))
                            .nice();

            var yScale = d3.scaleLinear()
                            .range([height, 0])
                            .domain([0, d3.max(data, function (d) {
                                return Math.max(d.numTags);
                            })])
                            .nice();

            // define the 1st line
            var tagLine = d3.line()
                .x(function (d) {
                    return xScale(d.date);
                })
                .y(function (d) {
                    return yScale(d.numTags);
                });


            // Axes
            var xAxis = d3.axisBottom()
                          .scale(xScale)
                          .ticks(json.length)
                          .tickSizeOuter(0)
                          .tickFormat(d3.timeFormat('%B %Y'));

            var yAxis = d3.axisLeft().scale(yScale);

            svg.append("path")
                .data([data])
                .attr("class", "line")
                .style("stroke", "blue")
                .attr("d", tagLine);

            var points = svg.selectAll(".point")
                    .data(data)
                    .enter().append("svg:circle")
                     .attr("stroke", "green")
                     .attr("fill", function(d, i) { return "blue" })
                     .attr("cx", function(d, i) { return xScale(d.date) })
                     .attr("cy", function(d, i) { return yScale(d.numTags) })
                     .attr("r", function(d, i) { return 10 });

            // Add the X Axis
            svg.append("g")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis)
                .style("font-size","14px");;

            // Add the Y Axis
            svg.append("g")
                .call(yAxis);

产生以下可视化:

enter image description here

我正在试图找出如何将刻度线居中并在只有1个这样的数据点时显示x轴标签。在2个数据点,我不喜欢它如何在x轴的最末端设置刻度线。对于3个数据点及以上,它看起来不错(感谢.nice(),似乎)。

任何帮助?

根据Gerado的回应,我能够接近。最后一个问题是X轴的左侧现在有月(3月),尽管当天没有数据。

enter image description here

修正: 将.ticks(json.length)更改为.ticks(d3.timeMonth.every(1))

1 个答案:

答案 0 :(得分:3)

由于您只使用一个数据点,因此您的日期刻度具有一个域,其中较低和较高的值相同:

[
    Mon May 01 2017 00: 00: 00 GMT + 1000,
    Mon May 01 2017 00: 00: 00 GMT + 1000
]

要将该圆放在x轴的中间,您必须为比例域设置不同的值。

有几种方法可以做到这一点。我在此提出的解决方案涉及验证域的值是否相同......

if (xScale.domain()[0].getTime() == xScale.domain()[1].getTime()) {

......如果是的话,改变它们。在这种情况下,我会从下限减去一天,并在上限中加一天:

if (xScale.domain()[0].getTime() == xScale.domain()[1].getTime()) {
    var dateLess = d3.timeDay.offset(xScale.domain()[0], -1);
    var dateMore = d3.timeDay.offset(xScale.domain()[0], 1);
    xScale.domain([dateLess, dateMore])
}

检查结果:



var json = [{
  date: "05/17",
  numTags: 23
}];

var margin = {
    top: 20,
    right: 30,
    bottom: 30,
    left: 40
  },
  width = 400,
  height = 200;

var parseTime = d3.timeParse("%m/%y");

var svg = d3.select("body").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 + ")");

// Get the data
var data = json;

// format the data
data.forEach(function(d) {
  d.date = parseTime(d.date);
  d.numTags = +d.numTags;
});

// set the ranges
var xScale = d3.scaleTime()
  .range([0, width])
  .domain(d3.extent(data, function(d) {
    return d.date;
  }))
  .nice();

if (xScale.domain()[0].getTime() == xScale.domain()[1].getTime()) {
  var dateLess = d3.timeDay.offset(xScale.domain()[0], -1);
  var dateMore = d3.timeDay.offset(xScale.domain()[0], 1);
  xScale.domain([dateLess, dateMore])
}

var yScale = d3.scaleLinear()
  .range([height, 0])
  .domain([0, d3.max(data, function(d) {
    return Math.max(d.numTags);
  })])
  .nice();

// define the 1st line
var tagLine = d3.line()
  .x(function(d) {
    return xScale(d.date);
  })
  .y(function(d) {
    return yScale(d.numTags);
  });


// Axes
var xAxis = d3.axisBottom()
  .scale(xScale)
  .ticks(json.length)
  .tickSizeOuter(0)
  .tickFormat(d3.timeFormat('%B %Y'));

var yAxis = d3.axisLeft().scale(yScale);

svg.append("path")
  .data([data])
  .attr("class", "line")
  .style("stroke", "blue")
  .attr("d", tagLine);

var points = svg.selectAll(".point")
  .data(data)
  .enter().append("svg:circle")
  .attr("stroke", "green")
  .attr("fill", function(d, i) {
    return "blue"
  })
  .attr("cx", function(d, i) {
    return xScale(d.date)
  })
  .attr("cy", function(d, i) {
    return yScale(d.numTags)
  })
  .attr("r", function(d, i) {
    return 10
  });

// Add the X Axis
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
  .style("font-size", "14px");;

// Add the Y Axis
svg.append("g")
  .call(yAxis);

<script src="https://d3js.org/d3.v4.js"></script>
&#13;
&#13;
&#13;

编辑:正如您在编辑中提到的那样,当您有两个数据值时,我的解决方案将在限制上创建额外的滴答,这是预期的行为:

&#13;
&#13;
var json = [{
  date: "05/17",
  numTags: 23
}, {
  date: "05/17",
  numTags: 17
}];

var margin = {
    top: 20,
    right: 30,
    bottom: 30,
    left: 40
  },
  width = 400,
  height = 200;

var parseTime = d3.timeParse("%m/%y");

var svg = d3.select("body").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 + ")");

// Get the data
var data = json;

// format the data
data.forEach(function(d) {
  d.date = parseTime(d.date);
  d.numTags = +d.numTags;
});

// set the ranges
var xScale = d3.scaleTime()
  .range([0, width])
  .domain(d3.extent(data, function(d) {
    return d.date;
  }))
  .nice();

if (xScale.domain()[0].getTime() == xScale.domain()[1].getTime()) {
  var dateLess = d3.timeDay.offset(xScale.domain()[0], -1);
  var dateMore = d3.timeDay.offset(xScale.domain()[0], 1);
  xScale.domain([dateLess, dateMore])
}

var yScale = d3.scaleLinear()
  .range([height, 0])
  .domain([0, d3.max(data, function(d) {
    return Math.max(d.numTags);
  })])
  .nice();

// define the 1st line
var tagLine = d3.line()
  .x(function(d) {
    return xScale(d.date);
  })
  .y(function(d) {
    return yScale(d.numTags);
  });


// Axes
var xAxis = d3.axisBottom()
  .scale(xScale)
  .ticks(json.length)
  .tickSizeOuter(0)
  .tickFormat(d3.timeFormat('%B %Y'));

var yAxis = d3.axisLeft().scale(yScale);

svg.append("path")
  .data([data])
  .attr("class", "line")
  .style("stroke", "blue")
  .attr("d", tagLine);

var points = svg.selectAll(".point")
  .data(data)
  .enter().append("svg:circle")
  .attr("stroke", "green")
  .attr("fill", function(d, i) {
    return "blue"
  })
  .attr("cx", function(d, i) {
    return xScale(d.date)
  })
  .attr("cy", function(d, i) {
    return yScale(d.numTags)
  })
  .attr("r", function(d, i) {
    return 10
  });

// Add the X Axis
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
  .style("font-size", "14px");;

// Add the Y Axis
svg.append("g")
  .call(yAxis);
&#13;
<script src="https://d3js.org/d3.v4.js"></script>
&#13;
&#13;
&#13;

有几种方法可以删除这些标记。其中一个是使用tickValues

.tickValues(data.map(function(d){ return d.date}))

以下是演示:

&#13;
&#13;
var json = [{
  date: "05/17",
  numTags: 23
}, {
  date: "05/17",
  numTags: 17
}];

var margin = {
    top: 20,
    right: 30,
    bottom: 30,
    left: 40
  },
  width = 400,
  height = 200;

var parseTime = d3.timeParse("%m/%y");

var svg = d3.select("body").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 + ")");

// Get the data
var data = json;

// format the data
data.forEach(function(d) {
  d.date = parseTime(d.date);
  d.numTags = +d.numTags;
});

// set the ranges
var xScale = d3.scaleTime()
  .range([0, width])
  .domain(d3.extent(data, function(d) {
    return d.date;
  }))
  .nice();

if (xScale.domain()[0].getTime() == xScale.domain()[1].getTime()) {
  var dateLess = d3.timeDay.offset(xScale.domain()[0], -1);
  var dateMore = d3.timeDay.offset(xScale.domain()[0], 1);
  xScale.domain([dateLess, dateMore])
}

var yScale = d3.scaleLinear()
  .range([height, 0])
  .domain([0, d3.max(data, function(d) {
    return Math.max(d.numTags);
  })])
  .nice();

// define the 1st line
var tagLine = d3.line()
  .x(function(d) {
    return xScale(d.date);
  })
  .y(function(d) {
    return yScale(d.numTags);
  });


// Axes
var xAxis = d3.axisBottom()
  .scale(xScale)
  .ticks(json.length)
  .tickSizeOuter(0)
  .tickValues(data.map(function(d){ return d.date}))
  .tickFormat(d3.timeFormat('%B %Y'));

var yAxis = d3.axisLeft().scale(yScale);

svg.append("path")
  .data([data])
  .attr("class", "line")
  .style("stroke", "blue")
  .attr("d", tagLine);

var points = svg.selectAll(".point")
  .data(data)
  .enter().append("svg:circle")
  .attr("stroke", "green")
  .attr("fill", function(d, i) {
    return "blue"
  })
  .attr("cx", function(d, i) {
    return xScale(d.date)
  })
  .attr("cy", function(d, i) {
    return yScale(d.numTags)
  })
  .attr("r", function(d, i) {
    return 10
  });

// Add the X Axis
svg.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)
  .style("font-size", "14px");;

// Add the Y Axis
svg.append("g")
  .call(yAxis);
&#13;
<script src="https://d3js.org/d3.v4.js"></script>
&#13;
&#13;
&#13;