【Python高级绘图+世界地图】原创Geo工具包绘制“数据+世界地图”精美热力图(含JSON数据+中/英文自动匹配)

目录

一、项目简介

二、如何使用?

1)克隆项目 

2)项目基本结构和功能

2-1)文件结构

2-2)函数介绍

        1. 数据清洗 (normalize_chinese)

        2. 匹配逻辑 (get_gray_list_chinese)

        3. 批量匹配 (match_data)

        4. 地理分布可视化 (plot_geo)

3)具体示例

step1:引入数据

step2:数据匹配

step3:找出绘制成灰色的 list

step4:绘制数据+世界地图

三、关于数据


一、项目简介

我的目标是实现一个 Dataframe 通过极短的代码输出一张带数据匹配的世界地图

我们先看绘制数据匹配的世界地图的代码长什么样子的:

import pandas as pd
from geo import *

# 读取文件
df = pd.read_csv('./data.csv')
df.rename(columns={'Total': 'The Average Number of MEDALS Won in The Past 25 Years'}, inplace=True)

# 获取匹配数据和未匹配成功的数据
[matched_df, unmatched_df] = match_data(find_style='en', 
                                        dataframe=df2, 
                                        column_country='NOC',
                                        column_data='Average number of gold MEDALS over the last 25 years', 
                                        fuzzy=True,
                                        conf=0.75)

# 获取要绘制成灰色的数据
key_list = matched_df['name'].drop_duplicates().tolist()
[stack, popped_list, unmatched_list] = get_gray_list_chinese(key_list)

# 绘制世界地图
plot_geo(dataframe=matched_df,
         gray_countries=stack,
         column_data="Average number of gold MEDALS over the last 25 years")

 最终绘制出来的结果如下所示:

利用Geo工具包在 Python 中的绘制结果

难点是数据匹配,因为谁也不知道数据的国家名称列是什么样的表达,尤其是对于英文,单单一个英国就有 United Kingdom、Britain、UK等等的表达,如果一个一个手动调整必将花费大量时间,这样在数学建模的相关竞赛中是相当不合理的。

因此,我利用 Python 的 geopandas 模块封装了一系列函数用于实现 Dataframe 直接绘制世界地图,同时借助 Python 中强大的 matplotlib 模块进行绘制地图,能够让美化变得更加“定制化”,让绘制地图的工作变得异常简单。称该工具包为 geo 工具包。


二、如何使用?

本项目目前已经封装好了世界地图的数据匹配和中国地图的绘制功能。

1)克隆项目 

首先,你需要在仓库中克隆项目。项目地址如下:GitHub: Python地理信息处理和可视化工具Python地理信息处理和可视化工具. Contribute to baojiachen0214/geo development by creating an account on GitHub.https://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geohttps://github.com/baojiachen0214/geo

(麻烦大家记得点个不要钱的 star 表示对项目的支持喔😃)

项目仓库剪影

最终克隆下来的项目文件是这样的:

项目基本结构

您可以在最外层的 geo 项目根目录下创建一个 Python 文件,进行后续的操作。

2)项目基本结构和功能

为了让大家能够快速掌握项目和功能,我们需要先快速了解文件结构和核心函数有哪些:

