ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

D3基本图表绘制——折线图

2022-02-02 17:03:04  阅读:242  来源: 互联网

标签:attr g1 元素 50 图表 折线图 line D3 append


 制作折线图分成4步走:

1.首先划定制图区域和范围——画一个边框

2.数据处理得到绘制折线图需要的数据——绘制折线需要一个数组整体

3.画出x,y轴和折线——y轴绘制需要注意

4.补充标签,调节位置

【1】第一步:框架绘制(规定范围)

<body>
    <div style="height:700px ;
                width: 1000px; 
                border: 2px solid grey;
                margin-top: 20px;
                margin-left: 200px;
                position: relative;
                float: left;
                overflow: auto;">
        <svg id="line" style="height:700px ; 
                width: 1000px;
                position: relative;
                float: left;">
    </svg>
    </div>
</body>

补充关于position的知识:

文档流:即元素在html中按照从左到右、从上到下的正常排序顺序

其中块级元素从上到下一行行排,内联元素按照从左到右行内排序

区分position中绝对定位和相对定位:

relative:

1.相对于文档流正常位置偏移,宽高不变化,撑大容器。

2.设置以后仍然处于文档流且不影响其他元素布局,其他元素相对于设置了relative的元素的正常位置布局

Absolute:

1.设置后其宽度若没有定义,会按照里面元素内容确定其宽度

2.其定位根据父元素定位,<div>  <div></div>  </div>最外面的就是父元素

如果父元素没有或者没有设置绝对定位或者相对定位的话,那么元素相对于html元素定位

如果父元素设置了绝对定位或者相对定位,那么元素根据最近的父元素定位

3. absolute脱离文档流,原来的位置是空的,下面的元素会来占据位置。

Tip:没有position,float设置topleftbottomright值都没有效

更详细的示例推荐:CSS position 相对定位和绝对定位 | 菜鸟教程 (runoob.com) }

盒子模型相关知识补充:

Tip:与position一起出现的问题:

可能容易混淆的关于x,y属性概念

以y属性为例,大多数时候,它体现了引用元素的矩形区域的左上角的y轴坐标

采用模块化编程:利用const line={myline:function(){  }}与main.js调用line.myline()

导入数据:利用d3.json导入数据或者d3.csv

插入g标签——g标签用于分组问题,专门用于svg标签下,没有x,y属性,移动使用transform,也无width、height、fill属性

【2】第二步:数据处理

绘制折线图需要的数据(联系下文将提到的path()):

数组——内部元素是字典或者数组或者别的对象等(如图所示)

data=[{'time': ,'number': },{'time': ,'number': }]
data=[[2,5],[6,10],[6,8]]

补充js中字典的知识

字典存储形式:dic={key1 :value1,key2:value2,…}

字典中的键是值在字典中的索引

//输出最初的字典元素

for(let k in dic){

Console.log(“key:”+key+”,value”+dic[key])};

}

//字典元素按照key排序

Var res=object.keys(dic).sort()-一个一个符号比较,非正统大小比较

//添加字典元素

dataset['set']=dic[i]

Object.keys()会返回一个由一个给定对象的自身可枚举属性组成的数组

建立字典数组,获取可处理数据:

dataset=[ ]

Dataset.push({‘time’:k,’number’:dic[k]})

另外补充下关于数据需要去重的方法,如何处理:

此处可以通过引入对象来处理,因为对象内部元素不可重复

Let data={}

       For(let i=0;i<d.length;i++){

       Data[d[i][‘first name’]]=0

}

       Let x_names=object.keys(data)

【3】第三步:绘制x,y轴与折线

比例尺利用:

如果是线性关系,使用scaleLinear;如果是非连续关系,使用scaleBand,domain为x轴上显示的数值等,range使用连续域,Padding设置关于间隔,padding(1)是点,值必须在【0,1】范围内

建立坐标轴:使用AxisBottom( )或AxisLeft( )等,其中参数是配置的比例尺,

const x_scale=d3.scaleBand().domain(x).range([0,800]).padding(1)
//此处x是一个数组,x=['Jan-21',……]
const y_scale=d3.scaleLinear().domain([8000,24000]).range([500,0])
//此处需要特别关注y轴比例尺range的设置,因此处y轴为朝下,而非数学中朝上,所以如果range为([0,500]),旋转之后会导致从上到下,为由小到大,所以需要改为range([500,0])
const xAxis=d3.axisBottom(x_scale)
const yAxis=d3.axisLeft(y_scale)

g1.append('g')
.call(xAxis)
.attr('transform','translate(' + 50 + ',' + 600 + ')')
.attr('fill','black')

g1.append('g')
.call(yAxis)
.attr('transform','translate(' + 50 + ',' + 100 + ')')
//关注此处的y坐标,因为本身range=>500,所以仅用向下100即可
.attr('fill','black')

利用line和path进行折线的绘制:

line()用于制定数据引用和线段基本信息

