首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >利用热图与径向条形图探索公司的塑料废物情况

利用热图与径向条形图探索公司的塑料废物情况

作者头像
HsuHeinrich
发布2025-06-17 12:02:01
发布2025-06-17 12:02:01
2560
举报
文章被收录于专栏:HsuHeinrichHsuHeinrich

HsuHeinrich

用真心,分享最实用的技巧~

130篇原创内容

公众号

利用热图与径向条形图探索公司的塑料废物情况

代码语言:javascript
复制
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

plt.rcParams.update({"font.family": "Roboto"})

数据探索

以下数据如果有需要的同学可关注公众号HsuHeinrich,回复【数据可视化】自动获取~

代码语言:javascript
复制
data = pd.read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-01-26/plastics.csv")
data.head()
image-20240129172848518
image-20240129172848518

image-20240129172848518

公司塑料废物数据集: country:国家 year:年份 parent_company:公司名称 empty/hdpe/ldpe/o/pet/pp/ps/pvc:塑料类型,数值为改塑料类型的废物量

代码语言:javascript
复制
# 汇总计算各公司每年不同类型的塑料废物总量

types_of_plastic = ["empty", "hdpe", "ldpe", "o", "pet", "pp", "ps", "pvc"]
total_by_company = (
    data
    .groupby(["parent_company", "year"], dropna=True)[types_of_plastic]
    .sum()
    .reset_index()
)
total_by_company.head()
image-20240129172919149
image-20240129172919149

image-20240129172919149

代码语言:javascript
复制
def get_top_n_data(data, n):
    '''
    创建2020年塑料废物总量topN的公司数据
    '''

    # 计算2020年各公司的塑料废物总量(其实也可以按grand_total求和)
    top_data = (
        data
        .query("year == 2020") # 筛选2020年数据
        .melt(                 # 将长格式的df转为宽格式
            id_vars=["parent_company", "year"], # 保留的列
            value_vars=types_of_plastic, # 需要转化的列,即types_of_plastic列表中的列
            var_name="type" # 转化后的列名,注意原始列对应的值默认存在value列
        )
        .groupby("parent_company")["value"] # 按公司汇总计算所有类型塑料废物
        .sum()                              # 求和
        .reset_index()
    )

    # 处理异常数据,将其公司名转为Unbranded_unknown
    top_data["parent_company"] = np.where(
        top_data["parent_company"].isin(["Unbranded", "null", "NULL", "#ERROR!"]), 
        "Unbranded_unknown",
        top_data["parent_company"]
    )

    # 获取topN的公司名称
    top_companies = list(top_data.sort_values("value", ascending=False)["parent_company"][:n])

    # 将非topN的公司标记为Other
    top_data["company_lumped"] = np.where(
        top_data["parent_company"].isin(top_companies),
        top_data["parent_company"],
        "Other"
    )

    # 合并total_by_company与top_data
    top_data = top_data.drop_duplicates(["parent_company", "company_lumped"]) # 删除重复数据(若重复保留第一条)
    top_data = top_data.merge(total_by_company, on="parent_company") # inner join

    # 计算total,不包含'empty'
    top_data["total"] = top_data.loc[:, types_of_plastic[:]].sum(axis=)

    return top_data
代码语言:javascript
复制
# 构造top30的公司数据
top_thirty = get_top_n_data(total_by_company, n=)
# 展示构造的某个公司数据
top_thirty.query('company_lumped == "Bakhresa Group"') # value为2020年塑料废物总量,total为每年除empty塑料废物总量
image-20240129172959277
image-20240129172959277

image-20240129172959277

代码语言:javascript
复制
# 计算每家公司各类型塑料废物总量
top_thirty = (
    top_thirty
    .groupby("company_lumped")[types_of_plastic]
    .sum()
    .reset_index()
)

# 每家公司各类型塑料废物横向求和
top_thirty["row_sum"] = top_thirty.loc[:, types_of_plastic].sum(axis=)

# 计算各类型塑料废物比例
top_thirty[types_of_plastic] = top_thirty[types_of_plastic].apply(lambda x: x / top_thirty["row_sum"])

# 将长数据转为宽数据
top_thirty = top_thirty.melt(
    id_vars="company_lumped",  
    value_vars=types_of_plastic,
    var_name="type",
    value_name="proportion" # 将value列命名为proportion
)

