数据可视化【六】Line Chart && Area Chart

Line Chart

vizhub代码:

https://vizhub.com/Edward-Elric233/094396fc7a164c828a4a8c2e13045308

实现效果:
在这里插入图片描述
这里先使用d3.line()设置每个点的x坐标和y坐标,然后再用这个东西设置path'd'属性,就可以得到曲线。

const lineGenerator = d3.line()
   .x(d => xScale(xValue(d)))
   .y(d => yScale(yValue(d)))
   .curve(d3.curveBasis); //使得曲线比较光滑

g.append('path')
   .attr('class', 'line-path')
   .attr('d', lineGenerator(data));

index.html

<!DOCTYPE html>
<html>

<head>
    <title>Temperature in San Francisc Line Chart</title>
    <link rel="stylesheet" href="./styles.css">
    <script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
    <!-- find D3 file on UNPKG d3.min.js-->
</head>

<body>
    <svg width="960" height="500"></svg>
    <script src="./index.js">
        // console.log(d3); test whether you have imported d3.js or not
    </script>

</body>

</html>

html.js

const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');

const render = data => {
    const title = 'A week in San Francisco';
    const xValue = d => d.timestamp;
    const xAxisLabel = 'Time';
    const yValue = d => d.temperature;
    const yAxisLabel = 'Temperature';
    const margin = { top: 60, right: 20, bottom: 80, left: 100 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const circleRadius = 6;

    const xScale = d3.scaleTime()
        //.domain([min(data, xValue), max(data, xValue)])	//和下面的写法等价
        .domain(d3.extent(data, xValue))
        .range([0, innerWidth])
        .nice(); //作用是如果值域的最大值不够整齐可以变得整齐


    // const yScale = scaleBand()
    const yScale = d3.scaleLinear()
        .domain([d3.max(data, yValue), d3.min(data, yValue)])
        .range([0, innerHeight])
        .nice();

    //const xAxisTickFormat = number => format('.3s')(number).replace('G','B');

    const yAxis = d3.axisLeft(yScale)
        .tickSize(-innerWidth)
        .tickPadding(15);
    const xAxis = d3.axisBottom(xScale)
        //.tickFormat(xAxisTickFormat)
        .tickSize(-innerHeight) //设置tick-line的长度
        .tickPadding(15); //通过设置Padding让x轴的数字离远一点



    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    //yAxis(g.append('g'));
    const yAxisG = g.append('g').call(yAxis);
    yAxisG.selectAll('.domain').remove();

    yAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', -70)
        .attr('x', -innerHeight / 2)
        .attr('fill', 'black')
        .attr('transform', `rotate(-90)`)
        .attr('text-anchor', 'middle') //设置锚点在中心
        .text(yAxisLabel);

    const xAxisG = g.append('g').call(xAxis)
        .attr('transform', `translate(0,${innerHeight})`);
    xAxisG.selectAll('.domain').remove();

    xAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', 60)
        .attr('x', innerWidth / 2)
        .attr('fill', 'black')
        .text(xAxisLabel);

    let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];

    const createGetColor = (idx) => {
        var i = idx || -1;
        return {
            get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
        };
    };

    const getColor = createGetColor();

    const lineGenerator = d3.line()
        .x(d => xScale(xValue(d)))
        .y(d => yScale(yValue(d)))
        .curve(d3.curveBasis); //使得曲线比较光滑

    g.append('path')
        .attr('class', 'line-path')
        .attr('d', lineGenerator(data));
    /*
    g.selectAll('circle').data(data)
        .enter().append('circle')
            .attr('cy', d=>yScale(yValue(d)))
            .attr('cx', d => xScale(xValue(d)))
            .attr('r', circleRadius)
            .attr('fill', 'red');
    */
    g.append('text')
        .attr('class', 'title')
        .attr('y', -20)
        .attr('x', innerWidth / 2)
        .attr('text-anchor', 'middle')
        .text(title);
};

d3.csv('https://vizhub.com/curran/datasets/temperature-in-san-francisco.csv').then(data => {
    // console.log(data);
    data.forEach(d => {
        //得到的数据默认每个属性的值都是字符串,因此需要进行转换
        d.temperature = +d.temperature;
        d.timestamp = new Date(d.timestamp);
    });
    render(data);
});

styles.css

body {
    margin: 0px;
    overflow: hidden;
    font-family: manosapce;
}

circle {
    opacity: 0.5;
}

text {
    font-family: sans-serif;
}

.tick text {
    font-size: 2em;
    fill: #8E8883
}

.tick line {
    stroke: #E5E2E0
}

.axis-label {
    fill: #8E8883;
    font-size: 2.5em
}

.title {
    font-size: 3em;
    fill: #8E8883
}

.line-path {
    fill: none;
    stroke: steelblue;
    stroke-width: 5;
    stroke-linejoin: round /*使得曲线比较光滑*/
}

其实也可以在折现图上加上点,只需要去掉原本散点图的注释就可以了。但是我觉得这样不好看就没有加上。

Area Chart

vizhub代码:

https://vizhub.com/Edward-Elric233/9fa9b8c649cf41a3afcde6e185a72cca

https://vizhub.com/Edward-Elric233/39790021eded4d398be6f97726e73dd2

area图只需要把使用line的地方换成area即可。不同的地方在于area需要设置y0,y1,y用来划分区域,而且需要设置pathfill属性,用来表示区域的颜色。一般来讲应该不需要设置线的strokestroke-width属性。

例如把上面的图变成Area Chart
在这里插入图片描述
需要修改的js代码如下:

