跳转至

使用 Networkx 绘制二部图

本文以工厂 - 仓库的运输成本、仓库 - 商品的销量为背景,绘制了能清晰反映结点之间关系的二部图。

dc_sku_network

数据

工厂 - 仓库的运输成本

factory_id dc_id unit_cost
F001 DC001 224
F001 DC002 198
F001 DC003 196
F001 DC004 170
F001 DC005 170
F001 DC006 212
F001 DC007 169
F001 DC008 344
F001 DC009 283
F001 DC010 518
F001 DC011 458
F001 DC012 1452
F001 DC013 499
F001 DC014 438
F001 DC015 443
F001 DC016 396
F001 DC017 260
F001 DC018 248
F002 DC001 444
F002 DC002 434
F002 DC003 356
F002 DC004 428
F002 DC005 418
F002 DC006 399
F002 DC007 439
F002 DC008 477
F002 DC009 463
F002 DC010 390
F002 DC011 397
F002 DC012 875
F002 DC013 343
F002 DC014 268
F002 DC015 361
F002 DC016 378
F002 DC017 282
F002 DC018 310

仓库 - 商品的销量

由于数据量太大,这里只展示一部分。

date dc_id sku_id idx sale
2018/5/1 DC001 SKU052 DC001_SKU052 0
2018/5/1 DC001 SKU060 DC001_SKU060 9
2018/5/1 DC001 SKU029 DC001_SKU029 589
2018/5/1 DC001 SKU036 DC001_SKU036 43
2018/5/1 DC001 SKU045 DC001_SKU045 2751
2018/5/1 DC001 SKU068 DC001_SKU068 96
2018/5/1 DC001 SKU069 DC001_SKU069 200
2018/5/1 DC001 SKU070 DC001_SKU070 42
2018/5/1 DC001 SKU071 DC001_SKU071 10
2018/5/1 DC001 SKU011 DC001_SKU011 12
2018/5/1 DC001 SKU013 DC001_SKU013 0
2018/5/1 DC001 SKU016 DC001_SKU016 19
2018/5/1 DC001 SKU046 DC001_SKU046 1417
2018/5/1 DC001 SKU047 DC001_SKU047 352
2018/5/1 DC001 SKU062 DC001_SKU062 678
2018/5/1 DC001 SKU063 DC001_SKU063 80
2018/5/1 DC001 SKU001 DC001_SKU001 0
2018/5/1 DC001 SKU002 DC001_SKU002 5
2018/5/1 DC001 SKU022 DC001_SKU022 1920

代码

导入包

Python
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib_inline.backend_inline import set_matplotlib_formats

set_matplotlib_formats("svg")

工厂 - 仓库的运输成本

Python
def plot_transport_tarrif(self):
    """
    绘制 Factory-DC 运输成本网络图
    """
    # 创建一个空的无向图
    G = nx.Graph()
    # 向图中添加所有的工厂和配送中心
    G.add_nodes_from(self.factory_list + self.dc_list)
    # 向图中添加所有的运输费用记录,其中边的两端分别为配送中心
    G.add_edges_from(
        list(
            self.transport_tariff[["factory_id", "dc_id"]]
            .drop_duplicates()
            .itertuples(index=False, name=None)
        )
    )
    # 定义边的宽度,根据运输费用进行设置
    width = {}
    for idx, row in self.transport_tariff.iterrows():
        width[(row["factory_id"], row["dc_id"])] = row["unit_cost"] / 500
    # 获取一个二分图的布局
    pos = nx.bipartite_layout(G, self.factory_list)
    # 绘制图形,并设置边的宽度和节点的大小
    nx.draw(G, pos, width=[width[e] for e in G.edges], node_size=30)
    # 在左边添加“Factory”标注
    plt.text(-1.1, 0, "Factory", fontsize=12)
    # 在右边添加“DC”标注
    plt.text(0.15, 0, "DC", fontsize=12)
    # 添加标题
    plt.title("Transport Tariff")
    # 导出图像到本地
    plt.savefig("./image/transport_tariff.png", dpi=300, bbox_inches="tight")
    # 显示图像
    plt.show()

transport_tariff

仓库 - 商品的销量

Python
def plot_dc_sku_network(self, date=None):
    """
    绘制 DC-SKU 销售量网络图

    Args:
        date: str “YYYY-MM-DD”, e.g. “2020-01-01”
    """
    if date:
        data = self.sales_data[self.sales_data.date == date]
        # 控制边的宽度
        reducer = 10000
    else:
        data = self.sales_data
        # 控制边的宽度
        reducer = 5000000
    # 创建一个空的无向图
    G = nx.Graph()
    # 向图中添加所有的配送中心和商品
    G.add_nodes_from(self.dc_list + self.sku_list)
    # 向图中添加所有的销售记录,其中边的两端分别为配送中心和商品
    G.add_edges_from(
        list(
            data[["dc_id", "sku_id"]]
            .drop_duplicates()
            .itertuples(index=False, name=None)
        )
    )
    # 定义边的宽度,根据销售量进行设置
    width = {}
    for idx, row in data.iterrows():
        width[(row["dc_id"], row["sku_id"])] = (
            width.get((row["dc_id"], row["sku_id"]), 0) + row["sale"] / reducer
        )
    # 获取一个二分图的布局
    pos = nx.bipartite_layout(G, self.dc_list)
    # 绘制图形,并设置边的宽度和节点的大小
    nx.draw(G, pos, width=[width[e] for e in G.edges], node_size=30)
    # 在左边添加“DC”标注
    plt.text(-1.1, 0, "DC", fontsize=12)
    # 在右边添加“SKU”标注
    plt.text(0.3, 0, "SKU", fontsize=12)
    # 添加标题,导出图像到本地
    if date:
        plt.title(f"DC-SKU Network {date}")
        plt.savefig(f"./image/dc_sku_network_{date}.png", dpi=300, bbox_inches="tight")
    else:
        plt.title("DC-SKU Network")
        plt.savefig("./image/dc_sku_network.png", dpi=300, bbox_inches="tight")
    # 显示图像
    plt.show()

dc_sku_network

评论