用Python绘制北京近一年来空气质量热力图,看看北京的沙尘暴真的多吗?

Python编程与实战

共 21039字,需浏览 43分钟

 ·

2021-03-30 11:17



大家好,我是村长。

3月15日北京迎来了近6年来的首次沙尘暴,是被迫吃土的一天!!上次沙尘暴出现还是在2015年4月15日

记得早上起床,打开手机看到好多盆友发来的询问关怀“听说北京沙尘暴了,注意安全哦”,比心 ! 随后拉开窗帘,果然是漫天黄沙还伴随着大风,打开朋友圈满屏的银翼杀手末日的关键字。

其实,我们看看北京最近15个月空气质量热力图发现,大部分的时间空气质量还是不错的在良好与优秀之间

注意:绿色(50以下) 表示优秀,黄色(50-100)表示良好,橙色开始属于污染。

公众号回复 0316 可以获取全部演示代码ipynb文件!

北京最近15个月空气质量热力图

接下来,我们 来一起试着利用python绘制上面这张热力图吧!

目录:

  • 0. 图赏

  • 1. 空气质量数据获取

  • 2. 数据预处理

  • 3. 热力图绘制

    • 3.1. seaborn的heatmap热力图

    • 3.2. plotly的热力图绘制

  • 4. 附

0. 图赏

鸟巢:

鸟巢

故宫角楼:

故宫角楼

大裤衩:

大裤衩

银翼杀手:

银翼杀手

我上班路上:

202103月15日早上10点上班路上

1. 空气质量数据获取

这里我们从akshare库的接口直接获取北京市历史空气质量数据

import akshare as ak

air_quality_hist_df = ak.air_quality_hist(city="北京", period="day", start_date="2020-01-01", end_date="2021-03-15")
air_quality_hist_df.head()
请求的数据预览

2. 数据预处理

由于绘制热力图x轴是日期(1-31),y轴是年月。因此我们需要对原数据进行宽表转化和一些简单的预处理。

注意:处理过程详情代码注释说明。

import pandas as pd

# 拷贝并进行索引重置
df = air_quality_hist_df[['aqi']].copy()
df.reset_index(inplace=True)
# 将time字段改为时间格式
df.time = pd.to_datetime(df.time)
# 新增年月字段,内容为 x年x月,如2021年3月,为字符串格式
df['年月'] = df.time.apply(lambda x:x.strftime('%Y{y}%m{m}').format(y="年",m="月"))
# 新增日期字段,内容为 1-31
df['日期'] = df['time'].dt.day

# 做透视处理,将长表转化为宽表
data = pd.pivot(df,
                values='aqi',
                index='年月',
                columns='日期')
# 转化后部分月份不存在部分日期默认为nan值,需要转化为数字格式 float(无法转化为int)
data = data.astype('float')
# 按照 索引年月倒序排序
data.sort_index(ascending=False,inplace=True)

data.head()
处理后数据预览

3. 热力图绘制

这里我们介绍两种热力图绘制手法,其一是sns.heatmap(),其二是plotlyff.create_annotated_heatmap()

3.1. seaborn的heatmap热力图

import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import seaborn as sns

