D3 -折线统计图

数据来自csv文件。

绘制效果图:
在这里插入图片描述

图片一共由几个部分构成:

  1. 横纵两个坐标轴,横轴为月份编号,纵轴是光照时间。
  2. 中间主体部分是折线,由svg的Path绘制,其中数据坐标点为svg的circle元素。
  3. 右上部分是图例,代表不同颜色代表的城市信息,城市纬度。颜色深浅程度代表纬度的高低。
    // 构造比例尺
    xScale = d3.scaleLinear()
        .domain([1, 12])
        .range([0, w - inner.left - inner.right])
        .nice();

    xAxis = d3.axisBottom(xScale);

    yScale = d3.scaleLinear()
        .domain([0, 400])
        .range([h - inner.top - inner.bottom, 0])
        .nice();

    yAxis = d3.axisLeft(yScale);

绘制横轴和纵轴的构造

    // 解析csv数据
    d3.csv("sunshine.csv").then(function (d) {
        console.log(d);
        Data = d;
        draw();
    });

解析csv数据,js的代码不是顺序执行的,而是异步的。在加载完csv文件后才去执行后面的内容,将解析后的数据放到d中作为参数来传递,此时d为数组元素。draw为后续的绘制操作。

完整代码:

<script src="https://d3js.org/d3.v5.js"></script>
<script>

    let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    w *= 0.98;
    h *= 0.75;

    let inner = {top: 50, right: 100, bottom: 50, left: 100};
    let xScale, yScale;
    let xAxis, yAxis;
    let Data = new Array();

    let svg = d3.select("body")
        .append("svg")
        .attr("width", w)
        .attr("height", h)
        .append("g");

    // 构造比例尺
    xScale = d3.scaleLinear()
        .domain([1, 12])
        .range([0, w - inner.left - inner.right])
        .nice();

    xAxis = d3.axisBottom(xScale);

    yScale = d3.scaleLinear()
        .domain([0, 400])
        .range([h - inner.top - inner.bottom, 0])
        .nice();

    yAxis = d3.axisLeft(yScale);

    // 解析csv数据
    d3.csv("sunshine.csv").then(function (d) {
        console.log(d);
        Data = d;
        draw();
    });

    function draw() {

        svg.append("g")
            .attr("transform", "translate(" + inner.left + "," + (h - inner.bottom) + ")")
            .call(xAxis);

        svg.append("g")
            .attr("transform", "translate(" + inner.left + "," + inner.top + ")")
            .call(yAxis);

        let Color = new Array();
        let H = h - inner.top - inner.bottom;
        let LineData = new Array();
        let City = new Array();
        let ct = -1, p = 0;

        // 画线函数
        let Line = d3.line()
            .x(function (d) {
                return d.x;
            })
            .y(function (d) {
                return d.y;
            });

        // 解析数据,获取城市名称,生成颜色,构造折线数据等
        for (let i = 0; i < Data.length; ++i) {
            if (i === 0 || Data[i].city !== Data[i - 1].city) {
                ++ct;
                City[ct] = Data[i].city;
                Color[ct] = 'rgba(' + (((ct + 1) / 6) * 128) + ',' + (((ct + 1) / 6) * 255) + ',' + 255 + ',0.8)';
                p = 0;
                LineData[ct] = new Array();
            }
            LineData[ct][p] = ({
                "x": (inner.left + ((w - inner.left - inner.right) / 11) * Data[i].monthnum),
                "y": (-inner.bottom + h - H * (Data[i].sunshine) / 400)
            });
            ++p;
        }

        // console.log(Color);
        for (let i = 0; i <= ct; ++i) {

            // 绘制路径
            svg.append("path")
                .attr("d", Line(LineData[i]))
                .attr("stroke", function () {
                    return Color[i];
                })
                .attr("stroke-width", function () {
                    return 3.5;
                })
                .attr("fill", "none");

            // 用圆圈标记每个点的位置
            svg.append("g")
                .selectAll("circle")
                .data(LineData[i])
                .enter()
                .append("circle")
                .attr("fill", function (d) {
                    return Color[i];
                })
                .attr("cx", function (d) {
                    return d.x;
                })
                .attr("cy", function (d) {
                    return d.y;
                })
                .attr("r", 3);
        }

        // 画线段函数
        function drawLine(x1, y1, x2, y2, l = 1, c = "black") {
            svg.append("line")
                .attr("x1", x1)
                .attr("y1", y1)
                .attr("x2", x2)
                .attr("y2", y2)
                .attr("stroke-width", l)
                .attr("stroke", c);
        }

        // 添加文本的函数
        function drawText(x, y, s, l = '12px', c = 'black') {
            svg.append('text')
                .attr('x', x)
                .attr('y', y)
                .style('fill', c)
                .style('font-size', l)
                .text(s);
        }

        drawText(w - inner.right * 0.9, h - inner.bottom * 0.9, 'monthnum');
        drawText(inner.left * 0.75, 0.6 * inner.bottom, 'sunshine');

        // 右上角添加图例以及文字说明
        for (let i = 0; i <= 5; ++i) {
            drawLine(w - inner.right - 100, inner.bottom + i * 15,
                w - inner.right - 50, inner.bottom + i * 15, 2, Color[i]);
            let str;
            if (i === 0) str = 47.61;
            if (i === 1) str = 41.88;
            if (i === 2) str = 40.73;
            if (i === 3) str = 37.73;
            if (i === 4) str = 29.74;
            if (i === 5) str = 25.76;
            drawText(w - inner.right - 40, inner.bottom + i * 15, City[i] + " / " + str);
        }

        drawText(w - inner.right - 75, 0.5 * inner.bottom, 'City/Latitude', '15px');
    }

</script>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值