您好,欢迎来到此教程。
今天,我将教您使用Geo-Data和社交连接索引创建上面看到的地图。
如果您想进一步了解可视化和数据集,则可以在我的新免费新闻通讯中查看此article。
让我们从教程开始。
步骤1:下载数据
在开始之前,我们需要下载一个足够令人兴奋的数据集,以供本教程和地理数据绘制美国的准确地图。
对于地图,我使用Cencus.gov的形状文件。您可以使用以下链接下载states和counties。
要拥有一个补充数据集,我选择了Facebook连接指数,该指数衡量了在Facebook上连接不同县的两个人的可能性。
您可以使用this link下载连接数据。
下载完成后,将它们解压缩并将其放置在一个好的位置。我在教程中使用./data
,但是您可以做任何喜欢的事情。
它应该看起来像这样。
让我们写一些代码。
步骤2:进口图书馆并准备海洋
唯一的新库(如果您完成了我的其他任何Matplotlib教程)是Geopandas,我们将使用它来绘制地图。
# Import libraries
import numpy as np
import pandas as pd
import seaborn as sns
import geopandas as gpd
import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.patches import Patch, Circle
接下来,让我们使用seaborn
定义一些有关样式的功能。
edge_color = "#30011E"
background_color = "#fafafa"
sns.set_style({
"font.family": "serif",
"figure.facecolor": background_color,
"axes.facecolor": background_color,
})
现在是时候学习如何绘制地图了。
步骤3:加载并准备地理数据
我使用geopandas
加载数据并删除关岛,波多黎各和美国萨摩亚等非法人领土。
# Load and prepare geo-data
counties = gpd.read_file("./data/cb_2018_us_county_500k/")
counties = counties[~counties.STATEFP.isin(["72", "69", "60", "66", "78"])]
counties = counties.set_index("GEOID")
states = gpd.read_file("./data/cb_2018_us_state_500k/")
states = states[~states.STATEFP.isin(["72", "69", "60", "66", "78"])]
geopandas
数据框具有一个geometry
列,该列定义了每行的形状。它使我们可以通过这样的调用counties.plot()
或states.plot()
绘制地图。
ax = counties.plot(edgecolor=edge_color + "55", color="None", figsize=(20, 20))
states.plot(ax=ax, edgecolor=edge_color, color="None", linewidth=1)
plt.axis("off")
plt.show()
在这里,我首先用透明的边界绘制县,然后在调用states.plot()
时重复使用ax
,以免绘制单独的地图。
这就是我得到的。
结果看起来不好,但是我会进行一些快速调整以使我们走上正确的轨道。
第一个调整是将地图投影更改为以美国为中心的一个。您可以通过致电to_crs()
使用geopandas
来做到这一点。
# Load and prepare geo-data
...
counties = counties.to_crs("ESRI:102003")
states = states.to_crs("ESRI:102003")
这是区别。
在绘制美国的数据地图时,通常在大陆下方画阿拉斯加和夏威夷,这也是我们将要做的。
使用geopandas
,您可以通过内置功能翻译,扩展和旋转几何形状。这是这样做的有用功能。
def translate_geometries(df, x, y, scale, rotate):
df.loc[:, "geometry"] = df.geometry.translate(yoff=y, xoff=x)
center = df.dissolve().centroid.iloc[0]
df.loc[:, "geometry"] = df.geometry.scale(xfact=scale, yfact=scale, origin=center)
df.loc[:, "geometry"] = df.geometry.rotate(rotate, origin=center)
return df
i计算了定义旋转和缩放的整个数据框架的中心点。如果我不这样做,geopandas
会自动为每一行做到这一点,这使得地图看起来完全混乱了。
下一个功能将我们当前的数据帧,将夏威夷和阿拉斯加分开,致电translate_geometries()
调整其几何形状,并将它们放回新的数据帧中。
def adjust_maps(df):
df_main_land = df[~df.STATEFP.isin(["02", "15"])]
df_alaska = df[df.STATEFP == "02"]
df_hawaii = df[df.STATEFP == "15"]
df_alaska = translate_geometries(df_alaska, 1300000, -4900000, 0.5, 32)
df_hawaii = translate_geometries(df_hawaii, 5400000, -1500000, 1, 24)
return pd.concat([df_main_land, df_alaska, df_hawaii])
我们将adjust_maps()
添加到我们的代码中。
# Load and prepare geo-data
...
counties = adjust_maps(counties)
states = adjust_maps(states)
现在我们的地图看起来像这样。
下一步的时间。
步骤4:添加数据
要添加数据,我们首先加载Facebook连接数据。我将user_loc
和fr_loc
列变成字符串,并添加领先的零以使其与地理数据一致。
# Load facebook data
facebook_df = pd.read_csv("./data/county_county.tsv", sep="\t")
facebook_df.user_loc = ("0" + facebook_df.user_loc.astype(str)).str[-5:]
facebook_df.fr_loc = ("0" + facebook_df.fr_loc.astype(str)).str[-5:]
user_loc
和fr_loc
列定义了一个县对,第三列scaled_sci
是我们要显示的值。
数据集中有3227个县,这意味着总共有10,413,529对,但我们将一次显示一个县的连接指数。
# Create data map
county_id = "06075" # San Fransisco
county_name = counties.loc[county_id].NAME
county_facebook_df = facebook_df[facebook_df.user_loc == county_id]
接下来,我定义了一个selected_color
和data_breaks
,其中包含以后的百分比,颜色和传奇文本。
# Create data map
...
selected_color = "#FA26A0"
data_breaks = [
(90, "#00ffff", "Top 10%"),
(70, "#00b5ff", "90-70%"),
(50, "#6784ff", "70-50%"),
(30, "#aeb3fe", "50-30%"),
(0, "#e6e5fc", "Bottom 30%"),
]
以下功能使用county_df
和我们刚刚定义的data_breaks
定义了每一行的颜色。
def create_color(county_df, data_breaks):
colors = []
for i, row in county_df.iterrows():
for p, c, _ in data_breaks:
if row.value >= np.percentile(county_df.value, p):
colors.append(c)
break
return colors
我们计算正确的值并像这样添加create_color()
。
# Create data map
...
counties.loc[:, "value"] = (county_facebook_df.set_index("fr_loc").scaled_sci)
counties.loc[:, "value"] = counties["value"].fillna(0)
counties.loc[:, "color"] = create_color(counties, data_breaks)
counties.loc[county_id, "color"] = selected_color
ax = counties.plot(edgecolor=edge_color + "55", color=counties.color, figsize=(20, 20))
states.plot(ax=ax, edgecolor=edge_color, color="None", linewidth=1)
ax.set(xlim=(-2600000, None)) # Removing some of the padding to the left
plt.axis("off")
plt.show()
这是我们得到的。
看起来很棒,但是我们需要添加一些信息。
步骤5:添加信息
我们需要的第一条信息是解释数据可视化的标题。
这是一个可以做到的函数。
def add_title(county_id, county_name):
plt.annotate(
text="Social Connectedness Ranking Between US Counties and",
xy=(0.5, 1.1), xycoords="axes fraction", fontsize=16, ha="center"
)
plt.annotate(
text="{} (FIPS Code {})".format(county_name, county_id),
xy=(0.5, 1.03), xycoords="axes fraction", fontsize=32, ha="center",
fontweight="bold"
)
接下来,我们需要一个传奇和支持信息,以解释数据,因为它有点复杂。
添加传奇的功能使用data_breaks
和selected_color
创建我们使用plt.legend()
添加的Patch(es)
。
def add_legend(data_breaks, selected_color, county_name):
patches = [Patch(facecolor=c, edgecolor=edge_color, label=t) for _, c, t in data_breaks]
patches = [Patch(facecolor=selected_color, edgecolor=edge_color, label=county_name)] + patches
leg = plt.legend(
handles=patches,
bbox_to_anchor=(0.5, -0.03), loc='center',
ncol=10, fontsize=20, columnspacing=1,
handlelength=1, handleheight=1,
edgecolor=background_color,
handletextpad=0.4
)
我也有一个简单的功能,可以在传奇下方添加一些其他信息。
def add_information():
plt.annotate(
"The Facebook Connectivity Index measure the likelyhood that users in different\nlocations are connected on Facebook. The formula divides the number of Facebook\nconnections with the number of possible connections for the two locations.",
xy=(0.5, -0.08), xycoords="axes fraction", ha="center", va="top", fontsize=18, linespacing=1.8
)
plt.annotate(
"Source: https://dataforgood.facebook.com/",
xy=(0.5, -0.22), xycoords="axes fraction", fontsize=16, ha="center",
fontweight="bold"
)
最后,我有add_circle()
功能,可以指示我们通过围绕它绘制一个圆圈来研究的哪个县。
def add_circle(ax, counties_df, county_id):
center = counties_df[counties_df.index == county_id].geometry.centroid.iloc[0]
ax.add_artist(
Circle(
radius=100000, xy=(center.x, center.y), facecolor="None", edgecolor=selected_color, linewidth=4
)
)
我们在# Create data map
评论下将它们添加到其余代码的其余部分。
# Create data map
...
add_circle(ax, counties, county_id)
add_title(county_id, county_name)
add_legend(data_breaks, selected_color, county_name)
add_information()
plt.axis("off")
plt.show()
这是完成的数据可视化。
恭喜,您现在知道如何在Matplotlib中创建美国的出色数据地图! :)
结论
当您想以捕捉用户眼睛的方式可视化地理信息时,数据图很棒。
这次,我们使用了Facebook的社交联系索引,但是您可以通过地理信息将其更改为其他任何内容。
我希望您喜欢这个教程并学到了新知识。
如果您这样做,请确保加入我的新闻Data Wonder。
下次见。