好文推薦:用 Python 繪制污染物玫瑰圖

作者:沂水寒城,CSDN博客專家,個(gè)人研究方向:機(jī)器學(xué)習(xí)、深度學(xué)習(xí)、NLP、CV
Blog:?http://yishuihancheng.blog.csdn.net
污染物玫瑰圖是一個(gè)比較領(lǐng)域化和專業(yè)化的名詞,主要是在環(huán)保數(shù)據(jù)分析領(lǐng)域中較為經(jīng)常使用到,如果一開(kāi)始就來(lái)說(shuō)污染物玫瑰圖可能不是很好理解,這里拿一個(gè)比較通用的實(shí)例來(lái)說(shuō)明,就是風(fēng)向玫瑰圖。
為了更好地說(shuō)明白風(fēng)向玫瑰圖這個(gè)學(xué)術(shù)化的名詞我從百度百科找到了關(guān)于它的相關(guān)介紹,具體如下:
風(fēng)向玫瑰圖(簡(jiǎn)稱風(fēng)玫瑰圖)也叫風(fēng)向頻率玫瑰圖,它是根據(jù)某一地區(qū)多年平均統(tǒng)計(jì)的各個(gè)風(fēng)向和風(fēng)速的百分?jǐn)?shù)值,并按一定比例繪制,一般多用8個(gè)或16個(gè)羅盤(pán)方位表示,由于形狀酷似玫瑰花朵而得名。玫瑰圖上所表示風(fēng)的吹向,是指從外部吹向地區(qū)中心的方向,各方向上按統(tǒng)計(jì)數(shù)值畫(huà)出的線段,表示此方向風(fēng)頻率的大小,線段越長(zhǎng)表示該風(fēng)向出現(xiàn)的次數(shù)越多。將各個(gè)方向上表示風(fēng)頻的線段按風(fēng)速數(shù)值百分比繪制成不同顏色的分線段,即表示出各風(fēng)向的平均風(fēng)速,此類統(tǒng)計(jì)圖稱為風(fēng)頻風(fēng)速玫瑰圖。接下來(lái)簡(jiǎn)單看幾個(gè)玫瑰圖的實(shí)例,具體如下所示:

借用echarts的極坐標(biāo)堆疊柱狀圖也可以繪制出來(lái)類似的效果只不過(guò)暫時(shí)沒(méi)有找到如何對(duì)不同區(qū)間的濃度值設(shè)定不同的顏色的方法,簡(jiǎn)單的效果圖如下所示:

在環(huán)保、氣象等領(lǐng)域中,風(fēng)向玫瑰圖是非常常用的數(shù)據(jù)分析可視化手段,與此相關(guān)衍生出來(lái)的還有一種類似的玫瑰圖——污染物玫瑰圖,與風(fēng)向玫瑰圖相同的是,在具體計(jì)算邏輯以及整體形式上都是比較一致的,不同的是污染物玫瑰圖主要是用于分析污染物溯源傳播等相關(guān)的問(wèn)題的,在可視化的時(shí)候疊加了污染物的濃度數(shù)據(jù)。
想要繪制污染物的玫瑰圖首先我們需要獲取到需要的因子濃度數(shù)據(jù)以及對(duì)應(yīng)的氣象數(shù)據(jù),這里我們的數(shù)據(jù)來(lái)源于中央氣象臺(tái)以及中國(guó)環(huán)境監(jiān)測(cè)總站,其中,前者提供了我們所需的氣象數(shù)據(jù),后者提供了我們所需的因子濃度監(jiān)測(cè)數(shù)據(jù)。
中國(guó)環(huán)境檢測(cè)總站首頁(yè)數(shù)據(jù)區(qū)域截圖如下:

