d3-数据操作

本文介绍了D3.js库在数据绑定、图形生成及动态更新方面的应用。通过示例展示了如何创建条形图并进行数据筛选、图形排序和动态更新。内容包括数据绑定的状态(进入、更新、退出),以及如何利用D3的API进行数据操作,如最小值、最大值、中位数等统计计算,以及数据筛选和图形排序的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

enter-update-exit

将数据和图形分为两个领域,分别记作AB,相互之间绑定才能做出图形展示,可以产生下面四种情况

领域状态表示
数据未绑定图形A−(A⋂B)A - (A \bigcap B)A(AB)
A0A_0A0
数据已绑定图形A⋂BA\bigcap BAB
A1A_1A1
图形未绑定数据B−A⋂BB - A\bigcap BBAB
B0B_0B0
图形已绑定数据A⋂BA\bigcap BAB
B1B_1B1

可以看到,整个集合被分割为了三个部分
A∪B=(A−A∩B)+A∩B+(B−A∩B) A \cup B = (A - A\cap B) + {A\cap B} + (B - A\cap B) AB=(AAB)+AB+(BAB)

data{A0A1⋯B1B0}graph \text{data}\left\{ \begin{matrix} A_0 & & \\ A_1 & \cdots & B_1 \\ & & B_0 \end{matrix} \right\}\text{graph} dataA0A1B1B0graph

基础数据

<html>
<head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style type="text/css">
        .h-bar {
            min-height: 15px;
            min-width: 10px;
            background-color: steelblue;
            margin-bottom: 2px;
            font-size: 11px;
            color: #f0f8ff;
            text-align: right;
            padding-right: 2px;
        }
    </style>
</head>
<body>
<script type="text/javascript">
    let data = [1,2,3,4,5,6,7,8,9];
    let last_index = 8;
    let direction = true;
    function render(data){
        // 选择元素
        d3.select("body").selectAll("div.h-bar")
        	// 指定数据
            .data(data)
        	// 绑定
            .enter()
            .append("div")
            .attr("class", "h-bar")
            .append("span");
        d3.select("body").selectAll("div.h-bar")
        	// 获取数据
            .data(data)
        	// 操作数据
            .style("width", function (d){
                return (d * 3) + "px";
            })
            .select("span")
        	// 填充数据
            .text(function (d){
                return d;
            });
        // 选择元素
        d3.select("body").selectAll("div,h-bar")
        	// 获取数据
            .data(data)
        	// 解绑
            .exit()
            .remove();
    }
    setInterval(function(){
        if(direction && data[last_index] > 100){
            direction = false;
        } else if(!direction && data[last_index] < 1){
            direction = true;
        }
        data.shift();
        data.push(data[last_index-1] + (direction ? 1 : -1));
        render(data);
    }, 10);
    render(data);
</script>
</body>
</html>

对象数据

<html>
<head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style type="text/css">
        .h-bar {
            min-height: 15px;
            min-width: 10px;
            background-color: steelblue;
            margin-bottom: 2px;
            font-size: 11px;
            color: #f0f8ff;
            text-align: right;
            padding-right: 2px;
        }
    </style>
</head>
<body>
<script type="text/javascript">
    // each内拿到的是集合中的单个对象,可以直接使用
    var data = [ 
        {width: 10, color: 23},{width: 15, color: 33},
        {width: 30, color: 40},{width: 50, color: 60},
        {width: 80, color: 22},{width: 65, color: 10},
        {width: 55, color: 5},{width: 30, color: 30},
        {width: 20, color: 60},{width: 10, color: 90},
        {width: 8, color: 10}
    ];
    
    var colorScale = d3.scale.linear()
        .domain([0, 100])
        .range(["#add8e6", "blue"]); 

    function render(data) {
        d3.select("body").selectAll("div.h-bar")
            .data(data)
            .enter().append("div")
                .attr("class", "h-bar")                
            .append("span");

        d3.select("body").selectAll("div.h-bar")
            .data(data)
            .exit().remove();

        d3.select("body").selectAll("div.h-bar")
            .data(data)
                .attr("class", "h-bar")
                .style("width", function (d) {
                    return (d.width * 5) + "px"; 
                })
                .style("background-color", function(d){
                    return colorScale(d.color); 
                })
            .select("span")
                .text(function (d) {
                    return d.width; 
                });
    }

    function randomValue() {
        return Math.round(Math.random() * 100);
    }

    setInterval(function () {
        data.shift();
        data.push({width: randomValue(), color: randomValue()});
        render(data);
    }, 100);

    render(data);