#设置全局默认字体 为 雅黑
plt.rcParams['font.family'] = ['Microsoft YaHei'
# 设置全局轴标签字典大小
plt.rcParams["axes.labelsize"] = 14  
# 设置背景
sns.set_style("darkgrid",{"font.family":['Microsoft YaHei''SimHei']})  
# 设置画布长宽 和 dpi
plt.figure(figsize=(18,8),dpi=100)
# 自定义色卡
cmap = mcolors.LinearSegmentedColormap.from_list("n",['#95B359','#D3CF63','#E0991D','#D96161','#A257D0','#7B1216']) 
# 绘制热力图
ax = sns.heatmap( data, cmap=cmap, vmax=300
                 annot=True# 热力图上显示数值
                 fmt='0.f'# 数值格式
                 linewidths=0.5,) 
ax.set_title( label='北京最近15个月空气质量AQI',fontdict = {'fontsize'16})
# 将x轴刻度放在最上面
ax.xaxis.set_ticks_position('top'
效果

3.2. plotly的热力图绘制

对于plotly来说,plotly.express可以直接将满足条件格式的dataframe数据用px.imshow()绘制,不过试了很久暂时没学会怎么方便的将数值显示在热力图上。找了半天发现plotly提供另外一种方式create_annotated_heatmap,专门用来显示数值。

px.imshow方法:

import plotly.express as px
# import plotly.graph_objs as go

fig = px.imshow(data,
               color_continuous_scale='Temps'
               color_continuous_midpoint= 75 ,
               range_color = [0,300],
               title = '北京最近15个月空气质量AQI',
               width=1200,
               height=711,
               )
fig.update_layout(xaxis=dict(tickmode='linear'), # x轴全部显示
                 )
fig.show()
px.imshow方法

create_annotated_heatmap方法:

以下重点介绍该方法

  • 由于绘图的时候 顺序和之前是反的,所以需要先进行顺序逆序调整;
  • 为了更好的根据aqi数值进行颜色分配,我们可以对数据进行分箱操作;
  • 为了让颜色和空气质量指数级别色卡一致,我们可以自定义颜色色卡;
  • 为了更好的在热力图上显示数值,需要将原来的float转化为int,nan转化为空字符。
# 数据分箱操作
data.sort_index(ascending=True,inplace=True)
bins = [0,50,100,150,200,300,999]
groups = [.1,.2,.3,.4,.5,.6]
data1 = data.apply(lambda x: pd.cut(x,bins,labels=groups))
data1.head()
数据预览
import plotly.figure_factory as ff
import numpy as np

x = list(data.columns)
y = list(data.index)
z = data1.values.tolist()
z_text = data3.fillna('').values.tolist() # data3 为初始未进行格式转化的透视宽表
# 自定义色卡
colorscale=[[0.0'rgb(0,153,102)'], [.1'rgb(211, 207, 99)'],
            [.3'rgb(255, 153, 51)'], [.4'rgb(204, 97, 51)'],
            [.5'rgb(102, 0, 153)'],[1.0'rgb(126, 0, 35)']]

fig = ff.create_annotated_heatmap(z, x=x, y=y, 
                                  annotation_text=z_text, 
                                  colorscale=colorscale,
                                 )
fig.update_layout(title ='北京最近15个月空气质量AQI',
                   width=1200,
                   height=711,
                 )
# 将x轴刻度放在最上面
fig.update_xaxes(side="top")
fig.show()
北京最近15个月空气质量AQI

4. 附

空气质量指数色卡对照表:

空气质量评级

matplotlib 热力图绘制参考

https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html

plotly元素周期表绘制案例:

元素周期表
# Add Periodic Table Data
symbol = [['H''''''''''''''''''''''''''''''''''He'],
         ['Li''Be''''''''''''''''''''''B''C''N''O''F''Ne'],
         ['Na''Mg''''''''''''''''''''''Al''Si''P''S''Cl''Ar'],
         ['K''Ca''Sc''Ti''V''Cr''Mn''Fe''Co''Ni''Cu''Zn''Ga''Ge''As''Se''Br''Kr'],
         ['Rb ''Sr''Y''Zr''Nb''Mo''Tc''Ru''Rh''Pd''Ag''Cd''In''Sn''Sb''Te''I''Xe' ],
         ['Cs''Ba''''Hf''Ta''W''Re''Os''Ir''Pt''Au''Hg''Tl''Pb''Bi''Po''At''Rn' ],
         ['Fr''Ra''''Rf''Db''Sg''Bh''Hs''Mt''Ds''Rg''Cn''Uut''Fl''Uup''Lv''Uus''Uuo'],
         ['''''La''Ce''Pr''Nd''Pm''Sm''Eu''Gd''Tb''Dy''Ho''Er''Tm''Yb''Lu'''],
         ['''''Ac''Th''Pa''U''Np''Pu''Am''Cm''Bk''Cf''Es''Fm''Md''No''Lr''' ],
         [''''''''''''''''''''''''''''''''''''],
         ['''Alkali Metal''''''Transition Metal''''''Actinide''''''Semimetal''''''Halogen'''''''''],
         ['''Alkaline Metal''''''Lanthanide''''''Basic Metal''''''Nonmetal''''''Noble Gas''''''''']]

element = [['Hydrogen''''''''''''''''''''''''''''''''''Helium'],
           ['Lithium''Beryllium''''''''''''''''''''''Boron''Carbon''Nitrogen''Oxygen''Fluorine''Neon'],
           ['Sodium''Magnesium''''''''''''''''''''''Aluminium''Silicon''Phosphorus''Sulfur''Chlorine'' Argon'],
           ['Potassium'' Calcium'' Scandium'' Titanium'' Vanadium'' Chromium',  'Manganese''Iron''Cobalt''Nickel''Copper''Zinc''Gallium''Germanium''Arsenic''Selenium''Bromine''Krypton'],
           ['Rubidium''Strontium''Yttrium''Zirconium''Niobium''Molybdenum''Technetium''Ruthenium''Rhodium''Palladium''Silver''Cadmium''Indium''Tin''Antimony''Tellurium''Iodine''Xenon'],
           [' Cesium'' Barium''',  'Hafnium''Tantalum''Tungsten''Rhenium''Osmium''Iridium''Platinum''Gold''Mercury''Thallium''Lead''Bismuth''Polonium''Astatine''Radon'],
           [' Francium'' Radium''''Rutherfordium','Dubnium','Seaborgium','Bohrium','Hassium','Meitnerium','Darmstadtium','Roentgenium','Copernicium','Ununtrium','Ununquadium','Ununpentium','Ununhexium','Ununseptium','Ununoctium'],
           ['''',  'Lanthanum''Cerium''Praseodymium''Neodymium''Promethium''Samarium''Europium''Gadolinium''Terbium''Dysprosium''Holmium''Erbium''Thulium''Ytterbium''Lutetium'''],
           ['''''Actinium''Thorium''Protactinium''Uranium''Neptunium''Plutonium''Americium''Curium''Berkelium''Californium''Einsteinium','Fermium' ,'Mendelevium''Nobelium''Lawrencium''' ],
           [''''''''''''''''''''''''''''''''''''],
           [''''''''''''''''''''''''''''''''''''],
           ['''''''''''''''''''''''''''''''''''']]

atomic_mass = [[ 1.00794.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0,  4.002602],
     [ 6.9419.012182.0.0.0.0.0.0.0.0.0.0,  10.81112.010714.006715.999418.998403220.1797],
     [ 22.9897692824.3050.0.0.0.0.0.0.0.0.0.0,  26.981538628.085530.97376232.06535.45339.948],
     [ 39.098340.07844.95591247.86750.941551.996154.93804555.84558.93319558.693463.54665.3869.72372.6474.9216078.9679.90483.798],
     [ 85.467887.6288.9058591.22492.9063895.9698101.07102.90550106.42107.8682112.411114.818118.710121.760127.60126.90447131.293],
     [ 132.9054519137.327.0178.49180.94788183.84186.207190.23192.217195.084196.966569200.59204.3833207.2208.98040209210222],
     [223226.0267268271272270276281280285284289288293'unknown'294],
     [.0.0138.90547140.116140.90765144.242145150.36151.964157.25158.92535162.500164.93032167.259168.93421173.054174.9668.0],
     [.0.0227232.03806231.03588238.02891237244243247247251252257258259262.0],
     [.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0],
     [.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0],
     [.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0]]

z = [[.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.01.],
     [.1.2.0.0.0.0.0.0.0.0.0.0.7.8.8.8.91.],
     [.1.2.0.0.0.0.0.0.0.0.0.0.6.7.8.8.91],
     [.1.2.3.3.3.3.3.3.3.3.3.3.6.7.8.8.91.],
     [.1.2.3.3.3.3.3.3.3.3.3.3.6.6.7.7.91.],
     [.1.2.4.3.3.3.3.3.3.3.3.3.6.6.6.7.91.],
     [.1.2.5.3.3.3.3.3.3.3.3.3.6.6.6.6.91.],
     [.0.0.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.0],
     [.0.0.5.5.5.5.5.5.5.5.5.5.5.5.5.5.5.0],
     [.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0],
     [.1.1.1.3.3.3.5.5.5.7.7.7.9.9.9.0.0.0],
     [.2.2.2.4.4.4.6.6.6.8.8.81.1.1..0.0.0]]

# Display element name and atomic mass on hover
hover=[]
for x in range(len(symbol)):
    hover.append([i + '<br>' + 'Atomic Mass: ' + str(j)
                      for i, j in zip(element[x], atomic_mass[x])])

# Invert Matrices
symbol = symbol[::-1]
hover = hover[::-1]
z = z[::-1]

# Set Colorscale
colorscale=[[0.0'rgb(255,255,255)'], [.2'rgb(255, 255, 153)'],
            [.4'rgb(153, 255, 204)'], [.6'rgb(179, 217, 255)'],
            [.8'rgb(240, 179, 255)'],[1.0'rgb(255, 77, 148)']]

# Make Annotated Heatmap
fig = ff.create_annotated_heatmap(z, annotation_text=symbol, text=hover,
                                 colorscale=colorscale, font_colors=['black'], hoverinfo='text')
fig.update_layout(title_text='Periodic Table')
fig.show()

以上就是本次全部内容,欢迎大家分享转发,点赞在看~

别忘了,回复 北京 领取演示文件哦!



用 Python 写了一个窃取摄像头照片的软件


任务队列神器:Celery 入门到进阶指南



浏览 48
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

分享
举报