全國都在為新冠病毒戰斗,這是一場看不見硝煙的戰“疫”,每天醒來第一件事就是看疫情數據,然后就投入到戰“疫”工作中去。
期望拐點到來,比較直觀的就是疫情地圖,丁香園、頭條、高德、百度等都發布了疫情地圖數據,可以分地區查看疫情數據專題圖,用不同顏色表示確診病例數量,如何實現疫情地圖,參照丁香園網站,似乎用的mapbox工具展示地圖。
實現效果如下:
一、數據獲取存儲到數據庫
這里從丁香園抓取當天的疫情數據,用DJANGO 新建 coviddataprovince,coviddatacity model 表示各省和各市疫情數據。
1 import os,django 2 os.environ['DJANGO_SETTINGS_MODULE'] = 'covid.settings' 3 django.setup() 4 import urllib.request 5 import requests 6 import re 7 from bs4 import BeautifulSoup 8 from distutils.filelist import findall 9 import json 10 from django.shortcuts import render 11 from coviddata.models import coviddataprovince,coviddatacity 12 from django.http import JsonResponse 13 import numpy 14 import psycopg2 15 16 def getcoviddata(): 17 url = "https://ncov.dxy.cn/ncovh5/view/pneumonia" 18 #url = "https://www.baidu.com" 19 headers = { # 設置header 20 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 21 'Accept-Language': 'zh-CN,zh;q=0.8', 22 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' 23 } 24 response = requests.get(url,headers=headers,timeout=30) # 以下是解析網頁的過程 25 htmlcontext = response.content 26 htmlcontext = str(htmlcontext, 'utf-8') 27 soup = BeautifulSoup(htmlcontext, "html.parser") 28 datas=soup.select('#getAreaStat')[0].get_text().replace("try { window.getAreaStat = ","").replace("}catch(e){}","") 29 jsondatas = json.loads(datas) 30 for jsondata in jsondatas: 31 province=coviddataprovince(); 32 province.provinceName=jsondata["provinceName"]; 33 province.provinceShortName = jsondata["provinceShortName"]; 34 province.currentConfirmedCount =int( jsondata["currentConfirmedCount"]); 35 province.confirmedCount = int(jsondata["confirmedCount"]); 36 province.suspectedCount = int(jsondata["suspectedCount"]); 37 province.curedCount = int(jsondata["curedCount"]); 38 province.deadCount = int(jsondata["deadCount"]); 39 province.locationId = int(jsondata["locationId"]); 40 province.save(); 41 for citydata in jsondata["cities"]: 42 city=coviddatacity(); 43 city.cityName = citydata["cityName"]; 44 city.currentConfirmedCount = int(citydata["currentConfirmedCount"]); 45 city.confirmedCount = int(citydata["confirmedCount"]); 46 city.suspectedCount = int(citydata["suspectedCount"]); 47 city.curedCount = int(citydata["curedCount"]); 48 city.deadCount = int(citydata["deadCount"]); 49 city.locationId = int(citydata["locationId"]); 50 city.save(); 51 52 def outcovidjson(request): 53 data = {} 54 coviddatas=coviddataprovince.objects.values() 55 data['coviddata'] = list(coviddatas) 56 return JsonResponse(data, safe=False, json_dumps_params={'ensure_ascii':False})
二、地圖展示
應用輕量級地圖工具Leafletjs展示地圖
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>疫情防控地圖</title> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <link rel="stylesheet" href="../static/gowhere/leaflet.css" /> 8 <link rel="stylesheet" href="../static/gowhere/screen.css" /> 9 <style> 10 .info { 11 padding: 6px 8px; 12 font: 14px/16px Arial, Helvetica, sans-serif; 13 background: white; 14 background: rgba(255,255,255,0.8); 15 box-shadow: 0 0 15px rgba(0,0,0,0.2); 16 border-radius: 5px; 17 width:200px; 18 height:100px 19 } 20 .info h4 { 21 margin: 0 0 5px; 22 color: #777; 23 } 24 .legend { 25 text-align: left; 26 line-height: 18px; 27 color: #555; 28 width:150px; 29 } 30 .legend i { 31 width: 18px; 32 height: 18px; 33 float: left; 34 margin-right: 8px; 35 opacity: 0.7; 36 } 37 .auto-style1 { 38 width: 24px; 39 } 40 #coviddatainfo_province{ 41 font-size:20pt; 42 line-height: 38px; 43 } 44 #coviddatainfo_confirm { 45 font-size:14pt; 46 line-height: 28px; 47 } 48 #coviddatainfo_cure { 49 font-size:14pt; 50 line-height: 28px; 51 } 52 td { 53 width:150px; 54 } 55 .auto-style2 { 56 height: 40px; 57 } 58 </style> 59 </head> 60 <body> 61 <div id="map"></div> 62 <script src="../static/gowhere/leaflet.js"></script> 63 <script src="../static/gowhere/jquery-3.4.1.min.js"></script> 64 <script src="../static/gowhere/leaflet.ChineseTmsProviders.js"></script> 65 <script type="text/javascript" src="../static/gowhere/data/bou2_4p2.js"></script> 66 <script type="text/javascript" src="../static/gowhere/data/chinaprovince.js"></script> 67 <script type="text/javascript"> 68 var map = L.map('map').setView([35, 105], 3); 69 var t11, t12,t13; 70 var coviddata; 71 L.tileLayer.chinaProvider('GaoDe.Normal.Map', { maxZoom: 9, minZoom: 3 }).addTo(map); 72 // control that shows state info on hover 73 var info = L.control(); 74 info.onAdd = function (map) { 75 this._div = L.DomUtil.create('div', 'info'); 76 this.update(); 77 return this._div; 78 }; 79 info.update = function (props) { 80 this._div.innerHTML = '<h4></h4>' + (props ? '<b>' + props.Name + '</b><br />確診:' + t12 + '<br/>疑似:' + t13 + '' : '選擇省份'); 81 }; 82 83 info.updatecontent=function(txt){ 84 this._div.innerHTML=txt; 85 }; 86 info.addTo(map); 87 // get color depending on population density value 88 function getColor(d) { 89 return d > 5000 ? '#FC4E2A' : 90 d > 500 ? '#FD8D3C' : 91 d > 300 ? '#FEB24C' : 92 d > 200 ? '#FED976' : 93 '#FFEDA0'; 94 } 95 function style(feature) { 96 return { 97 weight: 2, 98 opacity: 1, 99 color: 'white', 100 dashArray: '3', 101 fillOpacity: 0.7, 102 fillColor: getColor(getAch(feature)) 103 }; 104 } 105 function style2(feature) { 106 return { 107 weight: 2, 108 opacity: 1, 109 color: 'white', 110 dashArray: '3', 111 fillOpacity: 0.7, 112 fillColor: 'red' 113 }; 114 } 115 function getAch(feature) 116 { 117 var provinceName=getProvince(feature.properties.Name); 118 //var t12 = updateField("All", "All", provinceName, table1, "2014YTD", "Ach%", null); 119 t12=getProvincevalue(feature.properties.Name,"confirmedCount"); 120 return t12; 121 } 122 function highlightFeature(e) { 123 var layer = e.target; 124 layer.setStyle({ 125 weight: 5, 126 color: '#666', 127 dashArray: '', 128 fillOpacity: 0.7 129 }); 130 if (!L.Browser.ie && !L.Browser.opera) { 131 layer.bringToFront(); 132 } 133 //info.update(layer.feature.properties); 134 } 135 var geojson,provicename="All"; 136 function resetHighlight(e) { 137 geojson.resetStyle(e.target); 138 //info.update(); 139 } 140 function zoomToFeature(e) { 141 //map.fitBounds(e.target.getBounds()); 142 provicename = e.target.feature.properties.Name; 143 var currentConfirmedCount=getProvincevalue(provicename,"confirmedCount"); 144 var curedCount=getProvincevalue(provicename,"curedCount"); 145 //info.updatecontent(provicename+"確診病例:"+currentConfirmedCount+"治愈病例:"+curedCount); 146 $("#coviddatainfo_province").text("省名:"+provicename); 147 $("#coviddatainfo_confirm").text("確診病例:"+currentConfirmedCount); 148 $("#coviddatainfo_cure").text("治愈病例:"+curedCount); 149 //update(); 150 } 151 function onEachFeature(feature, layer) { 152 layer.on({ 153 mouseover: highlightFeature, 154 mouseout: resetHighlight, 155 click: zoomToFeature 156 }); 157 } 158 function addcovidmap() 159 { 160 $(document).ready(function(){ 161 $.get("http://localhost/outcovidjson",function(data,status){ 162 //$("#test1").text("Hello world!"); 163 info.updatecontent("<div id='coviddatainfo_province'>所在省</div><div id='coviddatainfo_confirm'>確診病例</div><div id='coviddatainfo_cure'>治愈病例</div>"); 164 coviddata=data["coviddata"]; 165 geojson = L.geoJson(states, { 166 style: style, 167 onEachFeature: onEachFeature 168 }).addTo(map); 169 }); 170 }); 171 } 172 addcovidmap(); 173 174 map.attributionControl.addAttribution(''); 175 var legend = L.control({ position: 'bottomright' }); 176 legend.onAdd = function (map) { 177 var div = L.DomUtil.create('div', 'info legend'), 178 grades = [0,200,300,500,2000], 179 labels = [], 180 from, to; 181 for (var i = 0; i < grades.length; i++) { 182 from = grades[i]; 183 to = grades[i + 1]; 184 labels.push( 185 '<i style="background:' + getColor(from + 1) + '"></i> ' + 186 from + (to ? '–' + to : '+')); 187 } 188 div.innerHTML = labels.join('<br>'); 189 return div; 190 }; 191 legend.addTo(map); 192 function getProvince(name) { 193 for (var i = 0; i < chinaProvince.length; i++) 194 if (chinaProvince[i].Name == name) 195 return chinaProvince[i].Pinyin; 196 } 197 function getProvincevalue(name,fieldname) { 198 for (var i = 0; i < coviddata.length; i++) 199 if (coviddata[i].provinceShortName == name) 200 return coviddata[i][fieldname]; 201 } 202 </script> 203 </body> 204 </html>