D3.js(2) Data-Join

news2024/11/18 20:38:55

什么是Data-Join?

本质上是将数据与图元绑定

可以省去大量根据数据设置图元属性的代码量,对动态变化的数据提供统一接口

D3.js绑定数据的三个状态

Enter

数据数量>图元数量,d3.js会根据新增的数据生成相应的图元

给不存在数据绑定的图元提供占位符

const p = maingroup.selectAll('.class').data(data).enter().append('').attr(...)
//data(data) 数据绑定

Update

图元数量与数据数量一致 

const p = maingroup.selectAll('.class').data(data).append('').attr(...)

在update状态时可以配合transition().duration(time)实现动画的过渡效果

Exit

数据数量<图元数量,d3.js会自动删除没有绑定数据的图元

const p = maingroup.selectAll('.class').data(data).exit().remove()

 读取CSV

d3.csv('./data.csv').then(data => {})
//返回值是一个Promise对象,JS中的异步编程
//不能用等号接受它的返回值

如果d3.csv读取的是主机本地的路径,那么会报跨域错误 

案例 

运行这次代码的时候的报错:Uncaught TypeError TypeError: Failed to fetch

按照这个文章里的第一个方法解决:(80条消息) d3.csv()读取本地文件失败_报错Access to XMLHttpRequest at ‘file:‘ from origin ‘null‘ has been blocked_替换和解决方法_Jude_zhai的博客-CSDN博客

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scatter-Simple</title>
  </head>
  <body style="text-align: center">
    <svg width="1650" height="920" id="mainsvg" class="svgs" style="background-color: #ffffff;"></svg>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script src="d3.min.js"></script>
    <script>
        const svg = d3.select('#mainsvg');
        const width = +svg.attr('width');
        const height = +svg.attr('height');
        const margin = {top: 100, right: 120, bottom: 100, left: 120};
        const innerWidth = width - margin.left - margin.right;
        const innerHeight = height - margin.top - margin.bottom;
        let xScale, yScale;
        const xAxisLabel = '累计确诊人数(对数)';
        const yAxisLabel = '新增人数(对数)';
        let alldates;
        let sequantial;
        let aduration = 1000;
        let xValue = d => Math.log(d['确诊人数'] + 1);
        let yValue = d => Math.log(d['新增确诊'] + 1); 

        var color = {
            "武汉":"#ff1c12",
            "黄石": "#de5991",
            "十堰": "#759AA0",
            "荆州": "#E69D87",
            "宜昌": "#be3259",
            "襄阳": "#EA7E53",
            "鄂州": "#EEDD78",
            "荆门": "#9359b1",
            "孝感": "#47c0d4",
            "黄冈": "#F49F42",
            "咸宁": "#AA312C",
            "恩施州": "#B35E45",
            "随州": "#4B8E6F",
            "仙桃": "#ff8603",
            "天门": "#ffde1d",
            "潜江": "#1e9d95",
            "神农架": "#7289AB"
        }

        const renderinit = function(data){
            // Linear Scale: Data Space -> Screen Space; 
            xScale = d3.scaleLinear()
            .domain([d3.min(data, xValue), d3.max(data, xValue)]) 
            .range([0, innerWidth])
            .nice();

            // Introducing y-Scale; 
            yScale = d3.scaleLinear()
            // d3.extent()计算数组的最小值和最大值 返回的是数组 纵轴起始点原本是左上角 需要reverse一下
            .domain(d3.extent(data, yValue).reverse()) 
            .range([0, innerHeight])
            .nice(); //将定义域的刻度扩展整齐

            // 可作图区域的容器
            const g = svg.append('g')
            .attr('transform', `translate(${margin.left}, ${margin.top})`)
            .attr('id', 'maingroup');

            // Adding axes; 
            const yAxis = d3.axisLeft(yScale)
            .tickSize(-innerWidth) //设置刻度线长度
            //.tickPadding(10); // .tickPadding is used to prevend intersection of ticks; 
            const xAxis = d3.axisBottom(xScale)
            .tickSize(-innerHeight)
            //.tickPadding(10);

            let yAxisGroup = g.append('g').call(yAxis)
            .attr('id', 'yaxis');
            yAxisGroup.append('text')
            .attr('font-size', '2em')
            .attr('transform', `rotate(-90)`)
            .attr('x', -innerHeight / 2)
            .attr('y', -60)
            .attr('fill', '#333333')
            .text(yAxisLabel)
            .attr('text-anchor', 'middle') // Make label at the middle of axis. 
            //yAxisGroup.selectAll('.domain').remove(); // we can select multiple tags using comma to seperate them and we can use space to signify nesting; 
            
            let xAxisGroup = g.append('g').call(xAxis)
            .attr('transform', `translate(${0}, ${innerHeight})`)
            .attr('id', 'xaxis');
            xAxisGroup.append('text')
            .attr('font-size', '2em')
            .attr('y', 60)
            .attr('x', innerWidth / 2)
            .attr('fill', '#333333')
            .text(xAxisLabel);
            //xAxisGroup.selectAll('.domain').remove();
        };
        

        const renderUpdate = function(seq){
            const g = d3.select('#maingroup');
            let circleupdates = g.selectAll('circle').data(seq, d => d['地区']);
            

            let circleenter = circleupdates.enter().append('circle')
            .attr('cx', d => xScale(xValue(d))) //横坐标
            .attr('cy', d => yScale(yValue(d))) //纵坐标
            .attr('r', 30) //半径
            .attr('fill', d => color[d['地区']]) //颜色
            .attr('opacity', 0.8) 


            circleupdates.merge(circleenter)
            .transition().ease(d3.easeLinear).duration(aduration)
            .attr('cx', d => xScale(xValue(d)))
            .attr('cy', d => yScale(yValue(d)));

            //日期修改
            time = seq[0]['日期'];
            g.selectAll('.date_text').remove();
            g.append("text")
            .data(['seq']) 
            .attr('class', 'date_text')
            .attr("x", innerWidth / 4 + 150)
            .attr("y", - 20)
            .style("text-anchor", "end")
            .attr("fill", "#504f4f")
            .attr('font-size', '6em')
            .attr('font-weight', 'bold')
            .text(time);

            textupdates = g.selectAll('.province_text').data(seq);
            textenter = textupdates.enter().append('text')
            .attr("class", "province_text")
            .attr("x", (datum) => { return xScale(xValue(datum)); })
            .attr("y", (datum) => { return yScale(yValue(datum)); })
            .attr("dy", "1em")
            .style("text-anchor", "middle")
            .attr("fill", "#333333")
            //.attr('opacity', 0)
            .text(function(d,i){ 
                return d['地区']
            })

            textupdates.merge(textenter).transition().ease(d3.easeLinear).duration(aduration)
            .attr('x', (datum) => { 
                return xScale(xValue(datum)); })
            .attr('y', (datum) => { return yScale(yValue(datum)); });
        }

        /*--------------------------------------------数据处理--------------------------------------------------*/
        d3.csv("hubeinxt.csv").then( data => {
            //数据过滤
            data = data.filter( d => d['地区'] !== '总计' );
            data.forEach( d => {
                //将目标数据转换成数值
                d['确诊人数'] = +(d['确诊人数']);
                d['新增确诊'] = +(d['新增确诊']);
                //异常数据处理
                if( d['新增确诊'] < 0 ){
                    d['新增确诊'] = 0;
                }
            } )

            //set去掉重复日期
            alldates = Array.from( new Set(data.map( d => d['日期']) )); 

            //日期的排序 从早到晚排序
            alldates = alldates.sort( (a,b) => {
                return new Date(a) - new Date(b);
            } );

            //构造每一天数据的二维数组
            sequantial = []; 
            alldates.forEach( d => {
                sequantial.push([])
            } );
            data.forEach( d => {
                //根据alldates中日期的索引,将data中日期相同的数据放在sequantial同一个数组
                sequantial[ alldates.indexOf(d['日期'])].push(d);
            } );
            renderinit(data);

            let c = 0;
            let intervalId = setInterval( () => {
                if( c >= alldates.length ){
                    clearInterval(intervalId);
                }else{
                    renderUpdate(sequantial[c]);
                    c = c + 1;
                }
            }, aduration)

            console.log(sequantial);
        } )

    </script>
  </body>
