中国大陆哪个省的人最长寿?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:2for 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.50.95, title, va="center", ha="center"
                    size = 12,transform = ax_base.transAxes)
        ax_base.text(0.130.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)


收工。😋


万水千山总是情,点个在看行不行?



浏览 33
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报