好奇心Log 发表于 2024-5-5 22:54:03

Python可视化 | 长沙城市气象报告可视化展示

本帖最后由 好奇心Log 于 2024-5-5 23:00 编辑

来源:https://zhuanlan.zhihu.com/p/58100920

为探索长沙天气,本着科学分析的态度,搜集长沙相关数据后,决定做一期关于长沙历年气象的分析报告。

本文简单记录了整个工作流程,以此方便其他地区的朋友参照本范例科学分析。
<i>
import math#数学基本库
import re    #正则库,对原始格式数据进行分割筛选

import matplotlib.pyplot as plt #绘图
import pandas as pd
import matplotlib.image as mpimg
from matplotlib.ticker import MultipleLocator, FuncFormatter
from pandas import DataFrame

ISTEST = False</i>几个基本函数
hsv转rgb函数
<i># hsv转rgb
def hsv2rgb(h, s, v):
    h = float(h)
    s = float(s)
    v = float(v)
    h60 = h / 60.0
    h60f = math.floor(h60)
    hi = int(h60f) % 6
    f = h60 - h60f
    p = v * (1 - s)
    q = v * (1 - f * s)
    t = v * (1 - (1 - f) * s)
    r, g, b = 0, 0, 0
    if hi == 0:
      r, g, b = v, t, p
    elif hi == 1:
      r, g, b = q, v, p
    elif hi == 2:
      r, g, b = p, v, t
    elif hi == 3:
      r, g, b = p, q, v
    elif hi == 4:
      r, g, b = t, p, v
    elif hi == 5:
      r, g, b = v, p, q
    r, g, b = int(r * 255), int(g * 255), int(b * 255)
    return r, g, b</i>
rgb转16
<i>

# rgb转16#
def color(value):
    digit = list(map(str, range(10))) + list("ABCDEF")
    if isinstance(value, tuple):
      string = '#'
      for i in value:
            a1 = i // 16
            a2 = i % 16
            string += digit + digit
      return string
   </i><i>
# 月份格式
def month_formatter(x, pos):
    v = int(x / 31) + 1
    if v > 12:
      return '-'
    else:
      return str(v)</i>
自定义了一个计算连续天数的函数,稍微复杂一些所以不适合用lambda表达式来直接写。基本思路为循环结果集中的所有数据,遇到连续索引的日期就进行累加,当累加超过之前保存过的最大值时就覆盖掉之前的记录,所有结果循环完毕之后,最后留下的记录就是最大值记录。
<i>
# 计算事件发生连续天数
def continue_count(_df):
    _count = 0
    _index = 0
    _maxCount = 0
    _maxDayIndex = 0
    _maxDesc = ''
    for i in _df['dayIndex']:
      if i - _index == 1:
            _count += 1
            if _count > _maxCount:
                _maxCount = _count
                _maxDayIndex = i - _maxCount + 1
                _maxDesc = _df == _maxDayIndex].index
      else:
            _count = 1
      _index = i
    _tdf = DataFrame(
      {'year': ], 'maxCount': , 'maxDayIndex': , 'maxDesc': _maxDesc})
    return _tdf</i>
数据读取以及整理
虽然获得的数据结构已经比较清晰,但是还不能拿来直接用,我们需要把逐月数据转换成逐天数据,然后保存到DataFrame里。
<i>
stationID = 'CHM00057679'

df_PRCP = DataFrame(columns=['datetime', 'year', 'month', 'day', 'dayIndex', 'value', 'color'])# 降雨数据
df_TAVG = DataFrame(columns=['datetime', 'year', 'month', 'day', 'dayIndex', 'value', 'color'])# 平均气温数据
df_TMAX = DataFrame(columns=['datetime', 'year', 'month', 'day', 'dayIndex', 'value'])# 最高气温数据
df_TMIN = DataFrame(columns=['datetime', 'year', 'month', 'day', 'dayIndex', 'value'])# 最低气温数据

tMax = 0
tMaxTime = ''
tMin = 0
tMinTime = ''