top_thirty.head()
image-20240129173024645
image-20240129173024645

image-20240129173024645

代码语言:javascript
复制
# 对公司名称进行排序

# 公司名称列表
categories = list(top_thirty["company_lumped"].unique())
# 按名称小写排序
sorted_categories = sorted(categories, key=str.lower)
# 移除Other并追加到列表最后
sorted_categories.remove("Other")
sorted_categories.append("Other")
代码语言:javascript
复制
# 将company_lumped转为有序分类变量
top_thirty["company_lumped"] = pd.Categorical(
    top_thirty["company_lumped"], 
    categories=sorted_categories, 
    ordered=True
)

# 将top_thirty排序
top_thirty = top_thirty.sort_values("company_lumped", ascending=False)
top_thirty.head()
image-20240129173041851
image-20240129173041851

image-20240129173041851

通过散点图呈现热图效果

代码语言:javascript
复制
# 自定义调色板
COLORS = ["#0C2C84", "#225EA8", "#1D91C0", "#41B6C4", "#7FCDBB", "#C7E9B4", "#FFFFCC"]
# 利用COLORS列表创建自定义的颜色渐变
cmap = mcolors.LinearSegmentedColormap.from_list("colormap", COLORS, N=)
代码语言:javascript
复制
def plot_heatmap(ax):
    # 迭代每个塑料类型
    for i, plastic in enumerate(types_of_plastic):
        # 获取当前塑料类型的数据
        d = top_thirty[top_thirty["type"] == plastic]

        # 制作散点图所需的x和y
        y = d["company_lumped"]
        x = [i] * len(y)
        
        # proportion作为颜色(proportion作为颜色介于0和1之间,因此无需标准化)
        color = cmap(d["proportion"]) 
        
        # 绘制散点图
        ax.scatter(x, y, color=color, s=)

    # 美化轴
    ax.set_frame_on(False) # 删除边框
    ax.grid(alpha=0.4) # 设置网格线
    ax.set_axisbelow(True) # 网格线位于底层
    ax.set_xticks(np.arange(len(types_of_plastic))) # 设置x刻度位置
    ax.set_xticklabels(types_of_plastic) # 设置x刻度标签
    ax.tick_params(size=, colors="0.3") # 删除刻度线,并设置颜色为0.3来置灰
    ax.set_xlabel("Type of plastic", loc="right") # 设置x轴标签

    # 限制y轴范围
    y_shrunk = 0.75
    y_lower, y_upper = ax.get_ylim()
    ax.set_ylim(y_lower + y_shrunk, y_upper - y_shrunk)
    
    return ax

代码语言:javascript
复制
# 利用散点图绘制热图效果

fig, ax = plt.subplots(figsize=(, ))
plot_heatmap(ax);
output_15_0
output_15_0

output_15_0

绘制径向形条形图

代码语言:javascript
复制
# 自定义颜色,这里需要绘制top6公司的径向条形图
COMPANY_PALETTES = ["#81C4CA", "#468D96", "#103128", "#E83D5F", "#FA6E90", "#FCB16D"]
代码语言:javascript
复制
# 构造合适的数据

# 先获取top7的公司,因为存在Other
top_seven = get_top_n_data(total_by_company, n=)

# 长转宽
top_seven = top_seven.melt(
    id_vars="company_lumped",  
    value_vars=types_of_plastic,
    var_name="type",
    value_name="amount"
)

# 删除Unbranded_unknown、Other
top_seven = top_seven[~top_seven["company_lumped"].isin(["Unbranded_unknown", "Other"])]
# 删除ps、pvc、empty等塑料类型
top_seven = top_seven[~top_seven["type"].isin(["ps", "pvc", "empty"])]
# 计算各公司各塑料类型的废物总量
top_seven = top_seven.groupby(["company_lumped", "type"]).sum().reset_index()
top_seven = top_seven.rename({"amount": "total"}, axis=) # 重命名字段amount
# 计算比例
top_seven["prop"] = top_seven["total"] / top_seven.groupby("company_lumped")["total"].transform("sum")
代码语言:javascript
复制
# 自定义函数

