leho:可视化:动态气泡图,拿走不谢

董乐器 2021-07-08 17:29:18

作者 | 小F

leho:可视化:动态气泡图,拿走不谢

来源 | 法纳斯特(IDleho:walker398)

leho:可视化:动态气泡图,拿走不谢

头图 | CSDN 下载自东方IC

leho:可视化:动态气泡图,拿走不谢

本期给大家分享一个用D3.js实现的动态气泡图案例leho。

leho:可视化:动态气泡图,拿走不谢

也是之前小F了解D3.js时发现的leho,效果大致如下。

leho:可视化:动态气泡图,拿走不谢

项目地址:://observablehq.com/@unkleho/covid-19-bubble-chart-with-d3-render

leho:可视化:动态气泡图,拿走不谢

GitHub地址:://github.com/unkleho/d3-render

leho:可视化:动态气泡图,拿走不谢

要想实现这个项目的话,首先需要安装Node.js以及npm,具体的安装步骤自行百度,还是比较简单的。

leho:可视化:动态气泡图,拿走不谢

接下来就可以安装Vue.js及Vue脚手架3.0。

leho:可视化:动态气泡图,拿走不谢

所以要想鼓捣一些高大上的可视化,前端的学习是必不可少的,默默的流下没有技术的泪水。

# 安装Vue.jsnpm install vue# 安装Vue-cli3脚手架npm install -g @vue/cli如此便可以创建项目了。

# 创建名为bubblechart的项目vue create bubblechart结果如下,选择默认模式即可。

由于里面有eslint(编码规范)的存在,记得在配置文件package.json中添加下面的代码。

"rules": { "no-unused-vars": "off", "no-undef": "off"}要不然会出现报错,无法运行。

项目创建成功后,修改App.vue文件内容如下。

<template> <div id="app"> <svg id="bubble-chart" width="954" height="450" /> </div></template><script>export default { name: 'App', components: { }}</script><style></style>保存成功后,打开bubblechart文件夹下的终端,运行下面这个命令。

npm run serve浏览器便会跳出一个标题为bubblechart的空白网页。

安装一些项目依赖d3,d3-render,d3-selection,d3-transition,axios。

npm install d3@5.16.0 --save-devnpm install d3-render@0.2.4 --save-devnpm install d3-selection@1.4.2 --save-devnpm install d3-transition@2.0.0 --save-devnpm install axios --save-dev最好是指定版本,要不然可能会报错。

在main.js文件中引用axios,用于请求数据。

import axios from 'axios'Vue.prototype.$axios = axios在App.vue的script标签中引用d3,d3-render。

import * as d3 from "d3";import render from "d3-render";设置初始数据,各式各样的气泡颜色。

data { return { covidData: , countries: , colours: { pink: "#D8352A", red: "#D8352A", blue: "#48509E", green: "#02A371", yellow: "#F5A623", hyperGreen: "#19C992", purple: "#B1B4DA", orange: "#F6E7AD", charcoal: "#383838", } };}获取各地区的新冠数据,两个CSV文件放在Public文件夹下,可直接访问。