const areaGenerator = area()
  	.x(d => xScale(xValue(d)))
  	.y1(d=>yScale(yValue(d)))
  	.y0(innerHeight)
  	.curve(curveBasis);	//使得曲线比较光滑
  
  g.append('path')
  	.attr('class', 'line-path')
  	.attr('d', areaGenerator(data));

这里还画了一个图,把网格提到了图形的前面。
在这里插入图片描述
虽然有些丑,但是如果需要使用的话还是可以的。技巧就是先生成Area图,然后再生成坐标轴就可以了。这样坐标线就会显示在图形的上面。

index.html

<!DOCTYPE html>
<html>

<head>
    <title>World Population Area Chart</title>
    <link rel="stylesheet" href="./styles.css">
    <script src="https://unpkg.com/d3@5.7.0/dist/d3.min.js"></script>
    <!-- find D3 file on UNPKG d3.min.js-->
</head>

<body>
    <svg width="960" height="500"></svg>
    <script src="./index.js">
        // console.log(d3); test whether you have imported d3.js or not
    </script>

</body>

</html>

index.js

const svg = d3.select('svg');
// svg.style('background-color', 'red'); test
const width = +svg.attr('width');
const height = +svg.attr('height');

const render = data => {
    const title = 'World Population';
    const xValue = d => d.year;
    const xAxisLabel = 'Year';
    const yValue = d => d.population;
    const yAxisLabel = 'Population';
    const margin = { top: 60, right: 20, bottom: 80, left: 100 };
    const innerWidth = width - margin.left - margin.right;
    const innerHeight = height - margin.top - margin.bottom;
    const circleRadius = 6;

    const xScale = d3.scaleTime()
        //.domain([min(data, xValue), max(data, xValue)])	//和下面的写法等价
        .domain(d3.extent(data, xValue))
        .range([0, innerWidth])
        //.nice();	//作用是如果值域的最大值不够整齐可以变得整齐


    // const yScale = scaleBand()
    const yScale = d3.scaleLinear()
        .domain([d3.max(data, yValue), 0])
        .range([0, innerHeight])
        .nice();

    const yAxisTickFormat = number => d3.format('.1s')(number).replace('G', 'B');

    const yAxis = d3.axisLeft(yScale)
        .tickFormat(yAxisTickFormat)
        .tickSize(-innerWidth)
        .tickPadding(15);
    const xAxis = d3.axisBottom(xScale)
        //.tickFormat(xAxisTickFormat)
        .ticks(10) //设置标签的多少,不知道为什么如果设置为10就会很乱,可能是因为这是一周的时间,如果划分成10个以上就需要显示小时吧
        .tickSize(-innerHeight) //设置tick-line的长度
        .tickPadding(15); //通过设置Padding让x轴的数字离远一点



    const g = svg.append('g')
        .attr('transform', `translate(${margin.left},${margin.top})`);

    const areaGenerator = d3.area()
        .x(d => xScale(xValue(d)))
        .y1(d => yScale(yValue(d)))
        .y0(innerHeight)
        .curve(d3.curveBasis); //使得曲线比较光滑

    g.append('path')
        .attr('class', 'line-path')
        .attr('d', areaGenerator(data));

    //yAxis(g.append('g'));
    const yAxisG = g.append('g').call(yAxis);
    yAxisG.selectAll('.domain').remove();

    yAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', -70)
        .attr('x', -innerHeight / 2)
        .attr('fill', 'black')
        .attr('transform', `rotate(-90)`)
        .attr('text-anchor', 'middle') //设置锚点在中心
        .text(yAxisLabel);

    const xAxisG = g.append('g').call(xAxis)
        .attr('transform', `translate(0,${innerHeight})`);
    xAxisG.selectAll('.domain').remove();

    xAxisG.append('text')
        .attr('class', 'axis-label')
        .attr('y', 60)
        .attr('x', innerWidth / 2)
        .attr('fill', 'black')
        .text(xAxisLabel);

    let colorSet = ['#eb2617', '#ffaa00', '#4dff00', '#00fbff', '#bb00ff', '#eeff00'];

    const createGetColor = (idx) => {
        var i = idx || -1;
        return {
            get: () => { i = (i + 1) % colorSet.length; return colorSet[i]; }
        };
    };

    const getColor = createGetColor();


    /*
    g.selectAll('circle').data(data)
        .enter().append('circle')
            .attr('cy', d=>yScale(yValue(d)))
            .attr('cx', d => xScale(xValue(d)))
            .attr('r', circleRadius)
            .attr('fill', 'red');
    */
    g.append('text')
        .attr('class', 'title')
        .attr('y', -20)
        .attr('x', innerWidth / 2)
        .attr('text-anchor', 'middle')
        .text(title);
};

d3.csv('https://vizhub.com/curran/datasets/world-population-by-year-2015.csv').then(data => {
    console.log(data);
    data.forEach(d => {
        //得到的数据默认每个属性的值都是字符串,因此需要进行转换
        d.population = +d.population;
        d.year = new Date(d.year);
    });
    render(data);
});

styles.css

body {
    margin: 0px;
    overflow: hidden;
    font-family: manosapce;
}

circle {
    opacity: 0.5;
}

text {
    font-family: sans-serif;
}

.tick text {
    font-size: 2em;
    fill: #8E8883
}

.tick line {
    stroke: #E5E2E0
}

.axis-label {
    fill: #8E8883;
    font-size: 2.5em
}

.title {
    font-size: 3em;
    fill: #8E8883
}

.line-path {
    fill: #42A5B3;
    /*   stroke : blue;
    stroke-width : 5; */
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值