中国大陆哪个省的人最长寿?Python动态图帮你盘点!
Python之王
共 19477字,需浏览 39分钟
·
2021-09-24 15:05
开场段子 😋
俗话说,人到中年不得已,保温杯里泡枸杞。健康长寿是大家非常关注的人生重要目标。
《2016 年世界卫生统计》显示:中国人的预期寿命为 76.1 岁。处于世界中等水平。世界上预期寿命最长的国家是日本,高达83.7岁。
那么,中国国内哪个省份的人口预期寿命最高呢?我们用Python动态图来盘点一下。
先上图片
再上视频
最后上代码
import numpy as np
import pandas as pd
import geopandas as gpd
import shapely
from shapely import geometry as geo
from shapely import wkt
import geopandas as gpd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import imageio
import os
from PIL import Image
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['animation.writer'] = 'html'
plt.rcParams['animation.embed_limit'] = 100
def html_to_gif(html_file, gif_file, duration=0.1):
path = html_file.replace(".html","_frames")
images = [os.path.join(path,x) for x in sorted(os.listdir(path))]
frames = [imageio.imread(x) for x in images]
imageio.mimsave(gif_file, frames, 'gif', duration=duration)
return gif_file
cmap = [
'#2E91E5',
'#1CA71C',
'#DA16FF',
'#B68100',
'#EB663B',
'#00A08B',
'#FC0080',
'#6C7C32',
'#862A16',
'#620042',
'#DA60CA',
'#0D2A63']*100
def getCoords(geom):
if isinstance(geom,geo.MultiPolygon):
return [np.array(g.exterior) for g in geom.geoms]
elif isinstance(geom,geo.Polygon):
return [np.array(geom.exterior)]
elif isinstance(geom,geo.LineString):
return [np.array(geom)]
elif isinstance(geom,geo.MultiLineString):
return [np.array(x) for x in list(geom.geoms)]
else:
raise Exception("geom must be one of [polygon,MultiPolygon,LineString,MultiLineString]!")
#底图数据
dfprovince = gpd.read_file("./data/dfprovince.geojson").set_crs("epsg:4326").to_crs("epsg:2343")
dfnanhai = gpd.read_file("./data/dfnanhai.geojson").set_crs("epsg:4326").to_crs("epsg:2343")
dfline9 = dfnanhai[(dfnanhai["LENGTH"]>1.0)&(dfnanhai["LENGTH"]<2.0)]
#多边形数据
dfpolygons = pd.read_csv("./data/macro_data_china.csv")[["省份","预期寿命"]]
dfgeoms = dfprovince[["name","geometry"]].rename({"name":"省份"},axis = 1)
df = dfpolygons.merge(dfgeoms)
df["省份"] = [x if "自治区" not in x else x[0:2] for x in df["省份"]]
df = df.sort_values("预期寿命").set_index("省份")
def polygon_map_dance(df,title = "中国大陆各省市人口预期寿命",
filename = None,
figsize = (8,6),dpi = 144,
duration = 0.5,
anotate_points = ["北京市","上海市","江西省","湖北省","青海省","黑龙江省","广东省"]):
fig, ax_base =plt.subplots(figsize=figsize,dpi=dpi)
ax_child=fig.add_axes([0.800,0.125,0.10,0.20])
def plot_frame(i):
ax_base.clear()
ax_child.clear()
#============================================================
#绘制底图
#============================================================
#绘制省边界
polygons = [getCoords(x) for x in dfprovince["geometry"]]
for j,coords in enumerate(polygons):
for x in coords:
poly = plt.Polygon(x, fill=True, ec = "gray", fc = "white",alpha=0.5,linewidth=.8)
poly_child = plt.Polygon(x, fill=True, ec = "gray", fc = "white",alpha=0.5,linewidth=.8)
ax_base.add_patch(poly)
ax_child.add_patch(poly_child )
#绘制九段线
coords = [getCoords(x) for x in dfline9["geometry"]]
lines = [y for x in coords for y in x ]
for ln in lines:
x, y = np.transpose(ln)
line = plt.Line2D(x,y,color="gray",linestyle="-.",linewidth=1.5)
line_child = plt.Line2D(x,y,color="gray",linestyle="-.",linewidth=1.5)
ax_base.add_artist(line)
ax_child.add_artist(line_child)
#设置spine格式
for spine in['top','left',"bottom","right"]:
ax_base.spines[spine].set_color("none")
ax_child.spines[spine].set_alpha(0.5)
ax_base.axis("off")
#设置绘图范围
bounds = dfprovince.total_bounds
ax_base.set_xlim(bounds[0]-(bounds[2]-bounds[0])/10, bounds[2]+(bounds[2]-bounds[0])/10)
ax_base.set_ylim(bounds[1]+(bounds[3]-bounds[1])/3.5, bounds[3]+(bounds[3]-bounds[1])/100)
ax_child.set_xlim(bounds[2]-(bounds[2]-bounds[0])/2.5, bounds[2]-(bounds[2]-bounds[0])/20)
ax_child.set_ylim(bounds[1]-(bounds[3]-bounds[1])/20, bounds[1]+(bounds[3]-bounds[1])/2)
#移除坐标轴刻度
ax_child.set_xticks([]);
ax_child.set_yticks([]);
#============================================================
#绘制散点
#============================================================
k = i//3+1
m = i%3
text = "NO."+str(len(df)+1-k)
dfdata = df.iloc[:k,:].copy()
dftmp = df.iloc[:k-1,:].copy()
# 绘制散点图像
if len(dftmp)>0:
polygons = [getCoords(x) for x in dftmp["geometry"]]
for j,coords in enumerate(polygons):
for x in coords:
poly = plt.Polygon(x, fill=True, ec = "gray", fc = cmap[j],alpha=0.5,linewidth=.8)
poly_child = plt.Polygon(x, fill=True, ec = "gray", fc = cmap[j],alpha=0.5,linewidth=.8)
ax_base.add_patch(poly)
ax_child.add_patch(poly_child)
# 添加注释文字
for j,p in enumerate(dftmp.index):
poly = dftmp.iloc[j]["geometry"]
pt = poly.representative_point()
if p in anotate_points:
ax_base.annotate(p,xy = (pt.x,pt.y), xycoords = "data", xytext = (-15,10),
fontsize = 10,fontweight = "bold", color = cmap[j], textcoords = "offset points")
# 添加标题和排名序号
ax_base.text(0.5, 0.95, title, va="center", ha="center",
size = 12,transform = ax_base.transAxes)
ax_base.text(0.13, 0.9, text, va="center", ha="center",
alpha=0.5, size = 30,transform = ax_base.transAxes)
# 添加注意力动画
if m==0:
poly = dfdata.iloc[-1]["geometry"]
pt = poly.representative_point()
px,py,pz = pt.x,pt.y,dfdata.iloc[-1]["预期寿命"]
p = dfdata.index[-1]+":"+str(pz)
fact = 1.5
geom = shapely.affinity.scale(poly, xfact= fact, yfact= fact)
coords = getCoords(geom)
for x in coords:
poly = plt.Polygon(x, fill=True, ec = "gray",
fc = cmap[k-1],alpha=0.5,linewidth=.8,zorder = 4)
ax_base.add_patch(poly)
ax_base.annotate(p,xy = (px,py), xycoords = "data",
xytext = (-15,10),fontsize = 20,fontweight = "bold",
color = "black", textcoords = "offset points",zorder = 5)
if m==1:
poly = dfdata.iloc[-1]["geometry"]
pt = poly.representative_point()
px,py,pz = pt.x,pt.y,dfdata.iloc[-1]["预期寿命"]
p = dfdata.index[-1]+":"+str(pz)
fact = 1.25
geom = shapely.affinity.scale(poly, xfact= fact, yfact= fact)
coords = getCoords(geom)
for x in coords:
poly = plt.Polygon(x, fill=True, ec = "gray",
fc = cmap[k-1],alpha=0.5,linewidth=.8,zorder = 4)
ax_base.add_patch(poly)
ax_base.annotate(p,xy = (px,py), xycoords = "data",
xytext = (-15,10),fontsize = 15,fontweight = "bold",
color = "black", textcoords = "offset points",zorder = 5)
if m==2:
poly = dfdata.iloc[-1]["geometry"]
pt = poly.representative_point()
px,py,pz = pt.x,pt.y,dfdata.iloc[-1]["预期寿命"]
p = dfdata.index[-1]+":"+str(pz)
fact = 1.0
geom = shapely.affinity.scale(poly, xfact= fact, yfact= fact)
coords = getCoords(geom)
for x in coords:
poly = plt.Polygon(x, fill=True, ec = "gray",
fc = cmap[k-1],alpha=0.5,linewidth=.8,zorder = 4)
ax_base.add_patch(poly)
ax_base.annotate(p,xy = (px,py), xycoords = "data",
xytext = (-15,10),fontsize = 10,fontweight = "bold",
color = "black", textcoords = "offset points",zorder = 5)
my_animation = animation.FuncAnimation(fig,plot_frame,frames = range(0,3*len(df)),interval = int(duration*1000))
if filename is None:
try:
from IPython.display import HTML
HTML(my_animation.to_jshtml())
return HTML(my_animation.to_jshtml())
except ImportError:
pass
else:
my_animation.save(filename)
return filename
html_file = "中国大陆各省市人口预期寿命.html"
polygon_map_dance(df,filename = html_file)
gif_file = html_file.replace(".html",".gif")
html_to_gif(html_file,gif_file,duration=0.8)
收工。😋
万水千山总是情,点个在看行不行?
评论