可视化温度变化;气候螺旋。
#初学者 #python #visualization #climate

介绍

欢迎,让我们先跳入定义。

  • Temperature - 是一种表达对炎热和寒冷感知的物理量。换句话说,对炎热和寒冷的度量是用尺度表示的。

  • Variation-是某种程度与另一个不同的程度

so ....

  • 温度变化是特定时间范围内特定区域中温度差异的度量。

Image showing variation in temperature across the world

目标

那么该项目的目标是什么?该项目的目的是创建肯尼亚从1991年至2016年温度变化的动画螺旋。

为什么?

  1. 描述性分析 - 它将描述当前情况。

  2. 明智的决策 - 洞察力将有助于在气候决策中做出明智的决定。

  3. 灾难准备 - 可视化可以帮助显示早期的温度尖峰的迹象,可以帮助他们更好地准备。

背景

气候科学家

Ed Hawkins在2017年推出了动画可视化,吸引了世界。这种可视化显示了从1850年到2017年全球平均温度的偏差。在Twitter和Facebook上共享了数百万次,甚至在里约奥运会的开幕式上显示了它的版本。

此动画是在Srini撰写的https://www.dataquest.io/blog/climate-temperature-spirals-python/的帮助下创建的。

从非洲检索到历史天气数据https://africaopendata.org/dataset/kenya-climate-data-1991-2016

the World Bank为气候知识门户收集了数据。

构建螺旋可视化。

1. ETL(提取,转换和加载数据)

#importing libraries we'll use 
%matplotlib inline
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
import matplotlib.animation as animation


#reading the temperature file into a pandas dataframe
temp_data = pd.read_csv(
    "temp data.csv",
    delim_whitespace=True,
    usecols=[0, 1],
    header=None)

让我们快速查看数据框架和数据的某些属性。

temp_data

结果:


0   1
0   Year,Month  Average,Temperature
1   1991,Jan    Average,25.1631
2   1991,Feb    Average,26.0839
3   1991,Mar    Average,26.2236
4   1991,Apr    Average,25.5812
... ... ...
308 2016,Aug    Average,24.0942
309 2016,Sep    Average,24.437
310 2016,Oct    Average,26.0317
311 2016,Nov    Average,25.5692
312 2016,Dec    Average,25.7401
temp_data.describe()

结果:


0   1
count   313 313
unique  313 313
top Year,Month  Average,Temperature
freq    1   1

从您获得的结果中,检查是否需要使其更可读。

在这种特殊情况下,您需要将年,月份和平均温度分开。

temp_data[['Year', 'Month']] = temp_data['Year'].str.split(',', expand=True)

temp_data[['Average', 'Temparature']] = temp_data['Average'].str.split(',', expand=True)
temp_data.head()


结果:


0   1   Year    Month   Average Temperature Temparature
0   Year,Month  Average,Temperature Year    Month   Average Average,Temperature Temperature
1   1991,Jan    Average,25.1631 1991    Jan Average Average,25.1631 25.1631
2   1991,Feb    Average,26.0839 1991    Feb Average Average,26.0839 26.0839
3   1991,Mar    Average,26.2236 1991    Mar Average Average,26.2236 26.2236
4   1991,Apr    Average,25.5812 1991    Apr Average Average,25.5812 25.5812

丢弃重复的列是最好的做法。

temp_data_1 = temp_data.drop(temp_data.columns[[0, 1, 4, 5]], axis=1)
temp_data_1

结果:

Year    Month   Temparature
0   Year    Month   Temperature
1   1991    Jan 25.1631
2   1991    Feb 26.0839
3   1991    Mar 26.2236
4   1991    Apr 25.5812
... ... ... ...
308 2016    Aug 24.0942
309 2016    Sep 24.437
310 2016    Oct 26.0317
311 2016    Nov 25.5692
312 2016    Dec 25.7401

现在让我们了解数据中的data types

