好文推荐:用 Python 绘制污染物玫瑰图

共 3548字,需浏览 8分钟

 ·

2019-10-22 23:21

1d6a14517fca051e474f816667bf64a6.webp


作者:沂水寒城,CSDN博客专家,个人研究方向:机器学习、深度学习、NLP、CV

Blog: http://yishuihancheng.blog.csdn.net

污染物玫瑰图是一个比较领域化和专业化的名词,主要是在环保数据分析领域中较为经常使用到,如果一开始就来说污染物玫瑰图可能不是很好理解,这里拿一个比较通用的实例来说明,就是风向玫瑰图。

为了更好地说明白风向玫瑰图这个学术化的名词我从百度百科找到了关于它的相关介绍,具体如下:

风向玫瑰图(简称风玫瑰图)也叫风向频率玫瑰图,它是根据某一地区多年平均统计的各个风向和风速的百分数值,并按一定比例绘制,一般多用8个或16个罗盘方位表示,由于形状酷似玫瑰花朵而得名。玫瑰图上所表示风的吹向,是指从外部吹向地区中心的方向,各方向上按统计数值画出的线段,表示此方向风频率的大小,线段越长表示该风向出现的次数越多。将各个方向上表示风频的线段按风速数值百分比绘制成不同颜色的分线段,即表示出各风向的平均风速,此类统计图称为风频风速玫瑰图。接下来简单看几个玫瑰图的实例,具体如下所示:

f41ae99d1798cce89b7463bcb1fbb92c.webp

借用echarts的极坐标堆叠柱状图也可以绘制出来类似的效果只不过暂时没有找到如何对不同区间的浓度值设定不同的颜色的方法,简单的效果图如下所示:

19da5ecf606e63d2673691aaa272d625.webp

在环保、气象等领域中,风向玫瑰图是非常常用的数据分析可视化手段,与此相关衍生出来的还有一种类似的玫瑰图——污染物玫瑰图,与风向玫瑰图相同的是,在具体计算逻辑以及整体形式上都是比较一致的,不同的是污染物玫瑰图主要是用于分析污染物溯源传播等相关的问题的,在可视化的时候叠加了污染物的浓度数据。

想要绘制污染物的玫瑰图首先我们需要获取到需要的因子浓度数据以及对应的气象数据,这里我们的数据来源于中央气象台以及中国环境监测总站,其中,前者提供了我们所需的气象数据,后者提供了我们所需的因子浓度监测数据。

中国环境检测总站首页数据区域截图如下:

83a196ec18d68328f21b8962236f17e0.webp

点击详情即可查看,这部分数据的采集我发现网上有开源的实现就直接拿来用了,所以这里就不多做介绍了,如有需要可以留言,我给你提供项目链接,能够获取城市的实时空气数据,包括AQI、pm2.5、pm10、co、o3、no2、so2、首要污染物、生活建议、污染描述等数据。

中央气象台中数据区域截图如下所示:

dce0bd9e812c5945b0f0efe5f94e5225.webp

这里我做了具体的实现,详细介绍请参考我的博客:
https://yishuihancheng.blog.csdn.net/article/details/99604953
到这里,我们的数据获取工作差不多就结束了,接下来就我们就开始绘制污染物玫瑰图,其实污染物玫瑰图本质上来说就是使用所需分析的污染物的浓度替换了原有的风速数据,将污染物的传播和分布情况借助于气象的数据展示了出来,在很多应用场景里面污染物玫瑰图都是很有帮助,能够有效地定位污染位置等信息。

之前的工作里面我从事过相关的研究项目,对于一些常用的工具模块都已有了比较完整的实现,这里可以很方便地进行调用,下面是具体的Demo代码实现:

def plotPollutionRoseDemo(value,direction,title,save_path='demo.png'):
    '''
    污染物可视化Demo
    '''

    plt.clf()
    ax=WindroseAxes.from_ax()
    ax.bar(direction,value,normed=True,opening=0.8,edgecolor='white')
    ax.set_legend(loc='best',bbox_to_anchor=(1.11.1))  #loc='lower center',ncol=3
    plt.title(title,chinese)
    plt.savefig(save_path)

