d3 几种常用的柱状图

Posted chenjy1225

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了d3 几种常用的柱状图相关的知识,希望对你有一定的参考价值。

本文参照了echarts罗列了几种常用的柱状图在d3中的画法

基本柱状图

使用d3直方图布局

  • d3的所有布局都不会帮你作图,只是帮你按需处理的数据。

  • 使用d3.randomBates构造一组1000个具有贝茨分布规律并且在1~0的随机数,使用d3.histogram()直方图布局处理数据。统计数据在每个x轴频段出现的频率。然后作出柱状图。

  • 处理后的数据

技术图片

x0、x1:起始及终止的x坐标,length:出现的频数,数组里其他的即为在此频段的数据。


<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>
        </title>
    </head>
    <body>
        <div id="test-svg">
        </div>
    </body>
    <script src="https://d3js.org/d3.v5.js">
    </script>
    <script>
        window.onload = function() 
            //创建具有贝茨分布规律的随机数,0~1
            var datas = d3.range(1000).map(function() 
                return d3.randomBates(10)();
            );
            
            var width = 800,
            height = 400,
            padding = 
                top: 10,
                right: 40,
                bottom: 40,
                left: 40
            ;
            
            var svg = d3.select("#test-svg")
            .append('svg')
            .attr('width', width + 'px')
            .attr('height', height + 'px');
            
            // x轴
            var xScale = d3.scaleLinear()
            .range([padding.left, width - padding.right]);
            // 将x轴,0~1,轴分成20个刻度 [0,0.05,0.1,0.15 ...,1.00]
            
            var xAxis = d3.axisBottom()
            .scale(xScale)
            .ticks(20);
            svg.append('g')
            .call(xAxis)
            .attr("transform", "translate(0," + (height - padding.bottom) + ")");
            
            // 构造一个直方图布局,返回随机数在每个x轴刻度区域出现的次数
            var his = d3.histogram()
            .domain(xScale.domain())
            .thresholds(xScale.ticks(20))
            (datas);
            
            // y轴
            var yScale = d3.scaleLinear()
            .domain([0, d3.max(his,
            function(d) 
                return d.length;
            )])
            .range([height - padding.bottom, padding.top]);
            
            var yAxis = d3.axisLeft()
            .scale(yScale)
            .ticks(10);
            svg.append('g')
            .call(yAxis)
            .attr("transform", "translate(" + padding.left + ",0)");
            
            var bar = svg.selectAll(".bar")
            .data(his)
            .join("g")
            .attr("class", "bar")
            .attr("transform",
            function(d) 
                return "translate(" + xScale(d.x0) + "," + yScale(d.length) + ")";
            );
            
            // 构造柱
            bar.append("rect")
            .attr("x", 1)
            .attr("width", xScale(his[0].x1) - xScale(his[0].x0) - 1)
            .attr("height",
            function(d) 
                return height - yScale(d.length) - padding.bottom;
            );
            
            bar.append("text")
            .attr("dy", ".75em")
            .attr("y", 6)
            .attr("x", (xScale(his[0].x1) - xScale(his[0].x0)) / 2)
            .attr("text-anchor", "middle")
            .attr("font-size", "8px")
            .attr("fill", "White")
            .text(function(d) 
                return d.length;
            );
        
    </script>
</html>

技术图片

使用原始数据

  • 这里使用echarts Bar Simple的原始数据,和上述类似直接处理数据作图。

技术图片


<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <div id="test-svg">
        </div>
    </body>
    <script src="https://d3js.org/d3.v5.js"></script>
    <script>
        window.onload = function() 
            // 原始数据
            var datax = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
            var datay = [120, 200, 150, 80, 70, 110, 130];
            
            var width = 800,
                height = 400,
                padding = 
                    top: 10,
                    right: 40,
                    bottom: 40,
                    left: 40
                ;
                
            var svg = d3.select("#test-svg")
                .append('svg')
                .attr('width', width + 'px')
                .attr('height', height + 'px');
                
            // x轴
            var xScale = d3.scaleOrdinal()
                .domain(datax)
                .range([100, 200, 300, 400, 500, 600, 700]);
            var xAxis = d3.axisBottom()
                .scale(xScale);
            svg.append('g')
                .call(xAxis)
                .attr("transform", "translate(0," + (height - padding.bottom) + ")")
                .selectAll("text")
                .attr("dx", "50px");
                
            // y轴      
            var yScale = d3.scaleLinear()
                .domain([0, d3.max(datay)])
                .range([height - padding.bottom, padding.top]);
            var yAxis = d3.axisLeft()
                .scale(yScale)
                .ticks(10);
            svg.append('g')
                .call(yAxis)
                .attr("transform", "translate(" + 100 + ",0)");
                
            var bar = svg.selectAll(".bar")
                .data(datay)
                .enter().append("g")
                .attr("class", "bar")
                .attr("transform", function(d, i) 
                    return "translate(" + xScale(i * 100) + "," + yScale(d) + ")";
                );
                
            bar.append("rect")
                .attr("x", 1)
                .attr("width", 100)
                .attr("height", function(d) 
                    return height - yScale(d) - padding.bottom;
                )
                .attr("stroke", "White");
                
            bar.append("text")
                .attr("dy", ".75em")
                .attr("y", 6)
                .attr("x", 50)
                .attr("text-anchor", "middle")
                .attr("font-size", "8px")
                .attr("fill", "White")
                .text(function(d) 
                    return d;
                );
        
    </script>

