Msk7000's picture
Upload 6 files
9babce0 verified
import streamlit as st
import pandas as pd
import numpy as np
import networkx as nx
from pyvis.network import Network
import streamlit.components.v1 as components
import matplotlib.font_manager as fm
import os
# --- 1. フォント設定 (長期メモリのデフォルト要件) ---
FONT_PATH = "NotoSansJP-Regular.ttf"
if os.path.exists(FONT_PATH):
fm.fontManager.addfont(FONT_PATH)
font_name = fm.FontProperties(fname=FONT_PATH).get_name()
else:
font_name = "sans-serif"
# --- 2. アプリ設定 ---
st.set_page_config(page_title="Interactive SNA Tool", layout="wide")
st.title("SNA:インタラクティブ隣接行列可視化")
nodes = ['A', 'B', 'C', 'D', 'E']
colors = ["#FF4B4B", "#1C83E1", "#00C04A", "#FFD700", "#800080"] # 美しい色分け
color_map = {node: color for node, color in zip(nodes, colors)}
# --- 3. セッション状態の管理 ---
if 'adj_df' not in st.session_state:
# 初期状態:全て0の5x5行列
st.session_state.adj_df = pd.DataFrame(
np.zeros((5, 5), dtype=int),
index=nodes,
columns=nodes
)
# --- 4. サイドバー:入力インターフェース ---
st.sidebar.header("1. 隣接行列の入力")
st.sidebar.info("上半三角(対角線より右上)のセルのみ編集可能です。")
# データエディタの表示
# ユーザーがどこを触っても、プログラム側で「上半三角以外を無効化・同期」する
edited_df = st.sidebar.data_editor(
st.session_state.adj_df,
column_config={
col: st.column_config.SelectboxColumn(
options=[0, 1],
required=True,
width="small"
) for col in nodes
},
hide_index=False,
key="matrix_editor"
)
# 【重要】上半三角のみを有効にするロジック
# 前回の値と比較して、上半三角(i < j)以外の変更をリセットし、
# 同時に下半三角を同期(対称化)させる
new_matrix = edited_df.values.copy()
old_matrix = st.session_state.adj_df.values
for i in range(5):
for j in range(5):
if i == j:
new_matrix[i, j] = 0 # 対角成分は0固定
elif i > j:
# 下半三角は上半三角(j, i)の値をコピー
new_matrix[i, j] = new_matrix[j, i]
final_df = pd.DataFrame(new_matrix, index=nodes, columns=nodes)
st.session_state.adj_df = final_df
# --- 5. メインコンテンツ:表示 ---
col1, col2 = st.columns([1, 1.5])
with col1:
st.subheader("隣接行列 (LaTeX表示)")
# LaTeX形式への変換
matrix_values = final_df.values
latex_str = r"A = \begin{pmatrix} "
rows = []
for row in matrix_values:
rows.append(" & ".join(map(str, row)))
latex_str += " \\\\ ".join(rows)
latex_str += r" \end{pmatrix}"
st.latex(latex_str)
st.write("---")
st.markdown(f"""
**現在の状態:**
- エッジ数: `{int(np.sum(matrix_values)/2)}`
- 無向グラフ(対称行列)
""")
with col2:
st.subheader("インタラクティブ・ネットワーク図")
st.caption("ノードをドラッグして移動できます。スクロールで拡大縮小可能です。")
# Pyvisを用いたグラフ作成
net = Network(height="500px", width="100%", bgcolor="#ffffff", font_color="#333333", directed=False)
# ノード追加
for i, node in enumerate(nodes):
net.add_node(node, label=node, color=colors[i], size=25, font={'size': 18, 'face': font_name})
# エッジ追加
for i in range(5):
for j in range(i + 1, 5):
if matrix_values[i, j] == 1:
net.add_edge(nodes[i], nodes[j], color="#888888", width=2)
# レイアウト設定(物理シミュレーション)
net.toggle_physics(True)
net.set_options("""
var options = {
"physics": {
"barnesHut": { "gravitationalConstant": -2000, "centralGravity": 0.3, "springLength": 150 },
"minVelocity": 0.75
}
}
""")
# HTMLとして保存してStreamlitで表示
try:
path = '/tmp' if os.name != 'nt' else '.'
file_path = f"{path}/nx.html"
net.save_graph(file_path)
with open(file_path, 'r', encoding='utf-8') as f:
html_data = f.read()
components.html(html_data, height=550)
except Exception as e:
st.error("グラフの描画中にエラーが発生しました。")