def style_polar_axis(ax):
    '''
    美化极坐标轴
    '''
    # 将0弧度的位置逆时针旋转90度,使图形的起点位于上方
    ax.set_theta_offset(np.pi / )
    
    # 绘制方向顺时针(默认逆时针)
    ax.set_theta_direction(-1)

    # 移除边框
    ax.set_frame_on(False)

    # 移除刻度标签
    ax.set_xticklabels([])
    
    # 设置范围
    ax.set_ylim([, 4.5])
    
    # 设置y的刻度位置
    ax.set_yticks([, , , , , 4.5])
    
    # 移除刻度标签
    ax.set_yticklabels([])
    
    # 设置网格线,并且让网格线半透明
    ax.grid(alpha=0.4)

    return ax


def add_labels_polar_axis(ax, color):
    '''
    添加坐标轴标签(塑料类型),并自定义颜色
    '''
    # 定义样式
    bbox_dict = {
        "facecolor": "w", "edgecolor": color, "linewidth": , 
        "boxstyle": "round", "pad": 0.15
    }
    types_of_plastic = ["hdpe", "ldpe", "o", "pet", "pp"]
    # 遍历塑料类型在轴上添加文本标签
    for idx, plastic in enumerate(types_of_plastic):
        ax.text(
            , idx, plastic, color=color, ha="center", va="center",
            fontsize=, bbox=bbox_dict
        )
    return ax


def plot_circular(axes):
    '''
    通过极坐标绘制多个公司的径向条形图。循环绘制在多个子图上
    '''
    axes_flattened = axes.ravel() # 将接收的子图对象数组进行降维,返回一个一维的子图对象数组
    companies = top_seven["company_lumped"].unique() # 公司列表
    
    # 迭代为每个公司绘制径向条形图
    for i, company in enumerate(companies):
        # 提取数据
        d = top_seven[top_seven["company_lumped"] == company]
        
        # 绘制在对应的子图位置上
        ax = axes_flattened[i]
        
        # 在第一个子图上,设置 y 轴的标签("Type of plastic")。
        if i == :
            ax.set_ylabel("Type of plastic", loc="top")
        
        # 调用style_polar_axis函数美化轴
        ax = style_polar_axis(ax)
        
        # prop*2pi 极坐标系中的角度
        proportions = d["prop"].values * ( * np.pi)
        
        # y的位置
        y_pos = np.arange(len(proportions))
        
        # 计算所有子图的 x 和 y 值
        x = np.linspace(, proportions, num=)
        y = np.vstack([y_pos] * )

        # 选择颜色
        color = COMPANY_PALETTES[i]
        
        # 在子图上绘制圆周
        ax.plot(x, y, lw=, color=color, solid_capstyle="round")
        
        # 添加标题
        ax.set_title(company, pad=, color="0.3")
        
        # 在每个公司的圆周上添加标签
        ax = add_labels_polar_axis(ax, color)
    return axes
代码语言:javascript
复制
# 初始化布局
fig, axes = plt.subplots(, , figsize=(, ), subplot_kw={"projection": "polar"})

axes = plot_circular(axes)
output_20_0
output_20_0

output_20_0

合并热图与径向条形图

代码语言:javascript
复制
# 初始化布局
fig = plt.figure(figsize=(, ))

# 添加第一个网格布局:1*1
gs1 = fig.add_gridspec(nrows=, ncols=, left=0.25, right=0.5, top=0.85)

# 在上述网格图中绘制子图
ax = fig.add_subplot(gs1[])

# 绘制热图
plot_heatmap(ax)

# 创建一个空列表存放六个极坐标图的轴对象
axes = []
# 添加第一个网格布局:3*2
gs2 = fig.add_gridspec(nrows=, ncols=, left=0.55, right=0.95, hspace=0.25, top=0.85)
# 迭代每个单元格,以极坐标投影方式,将这些子图对象添加到 axes 列表中
for gs in gs2:
    axes.append(fig.add_subplot(gs, projection="polar"))

# 将列表转换成 NumPy 数组,方便后续处理
axes = np.array(axes)

# 在对应的子图对象上绘制极坐标图
plot_circular(axes);
output_22_0
output_22_0

output_22_0

参考:Heatmap and Radial Barchart with Matplotlib[1]

共勉~

参考资料

[1] 

Heatmap and Radial Barchart with Matplotlib: https://python-graph-gallery.com/web-heatmap-and-radial-barchart-plastics/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HsuHeinrich 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 利用热图与径向条形图探索公司的塑料废物情况
    • 数据探索
    • 通过散点图呈现热图效果
    • 绘制径向形条形图
    • 合并热图与径向条形图
      • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档