使用 Networkx 绘制二部图¶
本文以工厂 - 仓库的运输成本、仓库 - 商品的销量为背景,绘制了能清晰反映结点之间关系的二部图。
数据¶
工厂 - 仓库的运输成本¶
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()
仓库 - 商品的销量¶
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()