#getting to know what data types my data frame has
temp_data_2.dtypes

结果:

Year           object
Month          object
Temparature    object
dtype: object

所有数据均以对象形式形式
您需要将温度列数据类型从对象转换为浮点。这是因为这是您可以在其上执行数学操作并在规模上可视化的唯一方法。

temp_data_2['Temparature'] = temp_data_2['Temparature'].astype(str).astype(float)

#view data types of each column
temp_data_2.dtypes

结果

Year            object
Month           object
Temparature    float64
dtype: object

现在,您将编写一个将月份名称转换为数字的函数。在这里,您使用datetime python library.

# Define a function to convert month names to numbers
def month_string_to_number(string):
    dt = datetime.strptime(string, "%b")
    return dt.month
## Apply the function to the month column to convert to numbers
temp_data_2['month_number'] = temp_data_2['Month'].apply(month_string_to_number)

temp_data_2.head(20)

结果:

    Year    Month   Temparature month_number
1   1991.0  Jan 25.1631 1
2   1991.0  Feb 26.0839 2
3   1991.0  Mar 26.2236 3
4   1991.0  Apr 25.5812 4
5   1991.0  May 24.6618 5
6   1991.0  Jun 23.9439 6
7   1991.0  Jul 22.9982 7
8   1991.0  Aug 23.0391 8
9   1991.0  Sep 23.9423 9
10  1991.0  Oct 25.5236 10
11  1991.0  Nov 24.5875 11
12  1991.0  Dec 24.7398 12
13  1992.0  Jan 24.4359 1
14  1992.0  Feb 26.2892 2
15  1992.0  Mar 26.5409 3
16  1992.0  Apr 26.0819 4
17  1992.0  May 24.7852 5
18  1992.0  Jun 24.0563 6
19  1992.0  Jul 22.8377 7
20  1992.0  Aug 22.7902 8

删除不必要的月份名称列是最好的做法。

temp_data_2 = temp_data_2.drop('Month', axis=1)

在ETL过程中检查零值或缺失值非常重要。

temp_data_2.isnull().sum()

结果:

Year            0
Temparature     0
month_number    0
dtype: int64

此数据中没有缺少值。

现在您找到了温度列的平均值,并从列中的每个单个值中减去平均值。这将帮助您在年平均温度下找到每个月的温度变化。这是一种normalization of data

2.可视化数据。

笛卡尔与极性坐标系
有一些关键阶段可以重新创建Ed的GIF:

- 学习如何在极坐标系上绘制
- 转移极性可视化数据
- 使情节的美学态度
- 逐年进行可视化,并将情节变成gif

- 准备极地绘图的数据

您需要按年来征收数据并使用以下坐标:

r:给定月份的温度值,调整为没有负值。
Matplotlib支持绘制负值,但不以您的思维方式进行绘制。您希望-0.1比0.1更靠近中心,这不是默认的matplotlib行为。
您还想在情节的起源周围留出一些空间,以显示本年份的文字。
theta:生成12个跨越0到2*pi。

的同等间隔的角度值

您将从如何仅绘制Matplotlib的1991年数据开始,然后扩展到所有年。

要生成使用极性系统的matplotlib轴对象,您需要在创建它时将投影参数设置为“ polar”。

fig = plt.figure(figsize=(8,8))
ax1 = plt.subplot(111, projection='polar')

a matplotlib Axes object that uses the polar system,

要调整数据以包含负温度值,您需要首先计算最低温度值:

temp_data_2['Temparature'].min()

结果:

-2.3378881410256405

您会添加

所有温度值的

2,因此它们将是正的,但是在原点周围仍然有一些空间显示文本:

注意;根据数据的最低温度调整价值。

您还会生成12个均匀间隔的值,从0到2*pi,并将第一个12作为theta值:

