中国大陆哪个省的人最长寿?Python动态图帮你盘点!

开场段子 ????

俗话说,人到中年不得已,保温杯里泡枸杞。健康长寿是大家非常关注的人生重要目标。

《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)

收工。????

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值