绘图的代码真的是很简单的,下面是具体的结果:

cee37c736fe65275e05f2132e2ac6610.webp

我觉得还是蛮好看的,当然如果需要放到产品里面的话可能还需要进一步去美化一下。

之前有一些博友留言需要一下绘图的参数设置,这里我一并给出来,如果需要的话可以直接拿去使用:

import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['font.sans-serif']=['SimHei']  #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False  #用来正常显示负号
english={'family':'Times New Roman','weight':'normal','size':12}
chinese={'family':'SimHei','weight':'normal','size':12}
color_list=['#CD853F','#DC143C','#00FF7F','#FF6347','#8B008B','#00FFFF','#0000FF','#8B0000','#FF8C00',
            '#1E90FF','#00FF00','#FFD700','#008080','#008B8B','#8A2BE2','#228B22','#FA8072','#808080']

个人习惯,比较喜欢将一些参数项整合到字典里面封装其起来之后可以很方便地进行调用。

完成绘图模块的开发后,就可以开发API了,基于flask将本地的工具模块暴露成可以直接调用的API服务是比较常用的做法,这里的具体代码实现如下:

#!usr/bin/env python
# encoding:utf-8


import os
import sys
import time
import json
from flask import Flask
from flask import request
from flask import make_response
from flask import jsonify
from windRosePloter import *


app = Flask(__name__)
reload(sys)
sys.setdefaultencoding("utf-8")



@app.route("/")
def init():
    return u"风向玫瑰图模块正常启动!"    


@app.route('/onlinerose',methods=['GET'])
def windRoseFunc():
    '''
    风向玫瑰图可视化功能
    http://IP:port/onlinerose?host=localhost&user=username&passwd=passwd&port=3306&db=database&table=tablename&code=code&factor=pm25&start=2019-01-01 00:00:00&end=2019-09-30 23:00:00
    '''

    if request.method=='GET':
        host=request.args['host']
        user=request.args['user']
        passwd=request.args['passwd']
        port=request.args['port']
        db=request.args['db']
        table=request.args['table']
        code=request.args['code']
        factor=request.args['factor']
        start=request.args['start']
        end=request.args['end']
    mysql['host']=host
    mysql['user']=user
    mysql['passwd']=passwd
    mysql['port']=int(port)
    mysql['db']=db
    #数据获取
    select_sql="SELECT wd,"+factor+" FROM "+table+" where station_code='"+code+"' AND data_time>='"+\
               start+"' AND data_time<='"+end+"'"
    #print select_sql
    data=selectAllRecords(mysql, select_sql)
    result=[]
    for i in range(len(data)):
        if data[i][0and data[i][1and data[i][0]!='None'and data[i][1]!='None':
            result.append([float(data[i][0]),float(data[i][1])])
    dd=[float(data[i][0]) for i in range(len(data)) if data[i][0]]
    ff=[float(data[i][1]) for i in range(len(data)) if data[i][1]]
    length=min(len(dd),len(ff))
    wd=windDirectionTransform(dd)
    title=factor+u"因子风向玫瑰图"
    pic_path='rosePics/'+code+'_'+factor+'.png'
    plotPollutionRoseDemo(ff[:length],dd[:length],title,save_path=pic_path)
    image_data=open(pic_path,"rb").read()
    response=make_response(image_data)
    response.headers['Content-Type']='image/png'
    return response  


if __name__ == "__main__":
    app.run(host=0.0.0.0,port=5000)

完成上述API的开发工作后就可以进行使用分析了,下面是简单的实例测试结果:

d9ff94c9111276681eeeb5393168ae39.webp

29ed01052475b948497f6651a3429baf.webp

基于API实现工具方便的调用对于提升工作效率或者是辅助现场人员完成数据分析工作是很有帮助的。

很高兴在自己温习回顾知识的同时能写下点分享的东西出来,如果说您觉得我的内容还可以或者是对您有所启发、帮助,还希望得到您的鼓励支持!

觉得不错,点个在看呗

浏览 92
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报