# returns a boolean Series that selects only the rows 
#where the Year column is equal to 1991.
hc_1991 = temp_data_2[temp_data_2['Year'] == 1991]
#the code creates a new figure with 
#the plt.figure() function and sets the size of the figure to be 8 inches by 8 inches with figsize=(8,8).
fig = plt.figure(figsize=(8,8))
ax1 = plt.subplot(111, projection='polar')
r = hc_1991['Temparature'] + 2
theta = np.linspace(0, 2*np.pi, 12)
# Plot the data on the polar axes
ax1.plot(theta, r)

# hide all of the tick labels for both axes 
ax1.axes.get_yaxis().set_ticklabels([])
ax1.axes.get_xaxis().set_ticklabels([])
#Background color within the polar plot to be black, and the color surrounding the polar plot to be gray.
#I can use
#fig.set_facecolor() to set the foreground color and Axes.set_axis_bgcolor() to set the background color of the plot:
fig.set_facecolor("#323331")
ax1.set_facecolor('#000100')
#add the title and labels
ax1.set_ylabel('Temperature')
ax1.set_title("Kenya's Temperature Change (1991-2016)", color='white', fontdict={'fontsize': 30})
# Display the plot
plt.show()

绘制其余几年
为了在剩下的几年中绘制螺旋形,您需要重复自己刚刚做的事情,但是在数据集中的所有年份中。您应该在这里进行的调整是手动设置

的轴极限

r(或matplotlib中的y)。这是因为Matplotlib根据所使用的数据自动缩放图的大小。这就是为什么在最后一步中,我观察到仅1991年的数据显示在绘图区域的边缘。您将计算整个数据集中的最高温度值,并添加大量的填充(以匹配Ed所做的事情)。

现在,您可以使用for循环来生成其余数据。您将删除现在生成中心文本的代码(否则每年都会在同一时刻生成文本,并且会非常混乱):

调用axes.plot()方法时,您将使用颜色(或c)参数,并从plt.cm.(index)绘制颜色。

ig = plt.figure(figsize=(14,14))
ax1 = plt.subplot(111, projection='polar')

# hide all of the tick labels for both axes 
ax1.axes.get_yaxis().set_ticklabels([])
ax1.axes.get_xaxis().set_ticklabels([])

#fig.set_facecolor() to set the foreground color and Axes.set_axis_bgcolor() to set the background color of the plot:
fig.set_facecolor("#323331")
#ax1.set_ylim(0, 3.25)


theta = np.linspace(0, 2*np.pi, 12)


ax1.set_title("Kenya's Temperature Change (1991-2016)", color='white', fontdict={'fontsize': 30})
ax1.set_facecolor('#000100')

years = temp_data_2['Year'].unique()

for index,Year in enumerate(years):
  r=temp_data_2.loc[temp_data_2["Year"]== Year,"Temparature"]+2
  ax1.plot(theta,r,c=plt.cm.viridis(index*2))
plt.show()

添加温度环
在此阶段,观看者实际上根本无法理解基础数据。在可视化中没有符号的温波值。
接下来,您将在0.0、1.5、2.0摄氏度上添加温度环:
然后,最终生成gif动画
现在,您准备从图中生成GIF动画。动画是一系列以快速连续显示的图像。您将使用

matplotlib.animation.funcanimation函数可帮助您解决这个问题。要利用此功能,您需要编写代码:

定义基本图的外观和属性
使用新数据更新每个帧之间的图
调用

时,您将使用以下所需的参数

funcanimation():

图:matplotlib图对象
func:在每个帧之间调用的更新功能
帧:帧数(每年您想要一个)
间隔:显示每个帧的毫秒数(一秒钟内有1000毫秒)
此功能将返回

matplotlib.animation.funcanimation对象,它具有一个可以用来将动画写入GIF文件的Save()方法。

下面的代码块显示了上述所有这些添加以产生GIF的步骤。

