d3.js将网格线和块更改为等间距

d3.js将网格线和块更改为等间距,d3.js,data-visualization,candlestick-chart,D3.js,Data Visualization,Candlestick Chart,我正在玩下面的d3块,这是一个烛台式图表的渲染。其输出如下所示: 每个区块的数据是1天的金融股票数据:高、低、开始和结束 不过,烛台图通常是不同的。通常,块的间隔是均匀的,每天有一条网格线,x轴每天标记一次。以下是谷歌金融的一个例子: 下面是从上面呈现d3图表的代码: var margin = 50; var chart = d3.select("#chart") .append("svg:svg") .attr("

我正在玩下面的d3块,这是一个烛台式图表的渲染。其输出如下所示:

每个区块的数据是1天的金融股票数据:高、低、开始和结束

不过,烛台图通常是不同的。通常,块的间隔是均匀的,每天有一条网格线,x轴每天标记一次。以下是谷歌金融的一个例子:

下面是从上面呈现d3图表的代码:

var margin = 50;           

      var chart = d3.select("#chart")
          .append("svg:svg")
          .attr("class", "chart")
          .attr("width", width)
          .attr("height", height);

      var y = d3.scale.linear()
          .domain([d3.min(data.map(function(x) {return x["Low"];})), d3.max(data.map(function(x){return x["High"];}))])
          .range([height-margin, margin]);
      var x = d3.scale.linear()
          .domain([d3.min(data.map(function(d){return d.timestamp;})), d3.max(data.map(function(d){ return d.timestamp;}))])
          .range([margin,width-margin]);

          chart.selectAll("line.x")
           .data(x.ticks(10))
           .enter().append("svg:line")
           .attr("class", "x")
           .attr("x1", x)
           .attr("x2", x)
           .attr("y1", margin)
           .attr("y2", height - margin)
           .attr("stroke", "#ccc");

          chart.selectAll("line.y")
           .data(y.ticks(10))
           .enter().append("svg:line")
           .attr("class", "y")
           .attr("x1", margin)
           .attr("x2", width - margin)
           .attr("y1", y)
           .attr("y2", y)
           .attr("stroke", "#ccc");

          chart.selectAll("text.xrule")
           .data(x.ticks(10))
           .enter().append("svg:text")
           .attr("class", "xrule")
           .attr("x", x)
           .attr("y", height - margin)
           .attr("dy", 20)
           .attr("text-anchor", "middle")
           .text(function(d){ var date = new Date(d * 1000);  return (date.getMonth() + 1)+"/"+date.getDate(); });

         chart.selectAll("text.yrule")
          .data(y.ticks(10))
          .enter().append("svg:text")
          .attr("class", "yrule")
          .attr("x", width - margin)
          .attr("y", y)
          .attr("dy", 0)
          .attr("dx", 20)        
          .attr("text-anchor", "middle")
          .text(String);

    chart.selectAll("rect")
      .data(data)
      .enter().append("svg:rect")
      .attr("x", function(d) { return x(d.timestamp); })
          .attr("y", function(d) {return y(max(d.Open, d.Close));})       
      .attr("height", function(d) { return y(min(d.Open, d.Close))-y(max(d.Open, d.Close));})
      .attr("width", function(d) { return 0.5 * (width - 2*margin)/data.length; })
          .attr("fill",function(d) { return d.Open > d.Close ? "red" : "green" ;});

        chart.selectAll("line.stem")
          .data(data)
          .enter().append("svg:line")
          .attr("class", "stem")
          .attr("x1", function(d) { return x(d.timestamp) + 0.25 * (width - 2 * margin)/ data.length;})
          .attr("x2", function(d) { return x(d.timestamp) + 0.25 * (width - 2 * margin)/ data.length;})         
          .attr("y1", function(d) { return y(d.High);})
          .attr("y2", function(d) { return y(d.Low); })
          .attr("stroke", function(d){ return d.Open > d.Close ? "red" : "green"; })

      }
我尝试过修补
.data(x.ticks(10))
值,这会改变滴答数,但我不确定如何将其设置为等于数据点的值,而且我也不确定
d3.scale.linear().domain(…)
东西在渲染开始之前到底是如何改变数据的


那么,我如何使块均匀分布,以便每个块都可以生成网格线和每个块都可以生成标签?

问题是,您试图模拟的图形没有基于时间的线性x轴(缺少天数)。您需要根据数据点的数量使用线性比例,然后自定义设置标签值

我没有真正测试这段代码,所以可能有bug。然而,这就是我处理问题的方式

// Create a formatter that given an index, will print the day number for the
// data at that index in data
var dayFormatter = d3.time.format('%d');
var dayAxisFormatter = function(d) {
    return dayFormatter(new Date(data[d].timestamp));
}

// Create a formatter that given an index, will print the short month name
// along with the day number for the data at that index in data
var dayWithMonthFormatter = d3.time.format('%b %d');
var dayWithMonthAxisFormatter = function(d) {
   return dayWithMonthFormatter(new Date(data[d].timestamp));
}

// Custom formatter to handle printing just the day number except for the first
// instance of the month, there we will print the short month and the day

// helper to create the formatter function that d3 accepts
function timeFormat(formats) {
  return function(date) {
    var i = formats.length - 1, f = formats[i];
    while (!f[1](date)) f = formats[--i];
    return f[0](date);
  };
}
var firstDone = {}; // track the months so first instance gets month label
var tickFormatter = timeFormat([
    [dayAxisFormatter, function(d) { return true; }],
    [dayWithMonthFormatter, function(d) {
        var month = (new Date(data[d].timestamp)).getMonth();
        var result = !firstDone['m' + month];
        firstDone['m' + month] = true;
        return result;
     }],
]);

// Set up a regular linear scale. This would normally just count up from
// 0 to d.length, but we'll use a custom formatter to print out our day
// numbers instead.
var x = d3.scale.linear()
    .domain([0, d.length]) // set the domain to be from 0 to # of points
    .range([margin,width-margin]);

// Set up the axis to use our customer formatter
var xAxis = d3.svg.axis()
    .scale(x)
    .tickSize(height)
    .tickFormat(tickFormatter);

// Now when you go to draw your data, you need to remember that the
// underlying scale is based on the data index, not the data timestamp.
chart.selectAll("rect")
    .data(data)
    .enter().append("svg:rect")
    .attr("x", function(d, i) { return x(i); })
    ...

谢谢你的回复。我在玩这个。
timeFormat
指的是什么?这是某个函数的本机函数吗?我问这个问题是因为它没有任何定义,我添加了
timeFormat
函数,忘了这是我写的东西。我可以用
d3.time.format.multi
替换掉它,它实际上工作得很好