v0.2.0: visualizations, interactive browser, arXiv paper, gap analysis

New features:
- 12 interactive visualizations (ietf viz): t-SNE landscape, similarity
  heatmap, score distributions, timeline, bubble explorer, radar charts,
  author network graph, category treemap, quality vs overlap, org bar chart,
  ideas chart, and interactive draft browser
- Interactive draft browser (browser.html): filterable by category, keyword,
  score sliders with sortable table and expandable detail rows
- arXiv paper (paper/main.tex): 13-page manuscript with all findings
- Gap analysis: 12 identified under-addressed areas
- Author network: collaboration graph, org contributions, cross-org analysis
- Draft generation from gaps (ietf draft-gen)
- Auto-load .env for API keys (python-dotenv)

New modules: visualize.py, authors.py, draftgen.py
New reports: timeline, overlap-matrix, authors, gaps
New deps: plotly, matplotlib, seaborn, scipy, scikit-learn, networkx, python-dotenv

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 13:37:55 +01:00
parent f44f9265bd
commit be9cf9c5d9
32 changed files with 4447 additions and 4 deletions

143
paper/export_figures.py Normal file
View File

@@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""Export interactive HTML visualizations to static images for the paper.
Run from the paper/ directory:
python export_figures.py
Copies PNG figures directly and exports HTML charts to PNG via plotly's kaleido engine.
If kaleido is not installed, creates placeholder PDFs instead.
"""
import shutil
from pathlib import Path
FIGURES_SRC = Path(__file__).parent.parent / "data" / "figures"
FIGURES_DST = Path(__file__).parent / "figures"
FIGURES_DST.mkdir(exist_ok=True)
# Direct PNG copies (already publication-ready)
PNG_FILES = [
"similarity-heatmap.png",
"score-distributions.png",
]
# HTML charts to export as static PNG (requires kaleido)
HTML_EXPORTS = {
"timeline.html": "timeline.png",
"score-vs-overlap.html": "quality.png",
"category-radar.html": "radar.png",
"author-network.html": "network.png",
"landscape-tsne.html": "landscape-tsne.png",
"bubble-explorer.html": "bubble.png",
"category-treemap.html": "treemap.png",
"org-contributions.html": "orgs.png",
}
def copy_pngs():
for name in PNG_FILES:
src = FIGURES_SRC / name
if src.exists():
shutil.copy2(src, FIGURES_DST / name)
print(f" Copied {name}")
else:
print(f" MISSING {name}")
def export_html_charts():
try:
import plotly.io as pio
from plotly.io import read_json
except ImportError:
print(" plotly not available, skipping HTML exports")
return
try:
# Test if kaleido is available
import kaleido
has_kaleido = True
except ImportError:
has_kaleido = False
print(" kaleido not installed (pip install kaleido)")
print(" To get static PNGs from HTML charts, install kaleido and re-run.")
print(" For now, creating placeholder instructions.\n")
if not has_kaleido:
# Write instructions for manual export
instructions = FIGURES_DST / "EXPORT_INSTRUCTIONS.md"
instructions.write_text(
"# Manual Figure Export\n\n"
"Install kaleido for automatic export:\n"
" pip install kaleido\n\n"
"Or open each HTML file in a browser and use the Plotly toolbar\n"
"(camera icon) to save as PNG.\n\n"
"Required files:\n"
+ "".join(f"- {v}\n" for v in HTML_EXPORTS.values())
)
print(f" Wrote {instructions}")
return
for html_name, png_name in HTML_EXPORTS.items():
src = FIGURES_SRC / html_name
if not src.exists():
print(f" MISSING {html_name}")
continue
try:
# Read the HTML, extract the plotly figure JSON, render to PNG
html_content = src.read_text()
# Extract Plotly JSON from the HTML
import json
import re
match = re.search(r'Plotly\.newPlot\(\s*"[^"]*"\s*,\s*(\[.*?\])\s*,\s*(\{.*?\})\s*,\s*\{',
html_content, re.DOTALL)
if match:
data = json.loads(match.group(1))
layout = json.loads(match.group(2))
import plotly.graph_objects as go
fig = go.Figure(data=data, layout=layout)
fig.write_image(str(FIGURES_DST / png_name), scale=2, width=1200, height=800)
print(f" Exported {html_name} -> {png_name}")
else:
print(f" Could not parse Plotly JSON from {html_name}")
except Exception as e:
print(f" Failed {html_name}: {e}")
def create_placeholder_pdfs():
"""Create minimal placeholder PDFs for figures that haven't been exported yet."""
placeholders = [
"timeline-placeholder.pdf",
"quality-placeholder.pdf",
"radar-placeholder.pdf",
"network-placeholder.pdf",
]
try:
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
for name in placeholders:
fig, ax = plt.subplots(figsize=(10, 6))
ax.text(0.5, 0.5, f"[{name.replace('-placeholder.pdf', '').upper()}]\n\n"
"Replace with exported figure from\n"
"data/figures/ (HTML → PNG/PDF)",
ha="center", va="center", fontsize=14, color="gray",
transform=ax.transAxes)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis("off")
fig.savefig(str(FIGURES_DST / name), bbox_inches="tight")
plt.close(fig)
print(f" Created placeholder: {name}")
except Exception as e:
print(f" Could not create placeholders: {e}")
if __name__ == "__main__":
print("Copying PNG figures...")
copy_pngs()
print("\nExporting HTML charts...")
export_html_charts()
print("\nCreating placeholder PDFs...")
create_placeholder_pdfs()
print("\nDone. Check paper/figures/ for outputs.")