pMax = 0
pMaxTime = ''
</i>
然后对dly文件进行逐行(逐月)读取,将单行进行字符串的分割,取出时间以及每个单日数据

读数据时间较长请耐心等待
<i>
# 导入数据
with open('/home/' + stationID + '.dly', 'r') as f1:
    dataList = f1.readlines()

pdi = 0# 降雨天数索引
tdi = 0# 气温天数索引

for _d in dataList:

    _res = re.split("\s+|s|S", _d)# 使用正则对字符串进行分割
    _date_res = list(filter(lambda x: x != '', _res))# 清除结果集中的空字符串

    _title = _date_res# 结果数组中的第一位为索引
    _year = _title.replace(stationID, '')# 获取年
    _month = _title.replace(stationID, '')# 获取月
    _type = _title.replace(stationID, '')# 获取数据类型
##    print('loding ' + str(_year) + str(_month))

    # 结果集中的后续内容为日数据值
    for i in range(1, len(_date_res)):
      _datetime = str(_year) + '-' + str(_month) + '-' + str(i)

      # 降雨记录
      if _type == 'PRCP':

            if _month == '01' and i == 1:
                pdi = 1
            else:
                pdi += 1

            _value = float(_date_res) / 10# 降雨量为 value / 10

            # 记录历史降雨量最高日期
            if _value > pMax:
                pMax = _value
                pMaxTime = _year + '/' + _month + '/' + str(i)

            _color = '#FFFFFF'
            if _value > 0:
                _color = color(tuple(hsv2rgb(int(_value * 0.75) + 180, 1, 1)))# 设置数据颜色值
            elif _value != -999.9:
                _color = '#FFFFFF'
            _df = DataFrame({'datetime': , 'year': , 'month': , 'day': , 'dayIndex': ,
                           'value': , 'color': })
            df_PRCP = df_PRCP.append(_df, ignore_index=True)# 将单行数据添加至总DF中

      # 平均气温记录
      elif _type == 'TAVG':

            if _month == '01' and i == 1:
                tdi = 1
            else:
                tdi += 1

            _value = str(_date_res).find('T') == True and -9999 or float(_date_res) / 10# 温度为 value / 10


            _color = '#FFFFFF'
            if _value != -999.9:
                _color = color(tuple(hsv2rgb(int(-7 * _value) + 240, 1, 1)))# 设置数据颜色值
            _df = DataFrame({'datetime': , 'year': , 'month': , 'day': , 'dayIndex': ,
                           'value': , 'color': })
            df_TAVG = df_TAVG.append(_df, ignore_index=True)

      # 最高气温记录
      elif _type == 'TMAX':

            _value = str(_date_res).find('T') == True and 0 or float(_date_res) / 10
            if _value > tMax and _value < 100:
                tMax = _value
                tMaxTime = _year + '/' + _month + '/' + str(i)

      # 最低气温记录
      elif _type == 'TMIN':

            _value = str(_date_res).find('T') == True and 0 or float(_date_res) / 10
            if _value < tMin and _value > -100:
                tMin = _value
                tMinTime = _year + '/' + _month + '/' + str(i)

    # 调试使用,避免数据加载时间过长
    if len(df_PRCP) and len(df_TAVG) > 100000:
      break
</i>
这里有两个循环,一个循环是dly文本文件的逐行读取,另一个循环是每一行中每一天的列数值读取和创建一行日数据df。获取并组合成新的日数据df之后,就可以添加进之前创建的指定类型的空DataFrame中。这里只截图了PRCP(降雨统计)的部分,其他部分同理。

关于数据显示时的颜色值,这里用了HSV颜色模型的思路,通过改变H(色相)值,来实现通过颜色表示数据大小的效果。实际也可以不需要,只是为了显示时更好看一些而已。详细代码在基本函数里。

可视化绘制

一、散点图绘制
以PRCP为例:绘制图表可以调用Maltplotlib.pyplot库下的各个方法。其中绘制散点图的方法为scatter(),参数中x轴填入日索引(当年的第几天)集合,y轴填入当日降雨量集合,s表示点的大小,这里设置为40,c表示颜色,可以使用固定字符串或者之前设置匹配数值的颜色集合。marker表示点的形状,alpha表示点的透明度。