</html>

技术图片

多柱图

在原来的基础上仿照echarts 添加了图例和对应的点击事件。


<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <div id="test-svg">
        </div>
    </body>
    <script src="https://d3js.org/d3.v5.js"></script>
    <script>
        window.onload = function() 
            
            var datax = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
            var datay = [
                [120, 200, 150, 80, 70, 110, 130],
                [100, 100, 130, 70, 10, 120, 135],
                [160, 120, 120, 90, 20, 140, 130]
            ];
            // 用来保存点击时的状态
            var legendStatus = [true, true, true];
            
            var width = 800,
                height = 400,
                padding = 
                    top: 40,
                    right: 40,
                    bottom: 40,
                    left: 40
                ;
            var sp = d3.schemeSet2;
            var svg = d3.select("#test-svg")
                .append('svg')
                .attr('width', width + 'px')
                .attr('height', height + 'px');
                
            // x轴
            var xScale = d3.scaleOrdinal()
                .domain(datax)
                .range([100, 200, 300, 400, 500, 600, 700]);
            var xAxis = d3.axisBottom()
                .scale(xScale)
                .tickSize(10);
            svg.append('g')
                .call(xAxis)
                .attr("transform", "translate(0," + (height - padding.bottom) + ")")
                .selectAll("text")
                .attr("dx", "50px");
                
            // y轴      
            var yScale = d3.scaleLinear()
                .domain([0, d3.max(d3.merge([datay[0], datay[1], datay[2]]))])
                .range([height - padding.bottom, padding.top]);
            var yAxis = d3.axisLeft()
                .scale(yScale)
                .ticks(10);
            svg.append('g')
                .call(yAxis)
                .attr("transform", "translate(" + 100 + ",0)");
            
            
                               
            // 这里使用了forEach 考虑到计算柱子偏移量可能会方便一点  也可以直接                   
            /**
             * 
             * var container = svg.selectAll(".container") 
             *                  .data(datay)
             *                  .join("g")
             *                  .attr("class", ".container");
             * 
             */
            
            datay.forEach(function(item, index) 
                var bar = svg.selectAll(".bar" + index)
                    .data(item)
                    .enter().append("g")
                    .attr("class", "bar" + index)
                    .attr("transform", function(d, i) 
                        var _d = (100 / datay.length) * (index);
                        return "translate(" + (xScale(i * 100) + _d) + "," + yScale(d) + ")";
                    );
                
                // 柱
                bar.append("rect")
                    .attr("x", 1)
                    .attr("width", (100 / datay.length))
                    .attr("height", function(d) 
                        return height - yScale(d) - padding.bottom;
                    )
                    .attr("stroke", "White")
                    .attr("fill", sp[index]);
                    
                bar.append("text")
                    .attr("dy", ".75em")
                    .attr("y", 6)
                    .attr("x", 100 / (datay.length * 2))
                    .attr("text-anchor", "middle")
                    .attr("font-size", "8px")
                    .attr("fill", "White")
                    .text(function(d) 
                        return d;
                    );
                
                // 图例
                var legend = svg.append('g');
                var line = legend.append('line')
                    .attr('x1', 0)
                    .attr('y1', 2)
                    .attr('x2', 15)
                    .attr('y2', 2)
                    .attr('stroke', sp[index])
                    .attr('stroke-width', 5);
                var text = legend.append('text')
                    .attr('class', 'legend-label')
                    .attr("dy", -13)
                    .style("text-anchor", "start")
                    .text("data" + index)
                    .attr('fill', "Black")
                    .attr('font-size', '13')
                    .attr("transform", "translate(" + 18 + "," + 20 + ")");
                // 图例对应的点击事件    
                legend.attr("transform", "translate(" + (padding.left * 3 + index * 100) + "," + padding.top / 2 + ")")
                    .on("click", function() 
                        var _this = d3.select(this);
                        var _i = parseInt(_this.select("text").text().split("data")[1]);

                        if(legendStatus[_i]) 
                            _this.selectAll("line").attr("stroke", "#d3d3d3");
                            _this.selectAll("text").attr("fill", "#d3d3d3");

                            svg.selectAll(".bar" + _i)
                                .attr("display", "none");
                         else 
                            _this.selectAll("line").attr("stroke", sp[_i]);
                            _this.selectAll("text").attr("fill", "#Black");

                            svg.selectAll(".bar" + _i)
                                .attr("display", "show");
                        

                        legendStatus[_i] = !legendStatus[_i];
                    );
            );
        
    </script>

