【问题标题】:d3.js categorical time series (evolustrip)d3.js 分类时间序列(evolustrip)
【发布时间】:2013-02-12 12:58:31
【问题描述】:

d3.js 中工作,我正在寻找一种显示分类时间序列数据的好方法。数据值不能同时出现,并且间隔不均匀,所以我的数据完全像:

location = [[time1: home], [time4: work], [time5: cafe], [time7: home]]

等等。我理想的结果图类似于evolustrip - 查看此图表的一种方式是作为具有可变宽度条的时间序列图表,条颜色对应于类别(例如“家”)。

谁能指出我正确的方向?非常感谢!

【问题讨论】:

    标签: d3.js time-series


    【解决方案1】:

    所以我最终制作了自己的 d3.js 解决方案:

    我使用 d3.time.scale 刻度作为时间维度,然后使用 d3.scale.category20 刻度为类别提供颜色。然后,我在时间轴上按开始时间将分类数据绘制为相同高度的矩形,并使用 d3.time.scale 比例计算每个矩形的适当 bin 宽度。

    可以在此处查看可重用组件(遵循http://bost.ocks.org/mike/chart/ 的模式)示例:

    function timeSeriesCategorical() {
        var w = 860,
            h = 70,
            margin = {top: 20, right: 80, bottom: 30, left: 50},
            width = w - margin.left - margin.right,
            height = h - margin.top - margin.bottom;
        var xValue = function(d) { return d[0]; },
            yValue = function(d) { return d[1]; };
        var yDomain = null;
        var xScale = d3.time.scale()
            .range([0, width]);
        var yScale = d3.scale.category20();
        var xAxis = d3.svg.axis()
            .scale(xScale)
            .tickSubdivide(1)
            .tickSize(-height)
            .orient('bottom');
        var yAxis = d3.svg.axis()
            .scale(yScale)
            .ticks(5)
            .orient('left');
        var binwidth = 20;
    
        function chart(selection) {
            selection.each(function(data) {
    
                // convert data to standard representation
                data = data.map(function(d, i) {
                    return [xValue.call(data, d, i), yValue.call(data, d, i)];
                    //return d;
                });
    
                // scale the x and y domains based on the actual data
                xScale.domain(d3.extent(data, function(d) { return d[0]; }));
                if (!yDomain) {
                    yScale.domain(d3.extent(data, function(d) { return d[1]; }));
                } else {
                    yScale.domain(yDomain);
                }
    
                // compute binwidths for TODO better comment
                // d looks like {timestamp, category}
                data.forEach(function(d, i) {
                    if (data[i+1]) {
                        w_current = xScale(data[i][0]);
                        w_next = xScale(data[i+1][0]);
                        binwidth = w_next - w_current;
                    }
                    d.binwidth = binwidth;
                });
    
                // create chart space as svg
                // note: 'this' el should not contain svg already
                var svg = d3.select(this).append('svg').data(data);
    
                // external dimensions
                svg.attr('width', w)
                    .attr('height', h);
    
                // internal dimensions
                svg = svg.append('g')
                    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    
                // x axis
                svg.append('g')
                    .attr('class', 'x axis')
                    .attr('transform', 'translate(0,' + height + ')')
                    .call(xAxis);
    
                // TODO bars legend
    
                // bars
                svg.selectAll('rect')
                    .data(data)
                  .enter().append('rect')
                    .attr('x', function(d, i) { return xScale(d[0]); })
                    .attr('width', function(d, i) { return d.binwidth; })
                    .attr('height', height)
                    .attr('fill', function(d, i) { return yScale(d[1]); })
                    .attr('stroke', function(d, i) { return yScale(d[1]); });
    
            });
        }
    
        chart.x = function(_) {
            if (!arguments.length) return xValue;
            xValue = _;
            return chart;
        };
    
        chart.y = function(_) {
            if (!arguments.length) return yValue;
            yValue = _;
            return chart;
        };
    
        chart.yDomain = function(_) {
            if (!arguments.length) return yDomain;
            yDomain = _;
            return chart;
        };
    
        return chart;
    }
    

    并且可以通过以下方式调用:

    d3.csv('./data.csv', function(data) {
         var chartActivity = timeSeriesCategorical()
            .x(function(d) { return d.when; })
            .y(function(d) { return d.activity; })
            .yDomain([0,1]);
         d3.select('#chart-activity')
            .datum(data)
            .call(chartActivity);
    });
    

    希望这对某人有帮助!这个项目是在https://github.com/interaction-design-lab/stress-sense-portal

    【讨论】:

      猜你喜欢
      • 2013-07-31
      • 1970-01-01
      • 2015-12-11
      • 2016-11-15
      • 2018-01-16
      • 1970-01-01
      • 2012-12-05
      • 2018-03-29
      • 2018-05-25
      相关资源
      最近更新 更多