df_PRCP = df_PRCP.set_index('datetime')
df_TAVG = df_TAVG.set_index('datetime')
# 画布基础设置
#if 1 == 0:
plt.rcParams['figure.figsize'] = (10.0, 6.0)# 设置figure_size尺寸

plt.rcParams['image.cmap'] = 'gray'# 设置 颜色 style

plt.rcParams['figure.dpi'] = 200# 分辨率
plt.rcParams['savefig.dpi'] = 200# 图片像素
plt.rcParams['image.interpolation'] = 'nearest'# 设置 interpolation style
# 柱状图
<i># PRCP散点图
plt.gca().xaxis.set_major_locator(MultipleLocator(31))# 设置x轴的刻度间隔
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))# 设置x轴的显示数值
plt.gca().yaxis.set_major_locator(plt.MultipleLocator(10))# 设置y轴的刻度间隔
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: str(y * 10) + 'mm'))# 设置y轴的显示数值
plt.gca().grid()# 开启网格

plt.scatter(df_PRCP['dayIndex'], df_PRCP['value'], s=40, c=df_PRCP['color'], marker='.', alpha=0.5)# 散点图绘制
plt.xlim(0, 365)# 设置x轴的坐标范围
plt.ylim(1, 250)# 设置y轴的坐标范围

plt.title('PRCP : 1951-2019')
plt.xlabel("Month")
plt.ylabel("Precipitation mm")

if ISTEST == False:
    plt.savefig("PRCP.png")# 保存图片

plt.show()</i>
每一个点表示70年中某一天的值,通过这张图就可以大概看出历年降雨量和日期的关系,以及分布情况。

平均气温TAVG也有一张散点图,用来展示历年气温分布和日期的关系,和PRCP的显示方法相同,因此这里就不再重复说明。

长沙历史平均气温散点图

# TAVG
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().grid()# 网格
# plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
plt.scatter(df_TAVG['dayIndex'], df_TAVG['value'], s=80, c=df_TAVG['color'], marker='.', alpha=0.05)
plt.xlim(0, 365)
plt.ylim(-30, 50)
plt.gca().yaxis.set_major_locator(plt.MultipleLocator(10))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: str(x) + 'C°'))

plt.title('TAVG : 1951-2019')
plt.xlabel("Month")
plt.ylabel("Temperature C°")

if ISTEST == False:
    plt.savefig("TAVG.png") # 保存图片

plt.show()
长沙历史气温分布散点图

# TAVG补温度显示
plt.scatter(df_TAVG['dayIndex'], df_TAVG['year'], s=20, c=df_TAVG['color'], marker='|', alpha=1)# 散点图绘制
plt.xlabel("Month")
plt.ylabel("Year")
plt.title("Historical TAVG Show : 1951-2019")

# 设置主刻度
plt.xlim(0, 365)
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().yaxis.set_major_locator(MultipleLocator(5))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1951)))
# 设置次刻度
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.gca().yaxis.set_minor_locator(MultipleLocator(1))

# 打开网格
plt.gca().xaxis.grid(True, which='major')# x坐标轴的网格使用主刻度
plt.gca().yaxis.grid(True, which='minor')# y坐标轴的网格使用次刻度
if ISTEST == False:
    plt.savefig("Historical TAVG Show.png")# 保存图片
plt.show()

PCRP补充长沙历史降水展示图


df_rainyAll = df_PRCP > 0]
plt.scatter(df_rainyAll['dayIndex'], df_rainyAll['year'], s=20, c=df_rainyAll['color'], marker='|', alpha=1)# 散点图绘制
plt.xlabel("Month")
plt.ylabel("Year")
plt.title("Historical Rainy Show : 1951-2019")

# 设置主刻度
plt.xlim(0, 365)
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().yaxis.set_major_locator(MultipleLocator(5))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1951)))
# 设置次刻度
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.gca().yaxis.set_minor_locator(MultipleLocator(1))

