前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高质量编码-克里金插值地图可视化(后台缓存优化)

高质量编码-克里金插值地图可视化(后台缓存优化)

原创
作者头像
MiaoGIS
修改2021-08-20 18:14:06
1.3K0
修改2021-08-20 18:14:06
举报
文章被收录于专栏:Python in AI-IOTPython in AI-IOT

前面在使用kriging.js进行克里金插值可视化时,计算分为三个步骤:

  • 模型训练(kriging.train)
  • 网格生成(kriging.grid)
  • 绘制结果(kriging.plot)

实际在web页面中根据真实数据即时运行上面三个步骤的计算,因为模型训练涉及到的数学计算量很大,可能需要很长时间才能得到结果,前端javascript耗时统计如下:

上面三个步骤的耗时大小取决于模型选择,原始数据,以及网格分辨率等参数,查看源代码可以看到各个步骤使用的参数。

  • 模型训练(kriging.train)

  • 网格生成(kriging.grid)

  • 绘制结果(kriging.plot)

现实需求中需要使用真实数据生成一个或多个热力图canvas,既然每次从计算到生成图片耗时很久,可不可以按照需求将每组数据计算生成的图片缓存到后台,下次使用直接从后台获取,这样页面上便能更快的看到热力图?答案是肯定的。

这里将某个时间对应的数据第一次克里金插值计算绘制生成的多个canvas的base64编码以及各自对应的经纬度范围信息保存到后台,下次再次需要绘制这个时间对应数据的热力图,直接从后台获取叠加到地图上。怎么判断是否是第一次呢,JavaScript代码逻辑首先从后台询问某个日期对应的热力图是否已经存在,如果存在就直接获取,如果不存在前端JavaScript开始计算生成,同时生成后保存到后台方便下次使用。

将热力图保存到后台
将热力图保存到后台
从后台获取热力图数据
从后台获取热力图数据

我们看一下前端JavaScript实现:

再来看一下后台实现:

前端代码如下:

代码语言:html
复制
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
        html,
        body,
        #allmap {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            overflow: hidden;
        }

        #allmap img {
            height: 100%;
        }

    </style>

    <script type="text/javascript" src="https://underscorejs.net/js/jquery-1.11.0.min.js"></script>
    <script type="text/javascript" src="https://underscorejs.net/js/underscore.js"></script>
    <script type="text/javascript" src="static/lib/kriging.js"></script>

    <script type="text/javascript" src="static/js/china.js"></script>
    <script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak=wWy2A8K94nhntYTYUHS19RXW"></script>
    <title>空气质量空间插值可视化</title>

</head>