</html>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/455221.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跨境电商服务简单说明

​ 前言 跨境电商服务是指通过互联网平台进行国际贸易的一种新型商业模式&#xff0c;涉及跨境物流、跨境支付、跨境电商平台等多个领域。随着全球化的不断推进和消费者需求的不断变化&#xff0c;跨境电商服务行业呈现出快速发展的趋势。 发展背景 跨境电商服务行业的发展背景…

基于ArcGIS Pro、R、INVEST等多技术融合下生态系统服务权衡与协同动态分析

生态系统服务是指生态系统所形成的用于维持人类赖以生存和发展的自然环境条件与效用&#xff0c;是人类直接或间接从生态系统中得到的各种惠益。联合国千年生态系统评估&#xff08;Millennium ecosystem assessment&#xff0c;MA&#xff09;提出生态系统服务包括供给、调节、…

JavaScript 函数调用和JavaScript 闭包

文章目录 一、JavaScript 函数调用二、JavaScript 闭包总结 一、JavaScript 函数调用 JavaScript 函数有 4 种调用方式。 每种方式的不同在于 this 的初始化。 this 关键字 一般而言&#xff0c;在Javascript中&#xff0c;this指向函数执行时的当前对象。 注意 this 是保留…

美创科技首届渠道高峰论坛| 两大分论坛亮点汇聚