# 打开网格
plt.gca().xaxis.grid(True, which='major')# x坐标轴的网格使用主刻度
plt.gca().yaxis.grid(True, which='minor')# y坐标轴的网格使用次刻度
if ISTEST == False:
    plt.savefig("Historical Rainy Show.png")# 保存图片
plt.show()

二、线性图绘制
在本步骤中我们将用线性图来展示数据在逐年中的变化情况。需要统计的数据有:单个年份中有降雨的天数,炎热(TAVG > 30°C)天数以及寒冷(TAVG < 10°C)

通过DataFrame的groupby()方法来将逐日数据按照年份进行分组,之后再使用count()方法对分组进行计数统计,产生的数据集即为我们需要的年统计数据。

# 年降雨天数统计
#统计数据代码:
se_rainyD = (df_PRCP > 0]).groupby('year')['value'].count()
df_rainyD = se_rainyD.to_frame('rainyDays')
# 年低温天数统计
se_LowT = (df_TAVG[(df_TAVG['value'] < 10) & (df_TAVG['value'] > -100)]).groupby('year')['value'].count()
df_LowT = se_LowT.to_frame('coldDays')
# 年高温天数统计
se_HighT = (df_TAVG > 30]).groupby('year')['value'].count()
df_HighT = se_HighT.to_frame('hotDays')
# 汇总
df_YearCount = pd.concat(, axis=1, sort=False)
#绘制线性图代码:
plt.plot(df_YearCount.index, df_YearCount['coldDays'], label='coldDays')
plt.plot(df_YearCount.index, df_YearCount['hotDays'], label='hotDays')
plt.plot(df_YearCount.index, df_YearCount['rainyDays'], label='rainyDays')
plt.gca().xaxis.set_major_locator(MultipleLocator(5))
plt.gca().xaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1950)))

plt.legend()# 显示图例Tips
plt.gca().grid()# 打开网格
plt.xlabel("Year")
plt.ylabel("Count Day")
plt.title("Historical Weather Count : 1951-2019")
if ISTEST == False:
    plt.savefig("Historical Weather Count.png")# 保存图片
plt.show()
注意:上图为在同一张画布上调用三次plot()方法,分别绘制年降雨天数、年高温天数、年低温天数这三个数据集的逐年线性变化曲线

三、柱状图绘制
之后我们还需要再统计两类直观数据,即历史上同一天的事件发生频率(如某一天的历史降雨频率)以及所有年份中事件连续发生的最值和时间段(如每一年连续降雨最长天数以及发生的日期)。

首先是事件发生频率图,以降雨为例:

长沙历年降雨频率统计图

# 历史同日降雨次数统计
se_HisRainyD = (df_PRCP > 0]).groupby('dayIndex')['value'].count()

plt.xlabel("Month")
plt.ylabel("Probability %")
plt.title("Historical Same Day Rainy Count : 1951-2019")
plt.bar(se_HisRainyD.index, se_HisRainyD / len(df_PRCP.groupby('year')) * 100,
      color=list(map(lambda v: color(tuple(hsv2rgb(int(2.4 * v) + 120, 1, 1))), se_HisRainyD.values)))

plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().grid()# 打开网格
plt.xlim(0, 365)
plt.ylim(0, 100)
plt.gca().yaxis.set_major_locator(plt.MultipleLocator(10))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: str(y * 10 - 10) + '%'))
if ISTEST == False:
    plt.savefig("Historical Same Day Rainy Count.png")# 保存图片
plt.show()

事件发生频率还可用于统计历史年份某一天严寒或者酷暑的概率,数据集的筛选方式不同但原理相同。

接下来就是我们最后的一类数据分析了,即事件连续发生天数逐年最值以及发生日期。这里仍旧分析降雨数据。我们需要计算出每一年连续下雨最长的天数以及从什么时候开始到什么时候结束。

长沙历史连续降雨分布图