from mpl_toolkits.mplot3d import Axes3D 
months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
fig=plt.figure(figsize=(15,15))
ax1=plt.subplot(111,projection="polar")

ax1.plot(full_circle_thetas, blue_one_radii, c='blue')
ax1.plot(full_circle_thetas, red_one_radii, c='red')
ax1.plot(full_circle_thetas, red_two_radii, c='red')
ax1.plot(full_circle_thetas, red_three_radii, c='red')
ax1.plot(full_circle_thetas, red_four_radii, c='red')

#fig.set_facecolor() to set the foreground color and Axes.set_axis_bgcolor() to set the background color of the plot:
fig.set_facecolor("#323331")
#ax1.set_ylim(0, 3.25)

ax1.text(np.pi/2, 1.0, "0.0 C", color="blue", ha='center', fontdict={'fontsize': 20})
ax1.text(np.pi/2, 2.0, "0.5 C", color="red", ha='center', fontdict={'fontsize': 20})
ax1.text(np.pi/2, 2.5, "1.0 C", color="red", ha='center', fontdict={'fontsize': 20})
ax1.text(np.pi/2, 3.0, "1.5 C", color="red", ha='center', fontdict={'fontsize': 20})
ax1.text(np.pi/2, 3.5, "2.0 C", color="red", ha='center', fontdict={'fontsize': 20})


ax1.set_xticks([])
ax1.set_yticks([])
ax1.set_xticklabels([])
ax1.set_yticklabels([])


theta = np.linspace(0, 2*np.pi, 12)


ax1.set_title("Kenya's Temperature Change Spiral (1991-2016)", color='white', fontdict={'fontsize': 30})
ax1.set_facecolor('#000100')

years = temp_data_2['Year'].unique()

fig.text(0.78,0,"Kenya Temperature data",color="white",fontsize=20)
fig.text(0.05,0.02,"Everlynn Muthoni; Data Stories",color="white",fontsize=20)
fig.text(0.05,0,"Inspired by Ed Hawkins's 2017 Visualization",color="white",fontsize=15)

#add months ring
months_angles= np.linspace((np.pi/2)+(2*np.pi),np.pi/2,13)
for i,month in enumerate(months):
  ax1.text(months_angles[i],5.0,month,color="white",fontsize=15,ha="center")

#for index,Year in enumerate(years):
  #r=temp_data_2.loc[temp_data_2["Year"]== Year,"Temparature"]+2
  #ax1.plot(theta,r,c=plt.cm.viridis(index*15))

def update(i):
    # Remove the last year text at the center
    for txt in ax1.texts:
      if(txt.get_position()==(0,0)):
        txt.set_visible(False)
    # Specify how we want the plot to change in each frame.
    # We need to unravel the for loop we had earlier.
    Year = years[i]
    r = temp_data_2[temp_data_2['Year'] == Year]['Temparature'] + 2
    ax1.plot(theta, r, c=plt.cm.viridis(i*30))
    ax1.text(0,0,Year,fontsize=20,color="white",ha="center")
    return ax1

anim = animation.FuncAnimation(fig, update, frames=len(years), interval=10)


ffmpeg_writer = animation.FFMpegWriter();

anim.save("Spiral.gif", writer = 'pillow', fps = 5, dpi=100);

最终结果:

final gif visualization of Kenya's temperature data

3.我们的数据可视化讲述的故事。

so ....从分析和可视化中,推导以下见解;

  • 自1990年以来,2月至6月之间的温度变化逐渐升高,大多数发生在6月至7月之间

- 温度变化主要发生在一年的大部分时间里。

就是这样。恭喜,您已经使用气候螺旋来成功可视化温度数据!

如果您想查看源代码,请单击here

4.建议

  • 对于更好的3D可视化,请使用Matlab

  • 探索该项目
  • 为了更好地实时描述性分析,请尝试查找最新日期的数据。

喜欢,订阅并与我分享您的想法。再见!和快乐的编码。