4月22日&#xff0c;美创科技首届渠道高峰论坛在海南三亚隆重举行&#xff0c;本届高峰论坛以“新起点 新战略 共赢数安蓝海”为主题&#xff0c;全国各地200余家合作伙伴齐聚。当日下午&#xff0c;行业分论坛、技术分论坛两大论坛以及圆桌会议&#xff0c;多方视角、全方位共…

C++篇----auto、内联函数、函数重载

文章目录 一、auto二、内联函数&#xff08;inline)三、函数重载 一、auto auto在c中是会根据等号右边表达式自动推导等号左边的类型 #include<iostream> using namespace std;int main() {int a 0;auto b a;double c 1.1;auto d c;//打印类型typeid().name()cout &l…

OpenGL与Metal API的Point Sprite

我们在实际用OpenGL等3D图形渲染API时 点图元 往往用得不多&#xff0c;而在粒子系统中可能也是用一个正方形来绘制一单个粒子。不过在当前大部分3D图形渲染API中都能支持用点图元来绘制一个具有纹理贴图的粒子&#xff0c;从早在OpenGL 1.4开始就能支持了&#xff0c;而在Open…

机器学习:基于逻辑回归(Logistic Regression)对股票客户流失预测分析

基于逻辑回归对股票客户流失预测分析 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1…

npm install报错

出现这个错误&#xff0c;我百度之后得到的解决方案是&#xff1a; 在node.js安装目录下找到node_modules文件夹并删除 但是当我操作完成之后&#xff0c;却出现了另外一个ERROR&#xff1a; 于是我又还原了原来的node_modules文件夹&#xff0c;于是又报一开始的错 仔细瞅瞅…

Netty 单机百万连接测试

1.Netty框架简介 1.1.Netty简介 netty是jboss提供的一个java开源框架&#xff0c;netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可用性的网络服务器和客户端程序。也就是说netty是一个基于nio的编程框架&#xff0c;使用netty可以快…

NFC 学习笔记 5 MFRC522读写器2 NDEF

NDEF简介 NDEF&#xff08;NFC Data Exchange Format&#xff09;是一种标准化的数据格式&#xff0c;用于将数据存储在NFC标签或智能手机中。该格式是NFC论坛定义的&#xff0c;目的是在不同的NFC设备之间交换信息。 NDEF格式可以存储各种类型的数据&#xff0c;例如URL、文本…