</script>

</body>
</html>

方法数据

<html>
<head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style type="text/css">
        .v-bar {
            min-height: 1px;
            min-width: 30px;
            background-color: #4682b4;
            margin-right: 2px;
            font-size: 10px;
            color: #f0f8ff;
            text-align: center;
            width: 10px;
            display: inline-block;
        }
    </style>
</head>
<body>
<div id="container"></div>

<script type="text/javascript">
    var data = [];
    var counter = 0;
    var boundary = 50;
    var period = 10;
    var flag = true;
    var scale = 10;
    // 元素是方法
    var next = function (x) {
       x += counter;
       if((x % 2 === 0)&&(x % period) === 0){
           flag = !flag;
       }
       x = x % period;
       if(flag){
           return x * scale;
       } else {
           return (period - x) * scale;
       }
    };

    var newData = function () {
        counter += 1;
        if(data.length > boundary){
            data.shift();
        }
        data.push(next);
        return data;
    };

    function render(){
        var selection = d3.select("#container")
                    .selectAll("div")
        			// 数据是方法
                    .data(newData);

        selection.enter().append("div").append("span");
        
        selection.attr("class", "v-bar")
        	// 这里只是单纯的元素遍历,具体元素类型应该参考传入data
            .style("height", function (d, i) {
                return d(i) + "px";
            })
            .select("span")
                .text(function(d, i){
                    return d(i);
                });
        selection.exit().remove();
    }
    setInterval(function () {
        render();
    }, 100);

    render();
</script>

</body>

</html>

数组操作

apidescription
d3.min最小值
d3.max最大值
d3.extent[最小值,最大值]
d3.sum求和
d3.medium中位数
d3.mean平均数
d3.ascending正序
d3.descending倒序
d3.quantileP(x≤X)P(x \leq X)P(xX)
d3.bisect插入点left<X<rightleft < X < rightleft<X<right
d3.nest转换树状结构
var array = [3, 2, 11, 7, 6, 4, 10, 8, 15];

    d3.select("#min").text(d3.min(array));
    d3.select("#max").text(d3.max(array));
    d3.select("#extent").text(d3.extent(array));
    d3.select("#sum").text(d3.sum(array));
    d3.select("#median").text(d3.median(array));
    d3.select("#mean").text(d3.mean(array));
    d3.select("#asc").text(array.sort(d3.ascending));
    d3.select("#desc").text(array.sort(d3.descending));
    d3.select("#quantile").text(
        d3.quantile(array.sort(d3.ascending), 0.25)
    );
    d3.select("#bisect").text(
        d3.bisect(array.sort(d3.ascending), 6)
    );

    var records = [
        {quantity: 2, total: 190, tip: 100, type: "tab"},
        {quantity: 2, total: 190, tip: 100, type: "tab"},
        {quantity: 1, total: 300, tip: 200, type: "visa"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 1, total: 100, tip: 0, type: "cash"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 2, total: 90, tip: 0, type: "tab"},
        {quantity: 2, total: 200, tip: 0, type: "cash"},
        {quantity: 1, total: 200, tip: 100, type: "visa"}
    ];
    var nest = d3.nest()
            .key(function (d) { 
                return d.type;
            })
            .key(function (d) { 
                return d.tip;
            })
            .entries(records); 
    d3.select("#nest").html(printNest(nest, ""));
    function printNest(nest, out, i) {
        if(i === undefined) i = 0;

        var tab = ""; for(var j = 0; j < i; ++j) tab += " ";

        nest.forEach(function (e) {
            if (e.key)
                out += tab + e.key + "<br>";
            else
                out += tab + printObject(e) + "<br>";

            if (e.values)
                out = printNest(e.values, out, ++i);
            else
                return out;
        });

        return out;
    }

    function printObject(obj) {
        var s = "{";
        for (var f in obj) {
            s += f + ": " + obj[f] + ", ";
        }
        s += "}";
        return s;
    }

数据筛选