methods: { async getdata { //获取新冠数据 await this.$axios.get("data.csv").then((res) => { this.covidData = d3.csvParse(res.data); }); //获取国家数据 await this.$axios.get("countries.csv").then((res) => { this.countries = d3.csvParse(res.data); }); //画图 this.drawType; },}开始画图的操作,先定义一下画布大小以及各大洲的颜色。

drawType { //设置svg大小 const width = 954; const height = 450; //设置各个大洲的参数 const continents = [ { id: "AF", name: "Africa", fill: this.colours.purple, colour: this.colours.charcoal, }, { id: "AS", name: "Asia", fill: this.colours.yellow, colour: this.colours.charcoal, }, { id: "EU", name: "Europe", fill: this.colours.blue, colour: this.colours.charcoal, }, { id: "NA", name: "N. America", fill: this.colours.pink, }, { id: "OC", name: "Oceania", fill: this.colours.orange, colour: this.colours.charcoal, }, { id: "SA", name: "S. America", fill: this.colours.green, colour: this.colours.charcoal, }, ];}定义圆圈组件,其中duration很重要,起到一个动画过渡的效果。

//定义圆圈组件const circleComponent = ({ r, cx, cy, fill, duration }) => { return { append: "circle", r, cx, cy, fill, duration, };};定义文字组件,设置字体、大小、颜色等。

//定义文字组件const textComponent = ({ key, text, x = 0, y = 0, fontWeight = "bold", fontSize = "12px", textAnchor = "middle", fillOpacity = 1, colour, r, duration = 1000,}) => { return { append: "text", key, text, x, y, textAnchor, fontFamily: "sans-serif", fontWeight, fontSize, fillOpacity: { enter: fillOpacity, exit: 0 }, fill: colour, duration, style: { pointerEvents: "none", }, };};数值转换,对较大的数值进行处理。

//对数值进行转换,比如42288变为42kconst format = (value) => { const newValue = d3.format("0.2s")(value); if (newValue.indexOf("m") > -1) { return parseInt(newValue.replace("m", "")) / 1000; } return newValue;};动态变化标签信息,包含名称及数值。

//将各地区名称长度和数值与圆圈大小相比较,实现信息动态变化const labelComponent = ({ isoCode, countryName, value, r, colour }) => { // Don't show any text for radius under 12px if (r < 12) { return ; } //console.log(r); const circleWidth = r * 2; const nameWidth = countryName.length * 10; const shouldShowIso = nameWidth > circleWidth; const newCountryName = shouldShowIso ? isoCode : countryName; const shouldShowValue = r > 18; let nameFontSize; if (shouldShowValue) { nameFontSize = shouldShowIso ? "10px" : "12px"; } else { nameFontSize = "8px"; } return [ textComponent({ key: isoCode, text: newCountryName, fontSize: nameFontSize, y: shouldShowValue ? "-0.2em" : "0.3em", fillOpacity: 1, colour, }), ...(shouldShowValue ? [ textComponent({ key: isoCode, text: format(value), fontSize: "10px", y: shouldShowIso ? "0.9em" : "1.0em", fillOpacity: 0.7, colour, }), ] : ), ];};设置气泡组件。

//设置气泡组件const bubbleComponent = ({ name, id, value, r, x, y, fill, colour, duration = 1000,}) => { return { append: "g", key: id, transform: { enter: `translate(${x 1},${y 1})`, exit: `translate(${width / 2},${height / 2})`, }, duration, delay: Math.random * 300, children: [ circleComponent({ key: id, r, fill, duration }), ...labelComponent({ key: id, countryName: name, isoCode: id, value, r, colour, duration, }), ], };};划分数据的层次结构,生成气泡图的结构。

后续的d.r、d.x、d.y数据都是从中获取的。

//d3.pack - 创建一个新的圆形打包图//d3.hierarchy - 从给定的层次结构数据构造一个根节点并为各个节点指定深度等属性const pack = (data) => d3 .pack .size([width - 2, height - 2]) .padding(2)(d3.hierarchy({ children: data }).sum((d) => d.value));这一步不是太懂,以后慢慢了解。

//生成气泡图表const renderBubbleChart = (selection, data) => { const root = pack(data); const renderData = root.leaves.map((d) => { return bubbleComponent({ id: d.data.id, name: d.data.name, value: d.data.value, r: d.r, x: d.x, y: d.y, fill: d.data.fill, colour: d.data.colour, }); }); return render(selection, renderData);};const renderBubbleChartContainer = (data) => { return renderBubbleChart("#bubble-chart", data);};最后便可以加入数据,生成动态的气泡图表。

对数据进行处理,进行日期限定及排序,以及选取相关的数据类型。

//定义新冠数据const covidData_result = this.covidData;//定义各地区数据const countries_result = this.countries;//选择数据类型为所有确诊病例数量const dataKey = "total_cases";//定义开始时间及结束时间const startDate = new Date('2020-01-12')const endDate = new Date('2020-06-02')//d3.map - 创建一个新的空的 map 映射const dates = d3 .map(this.covidData, (d) => d.date) .keys .map((date) => new Date(date)) .filter((date) => date >= startDate && date <= endDate) .sort((a, b) => a - b);//各大洲全选const selectedContinents = ["AF", "AS", "EU", "NA", "OC", "SA"];//最小数值const minimumPopulation = 0;//排序const order = "desc";//转换日期格式为2020-01-01const getIsoDate = (date) => { const IsoDate = new Date(date); return IsoDate.toISOString.split("T")[0];};//获取最终的数据function getDataBy({ dataKey, date, selectedContinents, order, minimumPopulation,}) { return ( covidData_result .filter((d) => d) .filter((d) => d.iso_code !== "OWID_WRL") // Filter out countries with populations under 1 million .filter((d) => d.population > parseInt(minimumPopulation)) .filter((d) => { return d.date === getIsoDate(date); }) .filter((d) => d[dataKey]) .filter((d) => { const country = countries_result.find( (c) => c.iso3 === d.iso_code ); const continent = continents.find((c, i) => { if (!country) { return false; } return c.id === country.continentCode; }); if (!continent) { return false; } return selectedContinents.includes(continent.id); }) .map((d) => { const country = countries_result.find( (c) => c.iso3 === d.iso_code ); const continent = continents.find( (c) => c.id === country.continentCode ); const name = country.shortName || country.name; return { name, id: country.iso3, value: d[dataKey], fill: continent.fill, colour: continent.colour || "white", }; }) .filter((d) => d.value !== "0.0") .sort(function (a, b) { const mod = order === "desc" ? -1 : 1; return mod * (a.value - b.value); }) );}设置For循环延时,完成动态气泡图的实现。

//延时执行,闭包for (var i = 0; i < dates.length; i ) { (function (i) { setTimeout(function { const date = dates[i]; console.log(date); const data = getDataBy({ dataKey, date, selectedContinents, minimumPopulation, order, }); renderBubbleChartContainer(data); }, 2000 * i); })(i);};运行项目,打开浏览器,访问:8080/

可以看到酷炫的动态气泡图,昨天青岛又出现病例,疫情结束遥遥无期呀~

将项目下载到本地,运行下面两行命令,即可运行。

npm installnpm run serve点分享

上一篇:笛风:请问有各种笛子的比较清晰的图片吗?
下一篇:talent吉他:什么是Talent management?
相关文章
留言与评论 (共有 条评论)
验证码:
顶部