# 年连续降雨最长时间段统计
df_stillRainyD = (df_PRCP > 0]).groupby('year').apply(continue_count)# 提交给自定义统计函数进行计算
df_stillRainyD = df_stillRainyD.set_index('year')

plt.xlabel("Month")
plt.ylabel("Year")
plt.title("Continuous Rainy Count : 1951-2019")
plt.barh(df_stillRainyD.index, df_stillRainyD['maxCount'], left=df_stillRainyD['maxDayIndex'],
         color=list(map(lambda v: color(tuple(hsv2rgb(int(6 * v) + 120, 1, 1))), df_stillRainyD['maxCount'])),
         align='edge') #绘制横向柱状图

# 设置主刻度
plt.xlim(0, 365)
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().yaxis.set_major_locator(MultipleLocator(5))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1950)))
# 设置次刻度
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.gca().yaxis.set_minor_locator(MultipleLocator(1))

# 打开网格
plt.gca().xaxis.grid(True, which='major')# x坐标轴的网格使用主刻度
plt.gca().yaxis.grid(True, which='minor')# y坐标轴的网格使用次刻度
if ISTEST == False:
    plt.savefig("Continuous Rainy Count.png")# 保存图片
plt.show()

注意到这里用的是plt.barh()方法,即横向柱状图绘制,同时添加了left=?标签,用于对柱状图块进行位移(位移用来表示从哪一天开始,不设置的话默认都是从x=0开始)。每一个柱状图块的长度表示了每一年的降雨最大天数,图块的位置表示了连续降雨的起始和结束时间。

补充:年连续高温最常时间段

# 年连续高温最长时间段
df_stillHotD = (df_TAVG > 30]).groupby('year').apply(continue_count)
df_stillHotD = df_stillHotD.set_index('year')

plt.xlabel("Month")
plt.ylabel("Year")
plt.title("Continuous Hot Count : 1951-2019")
plt.barh(df_stillHotD.index, df_stillHotD['maxCount'], left=df_stillHotD['maxDayIndex'],
         color=list(map(lambda v: color(tuple(hsv2rgb(int(-1.2 * v) + 60, 1, 1))), df_stillHotD['maxCount'])),
         align='edge')
# plt.barh(df_stillRainyD.index, df_stillRainyD['maxDayIndex'] , color='#FFFFFF')
plt.xlim(0, 365)
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().yaxis.set_major_locator(MultipleLocator(5))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1950)))
# 修改次刻度
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.gca().yaxis.set_minor_locator(MultipleLocator(1))

# 打开网格
plt.gca().xaxis.grid(True, which='major')# x坐标轴的网格使用主刻度
plt.gca().yaxis.grid(True, which='minor')# y坐标轴的网格使用次刻度
if ISTEST == False:
    plt.savefig("Continuous Hot Count.png")# 保存图片
plt.show()


年连续低温最长时间段

# 年连续低温最长时间段
df_stillColdD = (df_TAVG < 10]).groupby('year').apply(continue_count)
df_stillColdD = df_stillColdD.set_index('year')

plt.xlabel("Month")
plt.ylabel("Year")
plt.title("Continuous Cold Count : 1951-2019")
plt.barh(df_stillColdD.index, df_stillColdD['maxCount'], left=df_stillColdD['maxDayIndex'],
         color=list(map(lambda v: color(tuple(hsv2rgb(int(1 * v) + 180, 1, 1))), df_stillColdD['maxCount'])),
         align='edge')

# plt.xticks(range(1,13,1),range(1,13,1))
plt.xlim(0, 365)
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.gca().yaxis.set_major_locator(MultipleLocator(5))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: int(x + 1950)))
# 修改次刻度
plt.gca().xaxis.set_minor_locator(MultipleLocator(1))
plt.gca().yaxis.set_minor_locator(MultipleLocator(1))

# 打开网格
plt.gca().xaxis.grid(True, which='major')# x坐标轴的网格使用主刻度
plt.gca().yaxis.grid(True, which='minor')# y坐标轴的网格使用次刻度
if ISTEST == False:
    plt.savefig("Continuous Cold Count.png")# 保存图片