點(diǎn)擊詳情即可查看,這部分?jǐn)?shù)據(jù)的采集我發(fā)現(xiàn)網(wǎng)上有開(kāi)源的實(shí)現(xiàn)就直接拿來(lái)用了,所以這里就不多做介紹了,如有需要可以留言,我給你提供項(xiàng)目鏈接,能夠獲取城市的實(shí)時(shí)空氣數(shù)據(jù),包括AQI、pm2.5、pm10、co、o3、no2、so2、首要污染物、生活建議、污染描述等數(shù)據(jù)。
中央氣象臺(tái)中數(shù)據(jù)區(qū)域截圖如下所示:

這里我做了具體的實(shí)現(xiàn),詳細(xì)介紹請(qǐng)參考我的博客:
https://yishuihancheng.blog.csdn.net/article/details/99604953
到這里,我們的數(shù)據(jù)獲取工作差不多就結(jié)束了,接下來(lái)就我們就開(kāi)始繪制污染物玫瑰圖,其實(shí)污染物玫瑰圖本質(zhì)上來(lái)說(shuō)就是使用所需分析的污染物的濃度替換了原有的風(fēng)速數(shù)據(jù),將污染物的傳播和分布情況借助于氣象的數(shù)據(jù)展示了出來(lái),在很多應(yīng)用場(chǎng)景里面污染物玫瑰圖都是很有幫助,能夠有效地定位污染位置等信息。
之前的工作里面我從事過(guò)相關(guān)的研究項(xiàng)目,對(duì)于一些常用的工具模塊都已有了比較完整的實(shí)現(xiàn),這里可以很方便地進(jìn)行調(diào)用,下面是具體的Demo代碼實(shí)現(xiàn):
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.1,?1.1))??#loc='lower?center',ncol=3
????plt.title(title,chinese)
????plt.savefig(save_path)
繪圖的代碼真的是很簡(jiǎn)單的,下面是具體的結(jié)果:

我覺(jué)得還是蠻好看的,當(dāng)然如果需要放到產(chǎn)品里面的話可能還需要進(jìn)一步去美化一下。
之前有一些博友留言需要一下繪圖的參數(shù)設(shè)置,這里我一并給出來(lái),如果需要的話可以直接拿去使用:
import?matplotlib?as?mpl
mpl.rcParams['font.sans-serif']?=?['SimHei']
plt.rcParams['font.sans-serif']=['SimHei']??#用來(lái)正常顯示中文標(biāo)簽
plt.rcParams['axes.unicode_minus']=False??#用來(lái)正常顯示負(fù)號(hào)
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']
個(gè)人習(xí)慣,比較喜歡將一些參數(shù)項(xiàng)整合到字典里面封裝其起來(lái)之后可以很方便地進(jìn)行調(diào)用。
完成繪圖模塊的開(kāi)發(fā)后,就可以開(kāi)發(fā)API了,基于flask將本地的工具模塊暴露成可以直接調(diào)用的API服務(wù)是比較常用的做法,這里的具體代碼實(shí)現(xiàn)如下:
#!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"風(fēng)向玫瑰圖模塊正常啟動(dòng)!"????
@app.route('/onlinerose',methods=['GET'])
def?windRoseFunc():
????'''
????風(fēng)向玫瑰圖可視化功能
????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
????#數(shù)據(jù)獲取
????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][0]?and?data[i][1]?and?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"因子風(fēng)向玫瑰圖"
????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的開(kāi)發(fā)工作后就可以進(jìn)行使用分析了,下面是簡(jiǎn)單的實(shí)例測(cè)試結(jié)果:


基于API實(shí)現(xiàn)工具方便的調(diào)用對(duì)于提升工作效率或者是輔助現(xiàn)場(chǎng)人員完成數(shù)據(jù)分析工作是很有幫助的。
很高興在自己溫習(xí)回顧知識(shí)的同時(shí)能寫(xiě)下點(diǎn)分享的東西出來(lái),如果說(shuō)您覺(jué)得我的內(nèi)容還可以或者是對(duì)您有所啟發(fā)、幫助,還希望得到您的鼓勵(lì)支持!
覺(jué)得不錯(cuò),點(diǎn)個(gè)在看唄!