</html>

技术图片

技术图片

堆叠柱状图

  • 使用了d3.stack()堆叠布局来处理原始数据,然后作图。

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>
        </title>
    </head>

    <body>
        <div id="test-svg">
        </div>
    </body>
    <script src="https://d3js.org/d3.v5.js">
    </script>
    <script>
        window.onload = function() 
            var data = [
                apples: 3840,
                bananas: 1920,
                cherries: 960,
                dates: 400
            , 
                apples: 1600,
                bananas: 1440,
                cherries: 960,
                dates: 400
            , 
                apples: 640,
                bananas: 960,
                cherries: 640,
                dates: 400
            , 
                apples: 320,
                bananas: 480,
                cherries: 640,
                dates: 400
            ];

            var width = 800,
                height = 400,
                padding = 
                    top: 40,
                    right: 40,
                    bottom: 40,
                    left: 40
                ;

            var colors = d3.schemeSet2;
            var svg = d3.select("#test-svg")
                .append('svg')
                .attr('width', width + 'px')
                .attr('height', height + 'px');

            // 使用堆叠布局处理数据
            var stack = d3.stack()
                .keys(["apples", "bananas", "cherries", "dates"])
                .order(d3.stackOrderNone)
                .offset(d3.stackOffsetNone);
            var series = stack(data);
            
            // x轴
            var xScale = d3.scaleOrdinal()
                .domain(series.map(function(d) 
                    return d.key;
                ))
                .range([100, 200, 300, 400]);
            var xAxis = d3.axisBottom()
                .scale(xScale)
                .tickSize(10);
            svg.append('g')
                .call(xAxis)
                .attr("transform", "translate(0," + (height - padding.bottom) + ")")
                .selectAll("text")
                .attr("font-size", "10px")
                .attr("dx", "50px");
            
            // 求出y轴最大值
            var maxNum = d3.max(series,
                function(d) 
                    return d3.max(d,
                        function(dd) 
                            return dd[1];
                        )
                );
            // y轴   
            var yScale = d3.scaleLinear()
                .domain([0, maxNum])
                .range([height - padding.bottom, padding.top]);
            var yAxis = d3.axisLeft()
                .scale(yScale)
                .ticks(10);
            svg.append('g')
                .call(yAxis)
                .attr("transform", "translate(" + 100 + ",0)");
            
            // 画柱
            var bar = svg.selectAll(".bar")
                .data(series)
                .join("g")
                .attr("class", "bar")
                .selectAll("rect")
                .data(function(d) 
                    return d;
                );
                
            bar.join("rect")
                .attr("x", 1)
                .attr("width", 100)
                .attr("height",
                    function(d, i) 
                        return height - yScale(d[1] - d[0]) - padding.bottom;
                    )
                .attr("transform",
                    function(d, i) 
                        return "translate(" + xScale(i * 100) + "," + yScale(d[1]) + ")";
                    )
                .attr("stroke", "White")
                .attr("fill",
                    function(d, i) 
                        return colors[i];
                    );
                    
            bar.join("text")
                .attr("dy", ".75em")
                .attr("y", 6)
                .attr("x", 50)
                .attr("text-anchor", "middle")
                .attr("font-size", "8px")
                .attr("fill", "White")
                .text(function(d) 
                    return d[1] - d[0];
                )
                .attr("transform",
                    function(d, i) 
                        return "translate(" + xScale(i * 100) + "," + yScale(d[1]) + ")";
                    );
        
    </script>

</html>

技术图片

以上是关于d3 几种常用的柱状图的主要内容,如果未能解决你的问题,请参考以下文章

d3.js(v5.7)完整地画一个柱状图

D3绘制水平柱状图

D3---基础的柱状图制作

d3.js做的柱状图

零基础自学前端 D3.js 初体验03 柱状图+排序

D3.js中Stacked-to-Grouped Bars详解