plt.show()


长沙历年湿冷天气频率统计图


df_HisRainy = df_PRCP > 0]
df_HisCold = pd.merge(df_TAVG < 10], df_TAVG > -100], how='inner',
                      on=['datetime', 'year', 'month', 'day', 'dayIndex', 'value', 'color'])
df_HisRainyCold = pd.merge(df_HisRainy, df_HisCold, left_on='datetime', right_index=True, how='inner')
se_HisRainyColdD = df_HisRainyCold.groupby('dayIndex_x')['value_x'].count()

plt.xlabel("Month")
plt.ylabel("Probability %")
plt.title("Historical Same Day Rainy and Cold Count : 1951-2019")
plt.bar(se_HisRainyColdD.index, se_HisRainyColdD / len(df_PRCP.groupby('year')) * 100,
      color=list(map(lambda v: color(tuple(hsv2rgb(int(2.4 * v) + 120, 1, 1))), se_HisRainyColdD.values)))
plt.gca().grid()# 打开网格
plt.gca().xaxis.set_major_locator(MultipleLocator(31))
plt.gca().xaxis.set_major_formatter(FuncFormatter(month_formatter))
plt.xlim(0, 365)
plt.ylim(0, 100)
plt.gca().yaxis.set_major_locator(plt.MultipleLocator(10))
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, y: str(y * 10 - 10) + '%'))
if ISTEST == False:
    plt.savefig("Historical Same Day Rainy and Cold Count.png")# 保存图片
plt.show()



编码写到这里,最核心的几个步骤就结束了,接下来就是最后的一个步骤——数据分析。

数据分析篇
基于程序运算,我们一共生成了八张图,一一进行分析。

图一:长沙历史平均气温分布图
plt.imshow(mpimg.imread("/home/kesci/work/TAVG.png"))
<matplotlib.image.AxesImage at 0x7f0d234dc898>

这是一张散点图,每一个点表示70年中某一天的平均气温,直接呈现了气温与年单位时间的对应关系,可以看到历史同比的平均气温分布跨度都比较大,不同年份同比最大甚至出现了20C°的差异。

但综合来看还是比较直观的,长沙从11月中旬开始进入低温模式( TAVG<10C°),到次年的2月初开始逐步回温,直到3月中旬彻底结束长达4个月的寒冷天气。

也不排除有少数非常暖的年份,在2月初就早早迎来了春天,但只是少数。

而温度扮演的并不是最主要的角色,湿度才是噩梦的主角,这在后面会重点说明。

而长沙的炎热天气对比之下就不是很长了,综合来看,从6月底气温逐步上升到30C°左右,经过7-8这两个月的盛夏之后,在9月初气温开始逐步回落。

如果有人问我什么时候来长沙玩比较合适,那么就气温来说,上图中出现绿色比较多的时间是比较宜居的。即3月中旬到5月中旬,9月中旬到11月中旬,合计是4个月的时间。

接下来就气温情况还有一张图作为补充:

图二:长沙历史气温分布图

plt.imshow(mpimg.imread("/home/kesci/work/Historical TAVG Show.png"))
<matplotlib.image.AxesImage at 0x7f0d23902358>

从图中可以看到夏季连续高温的天气并不长,只是在2013年7月出现了一次连续一个半月的高温天气。

而连续的低温天气相对就比较漫长了,甚至在2012年出现了一次长达两个半月的超长低温天气,这还没有算上2011年入冬之后的连续低温。

所以比起天热,冬天寒冷也不容小觑。

说完温度接下来就要说最可怕的降雨情况了。冬天其实并不可怕,可怕的是冬天没有太阳还下着雨。

图三:长沙历史降雨量分布图

plt.imshow(mpimg.imread("/home/kesci/work/PRCP.png"))
<matplotlib.image.AxesImage at 0x7f0d23700f60>

首先不要被这张图吓到,一片蓝色不代表一年365天都在下雨,而是表示这70年里,几月几号这一天有下过雨。