2-1)文件结构

  • geo.py: 包含所有核心功能函数,如城市查找、文件URL获取、地理信息查询、数据匹配等。
  • demo.ipynb: 示例笔记本文件,演示如何使用geo.py中的函数进行数据处理和可视化。
  • 2-2)函数介绍

            1. 数据清洗 (normalize_chinese)

            针对中文字符的专用清洗函数,能够处理NaN值、繁体转简体、去除空格标点符号等操作。

            2. 匹配逻辑 (get_gray_list_chinese)

            用于处理全局列表与输入列表之间的匹配关系,输出未匹配项、已匹配项及其余项。

            3. 批量匹配 (match_data)

            批量匹配地理名称并分离匹配/未匹配的数据,适用于DataFrame格式的数据集。支持多种查询方式(英文名、中文名或ISO代码),并可选择是否启用模糊匹配。

            4. 地理分布可视化 (plot_geo)

            基于Cartopy库绘制地理分布图,支持自定义颜色映射、图例配置等。可以将指定国家显示为灰色背景,并根据提供的数据列进行染色。

    3)具体示例

    我们重新明确一下目标:我们有一张 Dataframe,这张 Dataframe 里只有部分的国家的信息,我们希望表中的国家根据 Data 的大小映射不同的颜色到世界地图上,而不在数据表上的国家绘制成灰色。

    因此,我们的任务有两点:

  • 匹配表中存在的国家,并根据数据大小绘制成不同的彩色
  • 找到表中不存在的国家,并统一绘制成灰色
  • 具体案例如下:

    step1:引入数据

    首先,必须是两列内容的 Dataframe 才适用 geo 工具。其中有一列为国家名,一列为数据。我们希望数据能够根据其值得大小在世界地图上显示不同的颜色深度。读取文件示例如下:

    import pandas as pd
    df = pd.read_csv('./data.csv')

    我的操作环境配置是 Pycharm + Jupyter 服务器。查看我们拿到的数据:

    查看表的基本数据

    NOC列是国家标签列,Total列是数据列。如果后续绘图中你希望图例的名称进行修改,建议这里需要对Total列改一个名字(这个新列名字后续需要用到):

    df.rename(columns={'Total': 'Average number of gold MEDALS over the last 25 years'}, inplace=True)

    step2:数据匹配

    先引入我们项目的 geo 模块。由于前文的 df 中国家名称里面的信息都是英文,可以使用 en 模式匹配。如果是中文,则用 zh 模式去匹配;如果是简称,则用 ISO 模式匹配。在 geo 模块中已经尽可能地写入了所有国家的多个不同名称(中文、英文、缩写)。事实上,如果你能够仔细阅读 geo 模块中的代码,你还可以自行在数据库中添加自己的名称映射表。

    我们使用 geo 模块中的 match_data 函数实现匹配,match_data 函数的具体用法如下:

    def match_data(
            find_style: str,
            dataframe: pd.DataFrame,
            column_country: str = "name",
            column_data: str = "data",
            fuzzy: bool = True,
            conf: float = 0.6
    ) -> Tuple[pd.DataFrame, pd.DataFrame]:
        """
        批量匹配地理名称并分离匹配/未匹配数据
    
        :param find_style: 查询类型 ('en'/'zh'/'ISO')
        :param dataframe: 原始数据DataFrame,需包含国家名称和关联数据列
        :param column_country: 国家名称列名(默认'raw_country')
        :param column_data: 关联数据列名(默认'associated_data')
        :param fuzzy: 是否启用模糊匹配(默认True)
        :param conf: 模糊匹配阈值(默认0.6)
        :return: (匹配数据DataFrame, 未匹配数据DataFrame)
        """

    具体案例是:

    from geo import *
    
    [matched_df, unmatched_df] = match_data(find_style='en', 
                                            dataframe=df2, 
                                            column_country='NOC',
                                            column_data='Average number of gold MEDALS over the last 25 years', 
                                            fuzzy=True,
                                            conf=0.75)

    我们可以查看一下 matched_df 和 unmatched_df :

    matched_df 数据
    unmatched_df 数据

    这些数据是可能一些社会性的组织等,无法匹配成功。一般情况下,几百个数据里面可能只会出现几个无法匹配得上的,这个时候需要手都匹配或者自行对绘图数据进行修改。

    如果是手动匹配,你只需要将信息加入到 matched_df 表的最后即可:

    matched_df.loc[len(matched_df)] = {'name':'英国', 'Average number of gold MEDALS over the last 25 years': 131}

    请注意,加入的 name 需要是中文的,因为 match_data 匹配最终是把英文、ISO的数据向中文匹配。还有一个需要注意的是,这里的 matched_df 把第一列换成了 name ,是为了后续绘图能少传一个量,而 unmatched_df 还是保持了NOC,是为了查看和阅读的方便。如果你不喜欢这样,可以自行修改源代码,或者你有更好的策略,欢迎 submit 至项目仓库。

    step3:找出绘制成灰色的 list

    前文的 matched_df 就是要绘制,且匹配好的表。但是我们还期望拿到其他绘制成灰色的数据列表。使用 get_gray_list_chinese() 函数可以实现:

    key_list = matched_df['name'].drop_duplicates().tolist()
    [stack, popped_list, unmatched_list] = get_gray_list_chinese(key_list)

    其中 stack, popped_list, unmatched_list 分别对应 栈中剩下的元素(即灰色数据列表)、被弹出的元素(在未出错的情况下 popped_list 和 matched_df 的 name 列一致,用于检验)、未能成功匹配的数据列表(通常情况下为空表,只有在出现错误时才会有元素。如果出现元素,说明该信息不存在于该世界地图的JSON数据库中)。运行结果如下:

    step4:绘制数据+世界地图

    使用 plot_geo 函数完成绘制。plot_geo 函数的使用方法如下:

    def plot_geo(
            dataframe: pd.DataFrame,
            gray_countries: list,
            geo_data_path: str = "./geo/WGS1984/",
            column_data: str = "value",
            cmap_colors: list = ["#72B6A1", "#95A3C3", "#E99675"],
            figuresize: tuple = (10, 5),
            dpi: int = 190
    ) -> None:
        """
        地理分布可视化函数
    
        :param dataframe: 已匹配数据框,需包含标准化国家名称和数据列
        :param gray_countries: 需要显示为灰色的国家名称列表
        :param geo_data_path: GeoJSON文件存储路径
        :param column_data: 用于染色的数据列名
        :param cmap_colors: 自定义颜色渐变列表
        :param figuresize: 图像尺寸
        :param dpi: 图像分辨率
        """

    其中 cmap_colors 给出的是我最喜欢的三种科研论文配色。在刚才的案例里,代码如下: 

    plot_geo(dataframe=matched_df,
             gray_countries=stack,
             column_data="Average number of gold MEDALS over the last 25 years")

    示例结果如下:

    由于 plot_geo 是基于 matplotlib.pyplot 实现最终的绘图的,因此接下来你可以对这张图做很多数据操作(如绘制点、绘制折线等等,完全和其他的绘图一致),有了无限多的可能性。当然,如果你是将该代码用于数学建模的相关比赛,你可以用 Python 很容易地修改配色、修改样式,做得和别人不一样,而并非一个模子里出来的。

    三、关于数据

    世界各国的地图数据是从互联网上搜集而来的,可能并非是最新的数据或最正确的数据,请注意甄别!本人不对该数据负责,但所有使用者应当明确,坚持我国的领土完整,坚守一个中国原则钓鱼岛自古以来是属于中国的,南海是中国的领海

    关于国内的地图绘制,可以参考我的这篇文章。这篇所采用的是方案是请求阿里的地图JSON数据(需要联网),相对于互联网上搜索到的其他地图 JSON 数据要准确得多(目前该功能也集成到了geo 仓库中):

    Python绘制标准中国行政区划图+颜色匹配https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501https://blog.csdn.net/m0_66817474/article/details/145246905?spm=1001.2014.3001.5501

    如果在使用的过程中存在相关的疑问,欢迎评论区留言~ 

    作者:琛説

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【Python高级绘图+世界地图】原创Geo工具包绘制“数据+世界地图”精美热力图(含JSON数据+中/英文自动匹配)

    发表回复