作者:可以叫我才哥
本文转自公众号:可以叫我才哥
今年3月
, 北京时 隔 6
年 再次遭遇 沙尘暴 ,大家一起被迫吃土 !上次沙尘暴出现还是在2015年4月15日
。
记得那天早上起床,打开手机看到好多盆友发来的询问关怀“听说北京沙尘暴了,注意安全哦”,比心 ! 随后拉开窗帘,果然是漫天黄沙还伴随着大风,打开朋友圈满屏的银翼杀手
、末日
的关键字。
其实,我们看看北京最近15个月空气质量热力图发现,大部分的时间空气质量还是不错的,良好与优秀居多 。
注意:绿色(50以下) 表示优秀,黄色(50-100)表示良好,橙色及其他属于污染。
北京最近15个月空气质量热力图 上面这张热力图是用Python绘制的,今天就来讲一讲是如何做出来的。
目录:
0. 图赏
1. 空气质量数据获取
2. 数据预处理
3. 热力图绘制
3.1. seaborn的heatmap热力图
3.2. plotly的热力图绘制
4. 附
0. 图赏 鸟巢:
鸟巢 故宫角楼:
故宫角楼 大裤衩:
大裤衩 银翼杀手:
银翼杀手 我上班路上:
2021 年 03月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()
,其二是plotly
的ff.create_annotated_heatmap()
。
3.1. seaborn的heatmap热力图 import matplotlib.pyplot as pltimport matplotlib.colors as mcolorsimport 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 ffimport 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.941 , 9.012182 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , 10.811 , 12.0107 , 14.0067 , 15.9994 , 18.9984032 , 20.1797 ], [ 22.98976928 , 24.3050 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , 26.9815386 , 28.0855 , 30.973762 , 32.065 , 35.453 , 39.948 ], [ 39.0983 , 40.078 , 44.955912 , 47.867 , 50.9415 , 51.9961 , 54.938045 , 55.845 , 58.933195 , 58.6934 , 63.546 , 65.38 , 69.723 , 72.64 , 74.92160 , 78.96 , 79.904 , 83.798
], [ 85.4678 , 87.62 , 88.90585 , 91.224 , 92.90638 , 95.96 , 98 , 101.07 , 102.90550 , 106.42 , 107.8682 , 112.411 , 114.818 , 118.710 , 121.760 , 127.60 , 126.90447 , 131.293 ], [ 132.9054519 , 137.327 , .0 , 178.49 , 180.94788 , 183.84 , 186.207 , 190.23 , 192.217 , 195.084 , 196.966569 , 200.59 , 204.3833 , 207.2 , 208.98040 , 209 , 210 , 222 ], [223 , 226 , .0 , 267 , 268 , 271 , 272 , 270 , 276 , 281 , 280 , 285 , 284 , 289 , 288 , 293 , 'unknown' , 294 ], [.0 , .0 , 138.90547 , 140.116 , 140.90765 , 144.242 , 145
, 150.36 , 151.964 , 157.25 , 158.92535 , 162.500 , 164.93032 , 167.259 , 168.93421 , 173.054 , 174.9668 , .0 ], [.0 , .0 , 227 , 232.03806 , 231.03588 , 238.02891 , 237 , 244 , 243 , 247 , 247 , 251 , 252 , 257 , 258 , 259 , 262 , .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 , .0 , 1. ], [.1 , .2 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .0 , .7 , .8 , .8 , .8 , .9 , 1. ], [.1 , .2 , .0 , .0 , .0 , .0
, .0 , .0 , .0 , .0 , .0 , .0 , .6 , .7 , .8 , .8 , .9 , 1 ], [.1 , .2 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .6 , .7 , .8 , .8 , .9 , 1. ], [.1 , .2 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .6 , .6 , .7 , .7 , .9 , 1. ], [.1 , .2 , .4 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .6 , .6 , .6 , .7
, .9 , 1. ], [.1 , .2 , .5 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .3 , .6 , .6 , .6 , .6 , .9 , 1. ], [.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 , .8 , 1. , 1. , 1. , .0 , .0 , .0 ]]# Display element name and atomic mass on hover hover=[]for x in range(len(symbol)): hover.append([i + ' ' + '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()
以上就是本次全部内容,演示代码 ipynb 文件: https://pan.baidu.com/s/1iR8E8OAJ0KCm5Cw840Ellg