Const line=d3.line().x(d=>xscale(d.time)+50).y(d=>yscale(d.number))

path用于绘制折线

g1.append('path')
            .datum(avg)
            .attr('d',line)
            .attr('fill','none')
//这里需要注意其fill一定为none,不然会导致三角面片显示出来
            .attr('stroke','blue')

我当时学习的时候对datum()这个函数有疑惑,因为这个函数绑定的为一个数值;而data()绑定的是一个数组,为什么不用data()?我请教了一下师兄,得到了理解的答案,有同样疑惑的同学可看下面解惑。

data()用于将数组中每个元素绑定到对应的物体上,从而生成对应数据和数量的物体,这些“一个个”物体之间是彼此分离的,

datum()用于将一个数据绑定到一个元素上,而此处我们画的折线是一条折线,虽然上面有很多个点,但是它是一个整体元素,而不是“一个个”元素。

因此我们使用datum(),将该数据绑定到元素上面之后,这个数组内部包含了一系列的点(x,y)来确定一整条线的位置,从而得到一条线

如果使用data(),应该得到许多条线,而且该参数应当是一个二维数组

【4】第四步:补充标注标签,调节位置

我画的这张图上面有两条线段,我使用颜色对它们区分,因此需要标注两条直线区分,这里再介绍另外一种画线的方法,也是最原始的一种画法

g1.append('line')
.attr('x1',50+500)
.attr('y1',80)
.attr('x2',50+510)
.attr('y2',80)
.attr('stroke','blue')
.attr('fill','none')
            

添加文本标签:

g1.append('text').attr('x',50+515).attr('y',80).text('每月平均用户数量')
g1.append('text').attr('x',50+515).attr('y',95).text('每月峰值用户数量')

附上我绘制的折线图及代码

const line={
    myLine:function(){
        d3.csv("../data/AllSteamData.csv").then((value)=>{
            //console.log(value)——一般先确认调试一下
            let g1=d3.select('#line').append('g').attr('transform','translate(' + 20 + ',' + 20 + ')')
            //利用字典中按照key值自动排序的性质,处理得到x轴时间,排序顺序为按21年一月份到近30天
            let x_times={}
            for(let i=0;i<10;i++){
                x_times[13-i]=value[i]['Month']
                }
            let x=[]
            for(var k in x_times){
                x.push(x_times[k])
            }
            //处理得到avg和peak字典数组,用于折线图两条折线绘制
            let avg=[]
            let peak=[]
            for(let i=0;i<10;i++){
                avg.push({'time':x[i],'number':value[9-i]['Avg. Players']})
                peak.push({'time':x[i],'number':value[9-i]['Peak Players']})
            }
            //console.log(avg)
            //console.log(peak)
            //console.log(x)
            //处理完成数据需要调试验证一下有无错误

            //绘制比例尺和坐标轴
            const x_scale=d3.scaleBand().domain(x).range([0,800]).padding(1)
            const y_scale=d3.scaleLinear().domain([8000,24000]).range([500,0])

            const xAxis=d3.axisBottom(x_scale)
            const yAxis=d3.axisLeft(y_scale)

            g1.append('g').call(xAxis).attr('transform','translate(' + 50 + ',' + 600 + ')').attr('fill','black')
            g1.append('g').call(yAxis).attr('transform','translate(' + 50 + ',' + 100 + ')').attr('fill','black')

            //绘制折线,制定折线关系函数
            const line=d3.line().x((d)=>x_scale(d.time)+50).y((d)=>y_scale(d.number)+100)
            //这里需要注意一下y轴的坐标,因为range对应([500,0])
            //所以该点对应的图像的y轴增加仅需要和y轴坐标轴的增加一致即可
            g1.append('path')
            .datum(avg)
            .attr('d',line)
            .attr('fill','none')
            //这里需要注意其fill一定为none,不然会导致三角面片显示出来
            .attr('stroke','blue')

            g1.append('path')
            .datum(peak)
            .attr('d',line)
            .attr('fill','none')
            .attr('stroke','green')

            //绘制标签
            g1.append('text').attr('x',250+50).attr('y',10).text('2021年Counter-Strike游戏用户数量变化图')
            g1.append('text').attr('x',40).attr('y',80).text('数量')
            g1.append('text').attr('x',50+850).attr('y',600).text('时间')
            g1.append('line').attr('x1',50+500).attr('y1',80).attr('x2',50+510).attr('y2',80).attr('stroke','blue').attr('fill','none')
            g1.append('line').attr('x1',50+500).attr('y1',95).attr('x2',50+510).attr('y2',95).attr('stroke','green').attr('fill','none')
            g1.append('text').attr('x',50+515).attr('y',80).text('每月平均用户数量')
            g1.append('text').attr('x',50+515).attr('y',95).text('每月峰值用户数量')

    })
}
}

 

标签:attr,g1,元素,50,图表,折线图,line,D3,append
来源: https://blog.csdn.net/m0_63150077/article/details/122769874

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有