<html>
<head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style type="text/css">
        .h-bar {
            min-height: 15px;
            min-width: 10px;
            background-color: steelblue;
            margin-bottom: 2px;
            font-size: 11px;
            color: #f0f8ff;
            text-align: right;
            padding-right: 2px;
        }
        .selected {
            background-color: #f08080;
        }
    </style>
</head>
<body>
<script type="text/javascript">
    var data = [ 
        {expense: 10, category: "Retail"},
        {expense: 15, category: "Gas"},
        {expense: 30, category: "Retail"},
        {expense: 50, category: "Dining"},
        {expense: 80, category: "Gas"},
        {expense: 65, category: "Retail"},
        {expense: 55, category: "Gas"},
        {expense: 30, category: "Dining"},
        {expense: 20, category: "Retail"},
        {expense: 10, category: "Dining"},
        {expense: 8, category: "Gas"}
    ];

    function render(data, category) {
        d3.select("body").selectAll("div.h-bar")
                .data(data)
			.enter()
            .append("div")
                .attr("class", "h-bar")
			.append("span");

        d3.select("body").selectAll("div.h-bar") 
                .data(data)
            .exit().remove();

        d3.select("body").selectAll("div.h-bar") 
                .data(data)
            .attr("class", "h-bar")
            .style("width", function (d) {
                return (d.expense * 5) + "px";}
            )
            .select("span")
                .text(function (d) {
                    return d.category;
                });
		// 筛选
        d3.select("body").selectAll("div.h-bar")
                .filter(function (d, i) {
                    return d.category == category;
                })
                .classed("selected", true);
    }

    render(data);

    function select(category) {
        render(data, category);
    }
</script>

<div class="control-group">
    <button onclick="select('Retail')">
        Retail
    </button>
    <button onclick="select('Gas')">
        Gas
    </button>
    <button onclick="select('Dining')">
        Dining
    </button>
    <button onclick="select()">
        Clear
    </button>
</div>

</body>

</html>

图形排序

<html>
<head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
    <style type="text/css">
        .h-bar {
            min-height: 15px;
            min-width: 10px;
            background-color: steelblue;
            margin-bottom: 2px;
            font-size: 11px;
            color: #f0f8ff;
            text-align: right;
            padding-right: 2px;
        }
        .selected {
            background-color: #f08080;
        }
    </style>
</head>
<body>

<script type="text/javascript">
    var data = [
        {expense: 10, category: "Retail"},
        {expense: 15, category: "Gas"},
        {expense: 30, category: "Retail"},
        {expense: 50, category: "Dining"},
        {expense: 80, category: "Gas"},
        {expense: 65, category: "Retail"},
        {expense: 55, category: "Gas"},
        {expense: 30, category: "Dining"},
        {expense: 20, category: "Retail"},
        {expense: 10, category: "Dining"},
        {expense: 8, category: "Gas"}
    ];

    function render(data, comparator) {
        d3.select("body").selectAll("div.h-bar")
                .data(data)
            .enter().append("div")
                .attr("class", "h-bar")
                .append("span");

        d3.select("body").selectAll("div.h-bar") 
                .data(data)
            .exit().remove();

        d3.select("body").selectAll("div.h-bar")
                .data(data)
            .attr("class", "h-bar")
            .style("width", function (d) {
                return (d.expense * 5) + "px";
            })
            .select("span")
                .text(function (d) {
                    return d.category;
                });

        if(comparator)
            d3.select("body")
                .selectAll("div.h-bar") 
                .sort(comparator); 
    }

    var compareByExpense = function (a, b) { 
        return a.expense < b.expense?-1:1;
    };
    var compareByCategory = function (a, b) {  
        return a.category < b.category?-1:1;
    };
    var compareByNameLength = function (a, b){
        return a.category.length - b.category.length;
    }

    render(data);

    function sort(comparator) {
        render(data, comparator);
    }
</script>

<div class="control-group">
    <button onclick="sort(compareByExpense)">
        Sort by Width
    </button>
    <button onclick="sort(compareByCategory)">
        Sort by Category
    </button>
    <button onclick="sort(compareByNameLength)">
        Sort by Category's Length
    </button>
    <button onclick="sort()">
        Clear
    </button>
</div>

</body>

</html>

动态更新

没啥,就是通过接口调用替换data,这里就不写了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值