Skip to content

Commit f155763

Browse files
committed
Add interactive Plotly.js charts to GitHub Pages HTML report
- Add HTML generation with --html flag to unified_analysis.py - Create tabbed interface with 7 analysis sections - Add Plotly.js visualizations: bar charts, histograms, scatter plots - Embed chart data as JSON in HTML (no external API calls) - Add responsive CSS styling for tabs, tables, and charts - Implement tab switching with URL hash support - Preserve all explanatory text and data tables Each tab now includes interactive charts that visualize the analysis results, making the report more accessible and engaging for end users.
1 parent 65e7f3c commit f155763

File tree

5 files changed

+381
-54
lines changed

5 files changed

+381
-54
lines changed

Graph Analysis/unified_analysis.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ def write_html_report(
366366
<meta name="viewport" content="width=device-width, initial-scale=1.0">
367367
<title>Unified Graph Analysis Report</title>
368368
<link rel="stylesheet" href="style.css">
369+
<script src="https://cdn.plot.ly/plotly-2.26.0.min.js"></script>
369370
</head>
370371
<body>
371372
<div class="container">
@@ -389,6 +390,7 @@ def write_html_report(
389390
<div id="summary" class="tab-pane active">
390391
<h2>Summary</h2>
391392
<p class="explanation">These are high-level counts of nodes/edges for each graph constructed during analysis.</p>
393+
<div id="summary-chart"></div>
392394
<ul class="summary-list">
393395
""")
394396
for k, v in summary.items():
@@ -403,6 +405,7 @@ def write_html_report(
403405
404406
<h3>Top Nodes by Degree</h3>
405407
<p class="explanation">These are the people connected to the most unique others across meetings.</p>
408+
<div id="coattendance-top-chart"></div>
406409
<table>
407410
<thead>
408411
<tr><th>Rank</th><th>Node</th><th>Degree</th></tr>
@@ -417,6 +420,7 @@ def write_html_report(
417420
418421
<h3>Degree Distribution</h3>
419422
<p class="explanation">How many people fall into each degree (number of unique co-attendees) bucket.</p>
423+
<div id="coattendance-dist-chart"></div>
420424
<table>
421425
<thead>
422426
<tr><th>Degree</th><th>Count of Nodes</th></tr>
@@ -436,6 +440,7 @@ def write_html_report(
436440
437441
<h3>Top Fields by Degree</h3>
438442
<p class="explanation">These fields co-occur with the largest variety of other fields.</p>
443+
<div id="field-degree-top-chart"></div>
439444
<table>
440445
<thead>
441446
<tr><th>Rank</th><th>Field</th><th>Degree</th></tr>
@@ -450,6 +455,7 @@ def write_html_report(
450455
451456
<h3>Degree Distribution</h3>
452457
<p class="explanation">How many fields have each degree (number of distinct co-occurring fields).</p>
458+
<div id="field-degree-dist-chart"></div>
453459
<table>
454460
<thead>
455461
<tr><th>Degree</th><th>Count of Fields</th></tr>
@@ -483,6 +489,7 @@ def write_html_report(
483489
484490
<h3>Most Common Parent Paths</h3>
485491
<p class="explanation">Parents that appear most often, suggesting common structural hubs.</p>
492+
<div id="path-structure-chart"></div>
486493
<table>
487494
<thead>
488495
<tr><th>Rank</th><th>Parent Path</th><th>Count</th></tr>
@@ -500,6 +507,7 @@ def write_html_report(
500507
<h2>Field Centrality (Co-occurrence)</h2>
501508
<p class="explanation">Centrality scores highlight fields that are well-connected (degree), act as bridges (betweenness), are close to others (closeness), or connect to other influential fields (eigenvector).</p>
502509
510+
<div id="centrality-chart"></div>
503511
<table>
504512
<thead>
505513
<tr><th>Rank</th><th>Field</th><th>Degree</th><th>Betweenness</th><th>Closeness</th><th>Eigenvector</th></tr>
@@ -532,6 +540,7 @@ def write_html_report(
532540
533541
<h3>Top Nodes by Clustering Coefficient</h3>
534542
<p class="explanation">Fields whose immediate neighborhoods are most tightly interlinked.</p>
543+
<div id="clustering-chart"></div>
535544
<table>
536545
<thead>
537546
<tr><th>Rank</th><th>Field</th><th>Clustering</th></tr>
@@ -549,6 +558,7 @@ def write_html_report(
549558
<h2>Connected Components (Field Co-occurrence Graph)</h2>
550559
<p class="explanation">Components are groups of fields that are all reachable from each other; multiple components suggest separate substructures.</p>
551560
561+
<div id="components-chart"></div>
552562
<ul class="summary-list">
553563
<li><strong>Number of Components:</strong> """ + str(components['component_count']) + """</li>
554564
<li><strong>Component Sizes (top 10):</strong> """ + str(components['component_sizes'][:10]) + """</li>
@@ -564,6 +574,29 @@ def write_html_report(
564574
</div>
565575
</div>
566576
577+
<script type="text/javascript">
578+
// Embedded chart data
579+
const chartData = {
580+
summary: """ + json.dumps({k: v for k, v in summary.items()}) + """,
581+
coattendanceTop: """ + json.dumps([{"node": _truncate_label(node, 80), "degree": deg} for node, deg in attend_top], ensure_ascii=False) + """,
582+
coattendanceDist: """ + json.dumps([{"degree": d, "count": c} for d, c in attend_dist]) + """,
583+
fieldDegreeTop: """ + json.dumps([{"field": _truncate_label(node, 80), "degree": deg} for node, deg in field_top], ensure_ascii=False) + """,
584+
fieldDegreeDist: """ + json.dumps([{"degree": d, "count": c} for d, c in field_dist]) + """,
585+
pathStructure: """ + json.dumps([{"parent": parent, "count": cnt} for parent, cnt in parent_top], ensure_ascii=False) + """,
586+
centrality: """ + json.dumps([{
587+
"field": node,
588+
"degree": round(centrality["degree"].get(node, 0), 3),
589+
"betweenness": round(centrality["betweenness"].get(node, 0), 3),
590+
"closeness": round(centrality["closeness"].get(node, 0), 3),
591+
"eigenvector": round(centrality["eigenvector"].get(node, 0), 3)
592+
} for node in sorted(centrality["degree"].keys(), key=lambda x: centrality["degree"][x], reverse=True)[:10]], ensure_ascii=False) + """,
593+
clustering: """ + json.dumps([{"field": node, "clustering": round(val, 3)} for node, val in top_clust_nodes], ensure_ascii=False) + """,
594+
components: """ + json.dumps({
595+
"count": components['component_count'],
596+
"sizes": components['component_sizes'][:10]
597+
}) + """
598+
};
599+
</script>
567600
<script src="script.js"></script>
568601
</body>
569602
</html>

0 commit comments

Comments
 (0)