<body>
    <div id="allmap"></div>

    <script type="text/javascript">
        // 百度地图API功能
        var map = new BMap.Map("allmap");
        map.centerAndZoom(new BMap.Point(116.403765, 39.914850), 5);
        map.enableScrollWheelZoom();

        function loadMarkers(points) {

            map.clearOverlays();
            $.each(points, (i, x) => {
                //console.log(x);
                var position = new BMap.Point(x['经度'], x['纬度']);
                var marker1 = new BMap.Marker(position);
                dictMarker[x['编号']] = marker1;
                map.addOverlay(marker1);
                marker1.addEventListener("click", function() {

                    var attrs = _.omit(x, ['编号', '经度', '纬度','value2']);
                    var content = _.map(attrs, (x, i) => `${i}:${x}`).join('<br>');
                    var infoWindow = new BMap.InfoWindow(content);
                    marker1.openInfoWindow(infoWindow);

                });

            })

        }
        dictMarker = {};
        $.get('api/stations', function(data) {

            data = JSON.parse(data['result']);
            window.points = data;

            dictPoints = _.indexBy(points, '编号');
            //loadMarkers(data);
            refreshCanvas();
        })

        function refreshCanvas() {
            var date = location.search.match(/date=([^&]*)/i);
            var hour = location.search.match(/hour=([^&]*)/i);
            if (!!date) {
                date = date[1];
            } else {
                date = "20210610";
            }
            if (!!hour) {
                hour = hour[1];
            } else {
                hour = "0";
            }
            var type = "PM2.5";
			window.params={date: date,hour: hour, type: type};
			
			$.post('krigingMap',params,function(data){console.log(data);
			if(data['result']==0){
			$.post('api/stations', params, function(data) {

                data = JSON.parse(data['result']);
                var airData = _.find(data, {
                    hour: parseInt(hour),
                    type: type
                });

                airData = _.omit(airData, ['date', 'hour', 'type']);

                var trainData = _.compact(_.map(airData, function(item, index) {
                    if (!item) {
                        return null;
                    }
                    result = _.result(dictPoints, index, null);
                    if (!!result) {
                        result['value']=item;
                        result['value2'] = _.sortedIndex(standards, item);
                    }
                    return result;
                }));
                window.data1 = trainData;
                window.canvas = getCanvas(trainData);
            })
			
			}
			else{
			var imgs=$.parseJSON(data['result']);
			imgs.forEach(function(item){
	 
			addOverlay([item['minX'],item['minY']],[item['maxX'],item['maxY']],item['data']);
			})
			}
			 
			});
			
            
        }
        var [width, height] = [10, 5];
        var [offsetX, offsetY] = [10, 5];
        let canvas = null; //画布
        let colors = ["green", "#82D827", "yellow", "#FFDF00", "orange", "#FF5E00",
            "red", "#B71850", "purple", "#952E81","brown"];
        var standards = [25, 50, 75, 100, 125, 150, 175, 200, 250, 300];

        function getCanvas(data) {
            var values = _.pluck(data, 'value2');
            var lngs = _.pluck(data, '经度');
            var lats = _.pluck(data, '纬度');
            var indexes = _.unique(values);
            var colors0 = colors.slice(_.min(indexes), _.max(indexes) + 1);
       
            var [minX, minY, maxX, maxY] = [_.min(lngs), _.min(lats), _.max(lngs), _.max(lats)];
            var bounds = [
                [
                    [minX, minY],
                    [minX, maxY],
                    [maxX, maxY],
                    [maxX, minY]
                ]
            ];
            console.log(bounds);
            bounds = _.flatten(china.geometry.coordinates,true);
            console.time();
            window.variogram = kriging.train(values, lngs, lats, 'exponential', 0, 100);
            console.timeEnd();
            console.time();
            window.grid = kriging.grid(bounds, variogram, (maxY - minY) / 500);
            console.timeEnd();
            console.time();

            var lngs = _.range(minX - offsetX, maxX + offsetX, width);
            var lats = _.range(minY - offsetY, maxY + offsetY, height);
			window.backupImgs=[];
            _.map(lngs, function(m) {
                canvas = document.createElement('canvas');
                canvas.width = width * 5;
                canvas.height = height * 5;
                canvas.style.display = 'block';
                canvas.getContext('2d').globalAlpha = 0.75;

                [minX, maxX] = [m, m + width]
				
                _.map(lats, function(n) {
                    [minY, maxY] = [n, n + height]

                    kriging.plot(canvas, grid, [minX, maxX], [minY, maxY], colors0);
					canvasImg=	canvas.toDataURL();
					backupImgs.push({'minX':minX,'minY':minY,'maxX':maxX,'maxY':maxY,'data':canvasImg});
                    addOverlay([minX, minY], [maxX, maxY], canvasImg);
					
                })
            })
			console.timeEnd();
			
			$.post('backupImgs',$.extend({'imgs':JSON.stringify(backupImgs)},params),function(data){
			if(data['result']==1){
			console.info('success');
			}
			});
            

        }

        function addOverlay(west_south, east_north, canvasImg) {
            var west_south = new BMap.Point(west_south[0], west_south[1]);
            var east_north = new BMap.Point(east_north[0], east_north[1]);
            var bounds = new BMap.Bounds(west_south, east_north);
            var canvasOverlay = new BMap.GroundOverlay(bounds, {

                imageURL: canvasImg,
                opacity: 0.6
            });
            map.addOverlay(canvasOverlay);
        }

    </script>
</body>


</html>

后台代码(使用Python Web框架Tornado实现)如下:

代码语言:python
复制
class backupImgsHandler(tornado.web.RequestHandler):
    def post(self):
        imgs=self.get_argument('imgs')
        date=self.get_argument('date')
        hour=self.get_argument('hour')
        _type=self.get_argument('type')
        imgsFile=os.path.join('static/backupImgs',f'{date}-{hour}-{_type}')
        with open(imgsFile,'w') as f:
            f.write(imgs)
            
        print(imgs)
        self.write({'result':1})

class krigingMapHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('krigingMap.html')

    def post(self):
        date=self.get_argument('date')
        hour=self.get_argument('hour')
        _type=self.get_argument('type')
        imgsFile=os.path.join('static/backupImgs',f'{date}-{hour}-{_type}')
        if os.path.exists(imgsFile):
            with open(imgsFile) as f:
                result=f.read()
            self.write({'result':result})
        else:
            self.write({'result':0})

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档