可以看到历史上365天都曾有过下雨记录,肯定是不存在不下雨的某一个幸运日的。雨量随着夏季的到来呈上升趋势,在6月到达顶峰,接下来炎热的7月和8月降雨量开始相对减少。而其他时间也是有概率降雨的,这一点亚热带季风气候的城市都是如此,并不会有太大的区别。

重点是后面的两张图:

图四:长沙历年降雨频率统计图

plt.imshow(mpimg.imread("/home/kesci/work/Historical Same Day Rainy Count.png"))
<matplotlib.image.AxesImage at 0x7f0d246225c0>

图五:长沙历年湿冷天气频率统计图

plt.imshow(mpimg.imread("/home/kesci/work/Historical Same Day Rainy and Cold Count.png"))
<matplotlib.image.AxesImage at 0x7f0d232ec400>

这两张图很直观的展示了,历史同比日单位的降雨频率…… 通俗点说就是统计了这70年以来,某月某日出现过降雨的次数,以此来计算出这一天会下雨的概率。

从图中可以看到长沙常年降雨频率都在30%以上,从1月份开始上升到了40%,2月中下旬开始彻底爆发,超过了50%、60%,一直到7月盛夏才有所下降。

其实下雨就下吧,这也不是重点,重点是图5——出现降水同时气温又低于10C°的频率统计。可以看到,1、2两月这样的天气出现的频率均值达到了45%以上,所以这也就是最近这两个月这么难熬的原因了:

空气湿度长期在80%以上,出门到外面,空气中无限接近0度又不结冰的水分子加速了体温的热传导,再厚实的棉袄也挨不住水分子的渗透,风再一吹加速一下热对流,那种绝望的感受只有长江以南一带的小伙伴才会懂。

而历史上连续下雨的天数极值可以参考下图:

图六:长沙历史连续降雨分布图

plt.imshow(mpimg.imread("/home/kesci/work/Continuous Rainy Count.png"))
<matplotlib.image.AxesImage at 0x7f0d232d2c50>

可以看到并不是每年都有超长的时间一直连续下雨,大部分都会在10天以内结束,但是有可能出一天太阳接着下十天雨这样的情况,为了调查到底,于是看下图:

图七:长沙历史降水展示图

plt.imshow(mpimg.imread("/home/kesci/work/Historical Rainy Show.png"))
<matplotlib.image.AxesImage at 0x7f0d2384d438>

图中每一个蓝色的点都表示历史上当天有降雨记录,空白区域则表示当天没有降雨记录。综合来看每年接近一半的时间都在下雨,冬末至夏初的降雨尤为频繁。

最后一张图,统计了长沙历史的降雨及高温 (大于30 C°)和低温(小于10 C°)的各年天数:

** 图八:长沙历史高低温及降雨天数统计图**

plt.imshow(mpimg.imread("/home/kesci/work/Historical Weather Count.png"))
<matplotlib.image.AxesImage at 0x7f0d204820b8>

可以看到,橙色、蓝色、绿色线条分别表示高温、低温和降雨天数。一年有接近一半天数在下雨,接近三分之一的天气低温寒冷,这些数据已经非常充分的说明了长沙是一个湿冷多过炎热的城市。

总而言之以上的8张图,从各个时间维度和量化标准上对长沙历年的气象情况做了一个大致的分析。70年的数据,几乎覆盖了许多人穷极一生所能经历的种种气象。

虽然反复无常,最近又一直是阴雨绵绵,但也还是起起落落会有一定的规律可循。

最后,再奉上统计出来的长沙历史的气象极值:

历史最高气温:1953年8月13日,40.6 C°
历史最低气温:1972年2月9日,-11.3 C°
历史单日最大降水量:1997年6月7日,249.5mm
历史连续降雨天数记录:2018年12月25日至2019年1月21日,连续降雨28天
数据及代码获取
好奇心Log公众号后台回复长沙城市报告获取

文章来源于微信公众号:好奇心Log
页: [1]
查看完整版本: Python可视化 | 长沙城市气象报告可视化展示