实战篇39#如何实现世界地图的新冠肺炎疫情可视化?(代码片段)

凯小默 凯小默     2023-01-11     276

关键词:

说明

【跟月影学可视化】学习笔记。

世界地图新冠肺炎疫情可视化

下面将实现世界地图新冠肺炎疫情可视化。数据用的是从 2020 年 1 月 22 日到 3 月 19 日这些天的新冠肺炎疫情进展。效果类似下图:https://covid19.who.int/

步骤一:准备世界地图可视化需要的数据

先需要准备新冠肺炎的官方数据( https://www.who.int/

这里直接使用大佬整理好的:https://github.com/akira-cn/graphics/blob/master/covid-vis/assets/data/covid-data.json

另外需要准备地图的 JSON 文件:

  • GeoJSON:基础格式,它包含了描述地图地理信息的坐标数据。
  • TopoJSON:GeoJSON 格式经过压缩之后得到的,它通过对坐标建立索引来减少冗余,能够大大减少 JSON 文件的体积。但在使用的时候还需要对它解压,把它变成 GeoJSON 数据,可以使用https://github.com/topojson/topojson这个JavaScript 模块来处理 TopoJSON 数据。

什么是 geojson 数据可以去看我下面这篇文章,这里不多做介绍。

推荐阅读:

这里直接使用大佬整理好 geojson 以及 topojson 的 json 数据:

步骤二:利用 GeoJSON 数据绘制地图

下面使用 Canvas2D 来绘制地图,先了解一下墨卡托投影

什么是墨卡托投影?

墨卡托投影,是正轴等角圆柱投影。由荷兰地图学家墨卡托(G.Mercator)于1569年创立。假想一个与地轴方向一致的圆柱切或割于地球,按等角条件,将经纬网投影到圆柱面上,将圆柱面展为平面后,即得本投影。

下面利用墨卡托投影将 GeoJSON 数据中,coordinates 属性里的经纬度信息转换成画布坐标。

经纬度投影示意图:

  • longitude:经度,经度范围是 360 度
  • latitude:纬度,维度范围是 180 度
  • width:Canvas 的宽度
  • height:Canvas 的高度

换算公式如下:

x = width * (180 + longitude) / 360;
y = height * (1.0 - (90 + latitude) / 180); // Canvas坐标系y轴朝下

具体实现如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>利用 GeoJSON 数据绘制地图</title>
        <style>
            canvas 
                border: 1px dashed salmon;
            
        </style>
    </head>
    <body>
        <canvas width="1024" height="512"></canvas>
        <script>
            const width = 1024;
            const height = 512;

            // 投影函数
            function projection([longitude, latitude]) 
                const x = (width * (180 + longitude)) / 360;
                const y = height * (1.0 - (90 + latitude) / 180); // Canvas坐标系y轴朝下
                return [x, y];
            
            // 绘制
            function drawPoints(ctx, points) 
                ctx.beginPath();
                ctx.moveTo(...points[0]);
                for (let i = 1; i < points.length; i++) 
                    ctx.lineTo(...points[i]);
                
                ctx.fill();
            

            const canvas = document.querySelector("canvas");
            const ctx = canvas.getContext("2d");
            ctx.fillStyle = "salmon";

            (async function () 
                // 用 fetch 来读取 JSON 文件
                const worldData = await (await fetch("./data/world-geojson.json")).json();
                const features = worldData.features;
                // 遍历数据
                features.forEach(( geometry ) => 
                    if (geometry.type === "MultiPolygon") 
                        const coordinates = geometry.coordinates;
                        if (coordinates) 
                            coordinates.forEach((contours) => 
                                contours.forEach((path) => 
                                    // 进行投影转换
                                    const points = path.map(projection);
                                    // 进行绘制
                                    drawPoints(ctx, points);
                                );
                            );
                        
                     else if (geometry.type === "Polygon") 
                        const contours = geometry.coordinates;
                        contours.forEach((path) => 
                            // 进行投影转换
                            const points = path.map(projection);
                            // 进行绘制
                            drawPoints(ctx, points);
                        );
                    
                );
            )();
        </script>
    </body>
</html>

步骤三:将疫情的 JSON 数据整合进地图数据里

地图数据中,properties 只有一个 name 属性,对应着不同国家的名字。


疫情数据中的 contry 属性和 GeoJSON 数据里面的国家名称是一一对应的。

下面建立一个数据映射关系,将疫情数据中的每个国家的疫情数据直接写入到 GeoJSON 数据的 properties 字段里面。这里我们使用 topojson 处理。

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>将疫情的 JSON 数据整合进地图数据里</title>
</head>

<body>
	<script src="https://lib.baomitu.com/topojson/3.0.2/topojson.min.js"></script>
	<script>
		// 数据映射函数
		function mapDataToCountries(geoData, covidData) 
			const covidDataMap = ;
			covidData.dailyReports.forEach((d) => 
				const date = d.updatedDate;
				const countries = d.countries;
				countries.forEach((country) => 
					const name = country.country;
					covidDataMap[name] = covidDataMap[name] || ;
					covidDataMap[name][date] = country;
				);
			);
			geoData.features.forEach((d) => 
				const name = d.properties.name;
				d.properties.covid = covidDataMap[name];
			);
		

		(async function () 
			// 使用 topojson 数据
			const worldData = await (await fetch('./data/world-topojson.json')).json();
			const countries = topojson.feature(worldData, worldData.objects.countries);

			const covidData = await (await fetch('./data/covid-data.json')).json();
			mapDataToCountries(countries, covidData);

			console.log("将疫情的 JSON 数据整合进地图数据里--->", countries)
		)();
	</script>
</body>

</html>

整合数据如下:可以看到疫情数据已经整进去地图里面了

步骤四:将数据与地图结合

这里用7个不同的颜色来表示疫情的严重程度,填充地图,确诊人数越多的区域颜色越红。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>世界地图新冠肺炎疫情可视化</title>
        <style>
            canvas 
                border: 1px dashed salmon;
            
        </style>
    </head>
    <body>
        <div id="dateInfo"></div>
        <canvas width="1200" height="600"></canvas>
        <script src="https://lib.baomitu.com/topojson/3.0.2/topojson.min.js"></script>
        <script>
            const width = 1200;
            const height = 600;

            // 投影函数
            function projection([longitude, latitude]) 
                const x = (width * (180 + longitude)) / 360;
                const y = height * (1.0 - (90 + latitude) / 180); // Canvas坐标系y轴朝下
                return [x, y];
            
            // 绘制
            function drawPoints(ctx, points) 
                ctx.beginPath();
                ctx.moveTo(...points[0]);
                for (let i = 1; i < points.length; i++) 
                    ctx.lineTo(...points[i]);
                
                ctx.fill();
            

            // 颜色映射
            function mapColor(confirmed) 
                // 无人感染
                if (!confirmed) 
                    return "rgb(80, 255, 80)";
                
                // 小于 10
                if (confirmed < 10) 
                    return "rgb(250, 247, 171)";
                
                // 感染人数 10~99 人
                if (confirmed < 100) 
                    return "rgb(255, 186, 66)";
                
                // 感染人数 100~499 人
                if (confirmed < 500) 
                    return "rgb(234, 110, 41)";
                
                // 感染人数 500~999 人
                if (confirmed < 1000) 
                    return "rgb(224, 81, 57)";
                
                // 感人人数 1000~9999 人
                if (confirmed < 10000) 
                    return "rgb(192, 50, 39)";
                
                // 感染人数超 10000 人
                return "rgb(151, 32, 19)";
            

            // 日期格式
            function formatDate(date) 
                const year = date.getFullYear();
                let month = date.getMonth() + 1;
                month = month > 9 ? month : `0$month`;
                let day = date.getDate();
                day = day > 9 ? day : `0$day`;
                return `$year-$month-$day`;
            

            // 数据映射函数
            function mapDataToCountries(geoData, covidData) 
                const covidDataMap = ;
                covidData.dailyReports.forEach((d) => 
                    const date = d.updatedDate;
                    const countries = d.countries;
                    countries.forEach((country) => 
                        const name = country.country;
                        covidDataMap[name] = covidDataMap[name] || ;
                        covidDataMap[name][date] = country;
                    );
                );
                geoData.features.forEach((d) => 
                    const name = d.properties.name;
                    d.properties.covid = covidDataMap[name];
                );
            

            // 绘制地图
            function drawMap(ctx, countries, date) 
                date = formatDate(date);
                dateInfo.innerHTML = date;
                countries.features.forEach(( geometry, properties ) => 
                    const covid = properties.covid
                        ? properties.covid[date]
                        : null;
                    let confirmed;
                    if (covid) 
                        confirmed = covid.confirmed;
                        properties.lastConfirmed = confirmed;
                     else if (properties.lastConfirmed) 
                        confirmed = properties.lastConfirmed;
                    
                    ctx.fillStyle = mapColor(confirmed);
                    if (geometry.type === "MultiPolygon") 
                        const coordinates = geometry.coordinates;
                        if (coordinates) 
                            coordinates.forEach((contours) => 
                                contours.forEach((path) => 
                                    const points = path.map(projection);
                                    drawPoints(ctx, points);
                                );
                            );
                        
                     else if (geometry.type === "Polygon") 
                        const contours = geometry.coordinates;
                        contours.forEach((path) => 
                            const points = path.map(projection);
                            drawPoints(ctx, points);
                        );
                    
                );
            

            const canvas = document.qu

python|新冠肺炎疫情数据的爬取与可视化分析(代码片段)

前言这两年,新冠肺炎肆虐而来,随着确诊人数的不断上升,全世界的人都陷入了恐慌中。我们经常能在手机、电视上看到各个地区疫情的情况,但那些数据大多数都是零碎的,我们不可能去记住每个数据,但我们可以用爬虫爬... 查看详情

基于flask框架的新冠疫情数据可视化系统(代码片段)

基于flask框架的新冠疫情数据可视化系统新冠疫情数据可视化系统是本学期大数据可视化这门课的结课作业,本系统有四个模块的功能,涵盖有视频播放、疫情情况中国地图分布、Echarts饼状图和树状图等,应用Python爬... 查看详情

新冠肺炎地图制作的10大误区

...的行为。今天他连发11条推文,针对目前网络上众多的新冠肺炎地图中存在的误区进行了分析,在和作者沟通获得授权后翻译成中文,给大家分享下。(文末有作者原文,大家可以对照着看,如有出入欢迎留言... 查看详情

《30天吃掉那只tensorflow2.0》1-4时间序列数据建模流程范例(国内新冠疫情结束时间预测问题)

...,训练模型四,评估模型五,使用模型六,保存模型国内的新冠肺炎疫情从发现至今已经持续很久了,这场起源于吃野味的灾难给大家的生活造成了诸多方面的影响。有的同学是收入上的,有的同学是感情上的,有的同学是心理... 查看详情

新冠疫情啥时结束

世界卫生组织召开会议的时候,迈尔·瑞安作出回答,新冠病毒可能会成为各国长期都需要面对的问题。它会成为一种流行性的病毒,一直都伴随在人类的左右,就跟我们平时患上感冒一样,但不同的是,新冠病毒更加的具有威... 查看详情

全球疫情形势动态地图展示(超帅超好玩的python动图)(代码片段)

全球疫情及疫苗接种进度可视化之一--全球疫情形势动态地图展示安装plotly库全球疫情形势定义工具函数抽取数据绘制动态图表重抽样数据抽取、整理与可视化展示抽取原始数据按周重抽样确诊病例治愈病例死亡病例全国疫情及... 查看详情

每日一练:python国内疫情数据爬取与地图绘制(代码片段)

...诊疫情地图绘制[系列文章篇]Python地图篇-使用pyecharts绘制世界地图、中国地图、省级地图、市级地图实例详解效果图先给大家看下效果图哈:可以看刚和查询的吉林累计确诊疫情数据是一致的。累计确诊疫情地图绘制①时时... 查看详情

每日一练:python国内疫情数据爬取与地图绘制(代码片段)

...诊疫情地图绘制[系列文章篇]Python地图篇-使用pyecharts绘制世界地图、中国地图、省级地图、市级地图实例详解效果图先给大家看下效果图哈:可以看刚和查询的吉林累计确诊疫情数据是一致的。累计确诊疫情地图绘制①时时... 查看详情

世界疫情呈现怎样的趋势

...病毒变异情况来看,还目前全球的今冬全球新冠疫情走势如何?吴尊友最新研判——今冬新冠疫情的趋势还很难判定。不过,疫情走势有三种可能情景。第一种情景是疫情在当前的形势下继续向好,虽然不大可能在今冬实现新冠... 查看详情

react17+vite+echarts实现疫情数据可视化「06完成疫情地图绘制」

往期文章目录:React17+Vite+ECharts实现疫情数据可视化「01项目介绍篇」React17+Vite+ECharts实现疫情数据可视化「02快速搭建项目」React17+Vite+ECharts实现疫情数据可视化「03学习ReactHooks」React17+Vite+ECharts实现疫情数据可视化「04初始化项... 查看详情

react17+vite+echarts实现疫情数据可视化「06完成疫情地图绘制」

往期文章目录:React17+Vite+ECharts实现疫情数据可视化「01项目介绍篇」React17+Vite+ECharts实现疫情数据可视化「02快速搭建项目」React17+Vite+ECharts实现疫情数据可视化「03学习ReactHooks」React17+Vite+ECharts实现疫情数据可视化「04初始化项... 查看详情

简单几行代码实现全国疫情数据可视化(python课程设计)(代码片段)

...面我们通过python对疫情数据进行一个简单的爬取整理以及可视化。#导入模块importpandasaspdimportrequests#首先这是爬取数据和整理数据我们需要用到的第三方库,疫情数据来自腾讯新闻#实时更新:新冠肺炎疫情最新动态https://... 查看详情

怎么看疫情预测

...的模型预测,其中一些看似“危言”,引人瞩目。我们该如何看待这些预测?预测带来警示24亿,这是英国帝国理工学院新冠肺炎反应小组3月26日发布的第12份报告里,对全球感染人数高中低三个预测的中间数字。该报告对今年... 查看详情

12.pgl图学习之项目实践(unimp算法实现论文节点分类新冠疫苗项目实战,助力疫情)[系列九](代码片段)

原项目链接:https://aistudio.baidu.com/aistudio/projectdetail/5100049?contributionType=11.图学习技术与应用图是一个复杂世界的通用语言,社交网络中人与人之间的连接、蛋白质分子、推荐系统中用户与物品之间的连接等等,都... 查看详情

python数据分析高薪实战第十天eda实战-全球新冠肺炎确诊病例趋势分析(代码片段)

...的假设,而是直接通过对原始数据进行分析,用可视化技术和各种统计的方法来探寻数据隐含的规律和信息。简单来说就是从数据中寻找规律,而不是基于人工假设。近些年随着大数据分析的蓬勃发展,尤其是近... 查看详情

实战篇40#如何实现3d地球可视化?(代码片段)

说明【跟月影学可视化】学习笔记。如何实现一个3D地球学习笔记源码实现:https://github.com/kaimo313/visual-learning-demo整体实现效果如下:1、绘制一个3D球体<!DOCTYPEhtml><htmllang="en"><head><metacharset= 查看详情

新冠肺炎感染人数为何远超sars?

新冠肺炎爆发以来,感染人数迅速增加,几天便超过了当年的SARS病毒感染人数,人们人心惶惶,不得安宁。所以,到底新冠病毒为何会有如此多的人感染那?归结起来,其实就是这种病毒比当年的SARS感染率高得多,极其容易感... 查看详情

计算机毕业设计python新冠疫情数据分析可视化平台

参考技术A前端开发:VUE、ElementUI、ECharts、Maptalks、D3js后端web开发:Flask、Mysql爬虫开发:request数据分析:pandas、numpy数据可视化、爬虫、数据清洗、大数据、3D视图 查看详情