First Initialization
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
import networkx as nx
|
||||
from pyvis.network import Network
|
||||
import textwrap
|
||||
import ast
|
||||
import re
|
||||
|
||||
|
||||
class Visualizer:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def build_graph(self, propositions, relations, scores, output_path):
|
||||
"""
|
||||
دریافت ۳ ساختار مجزا (گزارهها، روابط، امتیازها) و رسم گراف
|
||||
"""
|
||||
net = Network(height="100vh", width="100%", bgcolor="#1a1a1a", font_color="white", directed=True,
|
||||
cdn_resources="in_line")
|
||||
|
||||
# ساخت دیکشنریهای کمکی برای جستجوی سریع
|
||||
prop_dict = {p['proposition_id']: p['proposition_text'] for p in propositions}
|
||||
score_dict = {s['relation_id']: s['score'] for s in scores}
|
||||
|
||||
# 1. اضافه کردن نودها (گزارهها)
|
||||
for p_id, text in prop_dict.items():
|
||||
wrapped_text = "\n".join(textwrap.wrap(text, width=40))
|
||||
net.add_node(
|
||||
p_id,
|
||||
label=f"گزاره {p_id}",
|
||||
title=wrapped_text, # نمایش متن کامل هنگام هاور پیشفرض
|
||||
shape="box",
|
||||
color={"background": "#264653", "border": "#1b3039", "highlight": {"background": "#2a9d8f"}},
|
||||
font={"face": "B Nazanin, Tahoma, Arial", "size": 16, "color": "white"}
|
||||
)
|
||||
|
||||
# 2. اضافه کردن یالها (روابط)
|
||||
for rel in relations:
|
||||
source = rel['source_proposition_id']
|
||||
target = rel['target_proposition_id']
|
||||
rel_id = rel['relation_id']
|
||||
rel_type = rel['relation_type']
|
||||
score = score_dict.get(rel_id, 0)
|
||||
|
||||
wrapped_rel = "\n".join(textwrap.wrap(rel_type, width=40))
|
||||
edge_title = f"امتیاز: {score}\n\nنوع رابطه:\n{wrapped_rel}"
|
||||
|
||||
if source in prop_dict and target in prop_dict:
|
||||
net.add_edge(
|
||||
source,
|
||||
target,
|
||||
label=str(score),
|
||||
title=edge_title, # نمایش متن در سایدبار از طریق رویداد
|
||||
width=max(2, int(score) / 2), # ضخامت خط بر اساس امتیاز
|
||||
color={"color": "#e9c46a", "highlight": "#f4a261"},
|
||||
font={"align": "middle", "color": "#ffea00", "background": "#1a1a1a"},
|
||||
arrows={"to": {"enabled": True, "scaleFactor": 1.2}}
|
||||
)
|
||||
|
||||
# تنظیمات گراف و فعالسازی هاور
|
||||
net.set_options("""
|
||||
{
|
||||
"physics": {
|
||||
"forceAtlas2Based": {
|
||||
"gravitationalConstant": -50,
|
||||
"centralGravity": 0.01,
|
||||
"springLength": 150,
|
||||
"springConstant": 0.08
|
||||
},
|
||||
"minVelocity": 0.75,
|
||||
"solver": "forceAtlas2Based"
|
||||
},
|
||||
"interaction": { "hover": true, "navigationButtons": true }
|
||||
}
|
||||
""")
|
||||
|
||||
html_content = net.generate_html(output_path)
|
||||
|
||||
# تزریق اسکریپت برای ارسال اطلاعات هاور به سایدبار صفحه وب
|
||||
hover_js = """
|
||||
<script type="text/javascript">
|
||||
network.on("hoverEdge", function (params) {
|
||||
var edgeData = edges.get(params.edge);
|
||||
window.parent.postMessage({ type: 'hoverEdge', info: edgeData.title }, '*');
|
||||
});
|
||||
network.on("hoverNode", function (params) {
|
||||
var nodeData = nodes.get(params.node);
|
||||
window.parent.postMessage({ type: 'hoverNode', info: nodeData.title }, '*');
|
||||
});
|
||||
network.on("blurEdge", function (params) {
|
||||
window.parent.postMessage({ type: 'blur', info: '' }, '*');
|
||||
});
|
||||
network.on("blurNode", function (params) {
|
||||
window.parent.postMessage({ type: 'blur', info: '' }, '*');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
"""
|
||||
html_content = html_content.replace('</body>', hover_js)
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(html_content)
|
||||
return output_path
|
||||
|
||||
def build_tree(self, tree_data_list, output_path):
|
||||
net = Network(height="100vh", width="100%", bgcolor="#1a1a1a", font_color="white", directed=True,
|
||||
cdn_resources="in_line")
|
||||
valid_node_ids = set()
|
||||
|
||||
for node_data in tree_data_list:
|
||||
node_id = str(node_data.get('segment_id', '')).strip()
|
||||
valid_node_ids.add(node_id)
|
||||
level = int(node_data.get('level', 0))
|
||||
|
||||
full_text = node_data.get('semantic_unit', 'بدون متن')
|
||||
wrapped_text = "\n".join(textwrap.wrap(full_text, width=40))
|
||||
|
||||
raw_sentences = node_data.get('original_sentences', [])
|
||||
if isinstance(raw_sentences, str):
|
||||
try:
|
||||
raw_sentences = ast.literal_eval(raw_sentences)
|
||||
except (ValueError, SyntaxError):
|
||||
pass
|
||||
|
||||
if isinstance(raw_sentences, list):
|
||||
sentences_str = "<br><br>".join(raw_sentences)
|
||||
num_sentences = len(raw_sentences)
|
||||
else:
|
||||
sentences_str = str(raw_sentences)
|
||||
num_sentences = len([s for s in sentences_str.split('.') if s.strip()]) if sentences_str else 0
|
||||
|
||||
# متمایز کردن رنگ برگها (سطح 0) از نودهای میانی
|
||||
bg_color = "#e76f51" if level == 0 else "#2a9d8f"
|
||||
|
||||
net.add_node(
|
||||
node_id,
|
||||
label=f"سطح {level}\n{node_id}",
|
||||
title=wrapped_text,
|
||||
level=level,
|
||||
shape="box",
|
||||
sentences=sentences_str,
|
||||
num_sentences=num_sentences,
|
||||
color={"background": bg_color, "border": "#1f6e64", "highlight": {"background": "#3bc2b4"}},
|
||||
font={"face": "B Nazanin, Tahoma, Arial", "size": 16}
|
||||
)
|
||||
|
||||
for node_data in tree_data_list:
|
||||
node_id = str(node_data.get('segment_id', '')).strip()
|
||||
parent_val = node_data.get('parent_segment_id')
|
||||
|
||||
if parent_val and str(parent_val).strip() != "":
|
||||
clean_parents_str = re.sub(r"[\[\]\'\"\s]", "", str(parent_val))
|
||||
parents_list = clean_parents_str.split(',')
|
||||
|
||||
for p_id in parents_list:
|
||||
if p_id in valid_node_ids:
|
||||
net.add_edge(
|
||||
p_id,
|
||||
node_id,
|
||||
width=3,
|
||||
color={"color": "#e9c46a", "highlight": "#f4a261"},
|
||||
arrows={"to": {"enabled": True, "scaleFactor": 1.2}},
|
||||
smooth={'type': 'cubicBezier', 'forceDirection': 'vertical', 'roundness': 0.4}
|
||||
)
|
||||
|
||||
net.set_options("""
|
||||
{
|
||||
"layout": {
|
||||
"hierarchical": {
|
||||
"enabled": true,
|
||||
"direction": "DU",
|
||||
"sortMethod": "directed",
|
||||
"nodeSpacing": 250,
|
||||
"levelSeparation": 150
|
||||
}
|
||||
},
|
||||
"physics": {
|
||||
"hierarchicalRepulsion": {
|
||||
"centralGravity": 0.0,
|
||||
"springLength": 100,
|
||||
"springConstant": 0.01,
|
||||
"nodeDistance": 250,
|
||||
"damping": 0.09
|
||||
},
|
||||
"solver": "hierarchicalRepulsion"
|
||||
},
|
||||
"interaction": { "hover": true, "navigationButtons": true }
|
||||
}
|
||||
""")
|
||||
|
||||
html_content = net.generate_html(output_path)
|
||||
|
||||
# تزریق اسکریپت کلیک درخت
|
||||
click_js = """
|
||||
<script type="text/javascript">
|
||||
network.on("click", function (params) {
|
||||
if (params.nodes.length > 0) {
|
||||
var nodeId = params.nodes[0];
|
||||
var clickedNode = nodes.get(nodeId);
|
||||
window.parent.postMessage({
|
||||
type: 'node_click',
|
||||
id: nodeId,
|
||||
label: clickedNode.label,
|
||||
summary: clickedNode.title,
|
||||
sentences: clickedNode.sentences || 'اطلاعات جملات موجود نیست.',
|
||||
num_sentences: clickedNode.num_sentences || 0
|
||||
}, '*');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
"""
|
||||
html_content = html_content.replace('</body>', click_js)
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(html_content)
|
||||
|
||||
return output_path
|
||||
Reference in New Issue
Block a user