面对市场内卷,不同品牌应该如何做客户增长?

后疫情时代&#xff0c;我国新生人口减少、人口老龄化加剧&#xff0c;chatgpt火爆和AI替代论盛行&#xff0c;市场上&#xff0c;口红效应依旧繁荣&#xff0c;消费者的延迟满足、替代性满足成为常见心理&#xff0c;面对宏观的不确定性&#xff0c;人们在消费上更需要确定性的…

github 基础

github 基础 前面讲了 git 的基本使用&#xff0c;这里简单的提一下 github 的基本使用&#xff0c;主要还是 pull 和 push 两个部分。其中 pull 好像有了一些变化&#xff0c;现在似乎是需要 rebase 而不是自动就帮你做了……&#xff1f;不过 rebase 的部分之后再提。 当然…

Vuex实现数据共享

目录 一&#xff1a;index.js的创建 二&#xff1a;index.js的引入 三&#xff1a;Count.vue 四&#xff1a;App.vue的使用 五&#xff1a;mapstate等的使用 五&#xff1a;多组件数据共享&#xff08;模块化编程&#xff09; vc通过dispatch联系actions&#xff0c;acti…

Python小姿势 - ###### 随机选取的知识点:Python日期时间处理

随机选取的知识点&#xff1a;Python日期时间处理 Python日期时间处理&#xff1a;一种更简单的方式 日期和时间处理是许多程序中必不可少的部分。Python提供了一个标准库来处理日期和时间&#xff0c;这个库叫做datetime&#xff0c;它提供了一些类来处理不同的日期和时间格式…

远程访问及控制(SSH)

远程访问及控制&#xff08;SSH&#xff09; 一、SSH远程管理二、SSH服务1、ssh远程登录方式2、scp远程复制3、sftp安全FTP4、sshd配置文件5、ssh密钥对配置5.1 ssh密钥对免交互登录 三、TCP wrappers 访问控制1、**TCP wrappers &#xff08;TCP封套&#xff09;**2、**TCP wr…

会话与会话技术(Cookie)

Web应用中的会话过程指的是一个客户端&#xff08;浏览器&#xff09;与Web服务器之间连续发生的一系列请求和响应过程 为保存会话过程产生的数据&#xff0c;Servlet提供了两个用于保存会话数据的对象&#xff0c;分别是Cookie和Session 1、Cookie对象 Cookie是一种会话技术…

SS524V100 RTL8152B(USB转网卡)驱动移植

目录 前言 1. 内核下 USB Host 配置过程 2. 内核下 RTL8152 驱动配置 3. 重新编译内核 4. 测试USB转网卡 5. 总结 前言 本文主要是描述 SS524V100 对 RTL8152B(百兆网卡) 开发、移植的过程。 1. SS524V100 的 USB 2.0 支持 Host 模式&#xff1b; 2. 内核默认自带驱动…

0环境教你怎么安装配置GPU环境运行车流量检测代码

项目效果&#xff1a; python车流量检测双向车流计数 1、环境配置 1.1 安装显卡加速工具 (1) 安装CUDA和cudnn NVIDIA CUDA 深度神经网络库 (cuDNN) 是经 GPU 加速的深度神经网络基元库。cuDNN 可大幅优化标准例程&#xff08;例如用于前向传播和反向传播的卷积层、池化层、…

4月23日作业

#include <iostream> #include <cstring> using namespace std; class Student //学生类 { private: string name; //姓名 int year; //年龄 double sorce; //分数 public: Student (){} //无参构造 Student(string a,int b,double c):name(a),y…

五分钟学会在微信小程序中使用 vantUI 组件库

前言 我们在开发微信小程序时&#xff0c;设计和实现好用的用户界面无疑是至关重要的一步。但是微信小程序官方自带的 UI 组件库无法满足很多使用场景&#xff0c;这个时候就需要我们使用一些第三方的 UI 组件库。而 vant Weapp 作为一款优秀的前端 UI 组件库&#xff0c;可以帮…