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

 制作折线图分成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) }

盒子模型相关知识补充:

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

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('每月峰值用户数量')

    })
}
}

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

 

上一篇:第一个scilab程序


下一篇:python:cmd+zeromq