import pickle from sqlalchemy import text from orm import engine, connection import pandas as pd import networkx as nx import json import matplotlib.pyplot as plt # Prepare data Firm = pd.read_csv("input_data/input_firm_data/Firm_amended.csv") Firm['Code'] = Firm['Code'].astype('string') Firm.fillna(0, inplace=True) BomNodes = pd.read_csv('input_data/input_product_data/BomNodes.csv', index_col=0) # SQL query with open('SQL_analysis_risk.sql', 'r') as f: str_sql = text(f.read()) result = pd.read_sql(sql=str_sql, con=connection) result.to_csv('output_result/risk/count.csv', index=False, encoding='utf-8-sig') print(result) # G_bom plt.rcParams['font.sans-serif'] = 'SimHei' exp_id = 1 G_bom_df = pd.read_sql( sql=text(f'select g_bom from iiabmdb.without_exp_experiment where id = {exp_id};'), con=connection ) if G_bom_df.empty: raise ValueError(f"No g_bom found for exp_id = {exp_id}") G_bom_str = G_bom_df['g_bom'].tolist()[0] if G_bom_str is None: raise ValueError(f"g_bom data is None for exp_id = {exp_id}") G_bom = nx.adjacency_graph(json.loads(G_bom_str)) pos = nx.nx_agraph.graphviz_layout(G_bom, prog="twopi", args="") node_labels = nx.get_node_attributes(G_bom, 'Name') node_labels = { 7: 'Si Raw Mtl.', 8: 'Photoresist & Reagents', 9: 'Etch Solution', 10: 'SiF4', 11: 'Developer', 12: 'PCE Superplasticizer', 13: 'Metal Protectant', 14: 'Deep Hole Cu Plating', 15: 'Thinner', 16: 'HP Boric Acid (Nuc.)', 17: 'E-Grade Epoxy', 18: 'Stripper', 19: 'HP-MOC', 20: 'CMP Slurry & Consumables', 21: 'PR Remover', 22: 'Poly-Si Cutting Fluid', 23: 'Passivation', 24: 'E-Grade Phenolic', 25: 'Surfactant', 26: 'Mag. Carrier', 27: 'Wet Chems.', 28: 'Plating Chems.', 29: 'E-FR Materials', 30: 'LC Alignment Agent', 31: 'Func. Wet Chems.', 32: 'InP', 33: 'SiC', 34: 'GaAs', 35: 'GaN', 36: 'AlN', 37: 'Si3N4', 38: 'SiC Substrate', 39: 'GaN Substrate', 40: 'Si Wafer', 41: 'AlN Substrate', 42: 'DUV LED Substrate', 43: 'InP Substrate', 44: 'Mono-Si Wafer', 45: 'Poly-Si Wafer', 46: 'InP Cryst./Wafer', 47: 'SiC Cryst./Wafer', 48: 'GaAs Wafer', 49: 'GaN Cryst./Wafer', 50: 'Si Epi Wafer', 51: 'SiC Epi Wafer', 52: 'AlN Epi', 53: 'GaN Epi', 54: 'InP Epi', 55: 'LED Epi', 56: 'EDA/IP', 57: 'MPW Service', 58: 'IC Design', 59: 'Track System', 60: 'Wafer Grinder', 61: 'Etcher', 62: 'Ox/Diff Furnace', 63: 'Wafer Metrology', 64: 'Crystal Grower', 65: 'CMP Tool', 66: 'Stepper', 67: 'Wafer Dicer', 68: 'Deposition System', 69: 'Edge Profiler', 70: 'Descum Tool', 71: 'Clean System', 72: 'SAF', 73: 'Plating Eqpt.', 74: 'Implanter', 75: 'Trim/Form', 76: 'Probe Card', 77: 'ATE', 78: 'PCM Eqpt.', 79: 'Inspection Sys.', 80: 'Prober', 81: 'Dicing Saw', 82: 'Handler', 83: 'Backgrinder', 84: 'Die Bonder', 85: 'Reflow Oven', 86: 'FT Tester', 87: 'Wire Bonder', 88: 'BGA Mounter', 89: 'Molding Press', 90: 'Power Devices', 91: 'Diode', 92: 'Transistor', 93: 'Thyristor', 94: 'Rectifier', 95: 'IC Fab', 96: 'IC PKG', 97: 'DV', 98: 'IPM', 99: 'CP Test', 100: 'FT Test', 101: 'Bumping', 102: 'DA Materials', 103: 'Leadframe', 104: 'Solder Ball', 105: 'Substrate', 106: 'EMC', 107: 'Bond Wire', 108: 'Underfill', 109: 'Dicing Tape' } plt.figure(figsize=(12, 12), dpi=500) plt.axis('off') # 关闭坐标轴边框 # 优化节点绘制参数 nx.draw_networkx_nodes( G_bom, pos, node_size=100, # 优化节点尺寸 linewidths=0.0 # 去除节点边框 ) # 优化边绘制参数 nx.draw_networkx_edges( G_bom, pos, width=0.3, # 更细的边宽 alpha=0.5 # 半透明边 ) # 优化标签参数 nx.draw_networkx_labels( G_bom, pos, labels=node_labels, font_size=3, # 适当增大字号 font_family='sans-serif', # 使用无衬线字体 font_weight='bold', # 增强可读性 ) # 专业级保存参数设置 plt.savefig( f"output_result/risk/g_bom_exp_id_{exp_id}.png", bbox_inches='tight', # 去除图像白边 pad_inches=0.1, # 适当内边距 facecolor='white' # 保证背景纯白 ) plt.close() # G_firm plt.rcParams['font.sans-serif'] = 'SimHei' sample_id = 1 # G_firm_df = pd.read_sql( # sql=text(f'select g_firm from iiabmdb.without_exp_sample where id = {sample_id};'), # con=connection # ) # # if G_firm_df.empty: # raise ValueError(f"No g_firm found for sample_id = {sample_id}") # # G_firm_str = G_firm_df['g_firm'].tolist()[0] # if G_firm_str is None: # raise ValueError(f"g_firm data is None for sample_id = {sample_id}") # # G_firm = nx.adjacency_graph(json.loads(G_firm_str)) with open("firm_network.pkl", 'rb') as f: G_firm = pickle.load(f) print(f"Successfully loaded cached data from firm_network.pkl") # 1. 移除孤立节点 isolated_nodes = list(nx.isolates(G_firm)) # 找出所有没有连接的孤立节点 G_firm.remove_nodes_from(isolated_nodes) # 从图中移除这些节点 # 2. 重新布局和绘图 pos = nx.nx_agraph.graphviz_layout(G_firm, prog="twopi", args="") node_label = {key: key for key in nx.get_node_attributes(G_firm, 'Revenue_Log').keys()} node_label = { "7": "1", "9": "2", "829768": "4", "863079": "5", "1452048": "6", "2010673": "7", "2624175": "8", "2728939": "9", "5278074": "10", "5849940": "11", "7299120": "12", "9746245": "13", "11807506": "14", "15613202": "15", "24284343": "19", "24673506": "20", "25036634": "21", "25685135": "24", "25945288": "25", "26162741": "26", "26516263": "27", "27075840": "28", "27731896": "29", "29954548": "30", "43407343": "33", "70634828": "36", "71271700": "37", "80158773": "39", "118882692": "40", "145511905": "42", "151606446": "43", "152008168": "44", "159511306": "45", "191912252": "46", "194210021": "47", "203314437": "48", "213386023": "49", "218633337": "50", "251189644": "53", "271860868": "55", "278221281": "56", "301209792": "57", "343012684": "59", "354897041": "60", "400488703": "62", "400692942": "63", "413274977": "64", "420984285": "65", "448033045": "66", "453289520": "67", "474279224": "68", "483081978": "69", "495782506": "70", "503176785": "73", "549184982": "75", "560866402": "76", "561545339": "77", "571058167": "78", "581407487": "79", "591452402": "80", "593312758": "81", "594378026": "82", "607512171": "83", "615763365": "84", "620220747": "85", "631449822": "86", "644292599": "87", "653528340": "88", "654825436": "89", "688155470": "92", "695995052": "93", "750610681": "95", "762985858": "96", "771821595": "97", "857978527": "100", "868012326": "101", "887840774": "102", "888356483": "103", "888395016": "104", "888478182": "105", "930767828": "107", "996174506": "108", "1033972427": "110", "1128343125": "111", "1217957486": "113", "1307012237": "115", "1375606900": "116", "1549474227": "118", "1606833003": "120", "1679596339": "121", "2310825263": "122", "2311838590": "124", "2312490120": "125", "2316990095": "128", "2317245827": "129", "2317841563": "131", "2320102626": "132", "2320475044": "133", "2321109759": "134", "2324787028": "137", "2324844174": "138", "2326478786": "139", "2327031723": "140", "2327979389": "141", "2329375731": "142", "2333843479": "143", "2337952436": "146", "2339188563": "147", "2339684065": "148", "2341555098": "149", "2343704209": "150", "2348941764": "151", "2352036411": "155", "2354145351": "157", "2424229017": "159", "2545430247": "161", "2820140348": "163", "2944892892": "165", "3025036704": "168", "3026382513": "169", "3045721313": "171", "3047163873": "172", "3048263744": "173", "3069206426": "174", "3070859372": "175", "3072715478": "176", "3103797386": "177", "3111033905": "178", "3113895788": "179", "3120341363": "180", "3122923980": "181", "3127420424": "182", "3133307899": "183", "3147511625": "184", "3177507356": "185", "3188903709": "186", "3195502499": "187", "3203777710": "188", "3211956484": "189", "3215814536": "190", "3221190269": "191", "3226664625": "192", "3267688490": "193", "3269039233": "194", "3269940677": "195", "3271705843": "196", "3299144127": "197", "3312358902": "198", "3344297292": "200", "3372913783": "201", "3373311444": "202", "3384021594": "203", "3395900897": "205", "3398677646": "206", "3407754893": "207", "3433628561": "209", "3445244192": "212", "3445928818": "213", "4208851809": "216", "5007015990": "218", "11164476478": "219", "517717050": "223", "737770776": "224", "872394725": "225", "2311581270": "226", "2313209417": "227", "2347013470": "228", "2350418059": "229", "3031009366": "234", "3089095447": "235", "3100891962": "236", "3188352290": "238", "3288105727": "239", "3462551351": "240" } node_size = [value * 5 for value in nx.get_node_attributes(G_firm, 'Revenue_Log').values()] edge_label = {(n1, n2): label for (n1, n2, _), label in nx.get_edge_attributes(G_firm, "Product").items()} plt.figure(figsize=(15, 15), dpi=500) plt.axis('off') # 完全关闭坐标轴系统 # 分层绘制网络组件 nodes = nx.draw_networkx_nodes( G_firm, pos, node_size=node_size, # 保持原始尺寸设置 ) edges = nx.draw_networkx_edges( G_firm, pos, width=0.3, # 保持原始线宽设置 ) # 优化节点标签 labels = nx.draw_networkx_labels( G_firm, pos, labels=node_label, font_size=6, # 保持原始字号 ) # 增强边标签可读性 edge_labels = nx.draw_networkx_edge_labels( G_firm, pos, edge_labels=edge_label, font_size=2, label_pos=0.5, # 标签沿边偏移量 rotate=False, # 禁止自动旋转 ) # 专业级输出配置 plt.savefig( f"output_result/risk/g_firm_sample_id_{sample_id}_de.png", bbox_inches='tight', pad_inches=0.05, # 更紧凑的边距 facecolor='white', # 强制白色背景 metadata={ 'Title': f"Supply Chain Risk Map - Sample {sample_id}", 'Author': 'USTB Risk Analytics', 'Copyright': 'Confidential' } ) plt.close() # Count firm product count_firm_prod = result.value_counts(subset=['id_firm', 'id_product']) count_firm_prod.name = 'count' count_firm_prod = count_firm_prod.to_frame().reset_index() count_firm_prod.to_csv('output_result/risk/count_firm_prod.csv', index=False, encoding='utf-8-sig') print(count_firm_prod) # Count firm count_firm = count_firm_prod.groupby('id_firm')['count'].sum() count_firm = count_firm.to_frame().reset_index() count_firm.sort_values('count', inplace=True, ascending=False) count_firm.to_csv('output_result/risk/count_firm.csv', index=False, encoding='utf-8-sig') print(count_firm) # Count product count_prod = count_firm_prod.groupby('id_product')['count'].sum() count_prod = count_prod.to_frame().reset_index() count_prod.sort_values('count', inplace=True, ascending=False) count_prod.to_csv('output_result/risk/count_prod.csv', index=False, encoding='utf-8-sig') print(count_prod) # DCP disruption causing probability result_disrupt_ts_above_0 = result[result['ts'] > 0] print(result_disrupt_ts_above_0) result_dcp = pd.DataFrame(columns=[ 's_id', 'up_id_firm', 'up_id_product', 'down_id_firm', 'down_id_product' ]) result_dcp_list = [] # 用列表收集数据,避免DataFrame逐行增长的问题 for sid, group in result.groupby('s_id'): ts_start = max(group['ts']) while ts_start >= 1: ts_end = ts_start - 1 while ts_end >= 0: up = group.loc[group['ts'] == ts_end, ['id_firm', 'id_product']] down = group.loc[group['ts'] == ts_start, ['id_firm', 'id_product']] for _, up_row in up.iterrows(): for _, down_row in down.iterrows(): result_dcp_list.append([sid] + up_row.tolist() + down_row.tolist()) ts_end -= 1 ts_start -= 1 # 转换为DataFrame result_dcp = pd.DataFrame(result_dcp_list, columns=[ 's_id', 'up_id_firm', 'up_id_product', 'down_id_firm', 'down_id_product' ]) # 统计 count_dcp = result_dcp.value_counts( subset=['up_id_firm', 'up_id_product', 'down_id_firm', 'down_id_product'] ).reset_index(name='count') # 保存文件 count_dcp.to_csv('output_result/risk/count_dcp.csv', index=False, encoding='utf-8-sig') # 输出结果 print(count_dcp)