end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

networkx for python のお試し

networkxを初めて使用しますので、グラフデータ作成やその描画

# -*- coding: utf-8 -*-
import jaconv
import matplotlib.pyplot as plt
import networkx as nx
import sqlite3

#探索するルートノード
root_nodes = ["2C0???","2C1Q1???CIZW","2C8???45JBZL"]

db_path = 'bom.sqlite'
font    = "MS Gothic" # 日本語を表示する為

def main():
    # DB(sqlite)接続
    db_conn = sqlite3.connect( db_path )
    db_conn.row_factory = dict_factory
    db_cur  = db_conn.cursor()
    
    # ルートノード
    org_mims = root_nodes

    for org_mim in org_mims:
        root_node = select_mim_def(db_cur, org_mim)
        if root_node == None:
            print("fail select_mim() %s" % (org_mim))
            continue

        bom = nx.Graph()
        bom.add_node(1,**root_node) # ルートノード追加

        # 以下のように「data=True」とすることで属性も取得
        last_node = list( bom.nodes(data=True) )[-1]
        expand_bom(db_cur,bom, last_node)       # BOM展開
        draw_bom( bom )                         # BOM描画
    db_cur.close()
    db_conn.close()

def draw_bom( bom ):
    pos = nx.spring_layout(bom, k=0.3)
    # ノードと、そのラベルの表示
    nx.draw_networkx_nodes(bom,
                           pos,
                           node_color='#87cefa',
                           node_size=20)

    node_labels = nx.get_node_attributes(bom, 'label')
    nx.draw_networkx_labels(bom, pos, labels=node_labels,
                            font_size  =10,
                            font_family=font)
    # エッジと、そのラベルの表示
    nx.draw_networkx_edges(bom, pos,
                           arrows=True,
                           arrowstyle='->',
                           edge_color='#aaa')
    edge_labels = nx.get_edge_attributes(bom, 'label')
    
    nx.draw_networkx_edge_labels(bom, pos,
                                 edge_labels=edge_labels,
                                 font_family=font)
    plt.axis('off')
    plt.show()
    
def expand_bom(db_cur, bom, parent_node):

    for child_attr in select_children(db_cur,parent_node):
        child_id = list( bom.nodes )[-1] + 1
        child_attr["label"] = child_attr["code"]+"\n"+child_attr["name"]
        child_attr["label"] = child_attr["label"].replace(" ","\n")
        child_attr["label"] = jaconv.z2h(child_attr["label"],
                                         kana=True,
                                         digit=True,
                                         ascii=True )
        # add_node()やadd_edge()する際のIDはunique
        bom.add_node(child_id,**child_attr)
        bom.add_edge(parent_node[0],
                     child_id,
                     label =child_attr["use_amount"],
                     weight=child_attr["use_amount"] )
        child_node = list( bom.nodes(data=True) )[-1]
        expand_bom(db_cur, bom, child_node)

        
def select_children( db_cur, parent_node ):
    ret_datas = []
    ret_datas += select_mim_children(db_cur, parent_node)
    ret_datas += select_im_children(db_cur, parent_node)
    return ret_datas
    
# sql selectした結果をdict型で取得する為
def dict_factory(cursor, row):
   d = {}
   for idx, col in enumerate(cursor.description):
       d[col[0]] = row[idx]
   return d

def select_im_children(db_cur,parent_node):
    
    sql = """
SELECT mps.m_p_child as code,
       im.name_kanji as name,
       mps.use_amount
FROM mps
JOIN im ON (mps.m_p_child=im.part_num)
WHERE m_p_child_flag='P' AND m_p_parent=?
"""
    sql_vals = (parent_node[1]["code"],)
    db_cur.execute( sql, sql_vals )

    ret_datas = []
    for ret_data in db_cur.fetchall():
        ret_data["type"] = "im"
        ret_datas.append( ret_data )
    return ret_datas

def select_mim_children(db_cur,parent_node):
    
    sql = """
SELECT mps.m_p_child  as code,
       mim.name_kanji as name,
       mps.use_amount
FROM mps
JOIN mim ON (mps.m_p_child=mim.menu_code)
WHERE m_p_child_flag='M' AND m_p_parent=?
"""
    sql_vals = (parent_node[1]["code"],)
    db_cur.execute( sql, sql_vals )

    ret_datas = []
    for ret_data in db_cur.fetchall():
        ret_data["type"] = "mim"
        ret_datas.append( ret_data )
    return ret_datas

def select_mim_def(db_cur, menu_code):
    sql = """
SELECT menu_code as code, name_kanji as name
FROM mim
WHERE menu_code=?
"""
    sql_vals = (menu_code,)
    db_cur.execute( sql, sql_vals )
    ret_data = db_cur.fetchone()
    if not ret_data:
        return
        
    ret_data["type"] = "mim"

    ret_data["label"] = ret_data["code"]+" "+ret_data["name"]
    ret_data["label"] = ret_data["label"].replace(" ","\n")
    ret_data["label"] = jaconv.z2h(ret_data["label"],
                                   kana=True,
                                   digit=True,
                                   ascii=True )
    return ret_data

if __name__ == '__main__':
    main()