Skip to content

Commit 65379c2

Browse files
committed
Regenerate charts from original Dash app definitions with correct data and styling
1 parent 0519ba0 commit 65379c2

8 files changed

+518
-202
lines changed

docs/chart1-supplier-influence.html

Lines changed: 41 additions & 34 deletions
Large diffs are not rendered by default.

docs/chart3-defense-systems.html

Lines changed: 40 additions & 33 deletions
Large diffs are not rendered by default.

docs/chart4-multi-country-radar.html

Lines changed: 41 additions & 34 deletions
Large diffs are not rendered by default.

docs/chart5-priorities-heatmap.html

Lines changed: 41 additions & 34 deletions
Large diffs are not rendered by default.

docs/chart7-supplier-connections.html

Lines changed: 40 additions & 33 deletions
Large diffs are not rendered by default.

docs/threat-perception-analysis.html

Lines changed: 41 additions & 34 deletions
Large diffs are not rendered by default.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Export charts from the Dash app pages as standalone HTML files
3+
"""
4+
5+
import os
6+
import sys
7+
8+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
9+
10+
from geopolitical_app import create_threat_density_map
11+
from pages.chart1 import create_3d_surface_figure
12+
from pages.chart3 import create_3d_scatter_figure
13+
from pages.chart4 import create_radar_figure
14+
from pages.chart5 import create_heatmap_figure
15+
from pages.chart7 import create_connection_map_figure
16+
17+
def main():
18+
print("=" * 70)
19+
print("EXPORTING CHARTS FROM DASH APP")
20+
print("=" * 70)
21+
print()
22+
23+
charts = [
24+
("Chart 0: Threat Perception", create_threat_density_map, "threat-perception-analysis", {}),
25+
("Chart 1: Supplier Influence", create_3d_surface_figure, "chart1-supplier-influence", {"influence_type": "Influence", "show_all_countries": True}),
26+
("Chart 3: Defense Systems", create_3d_scatter_figure, "chart3-defense-systems", {"supplier_filter": "all"}),
27+
("Chart 4: Multi-Country Radar", create_radar_figure, "chart4-multi-country-radar", {"selected_countries": None, "metric_type": "influence"}),
28+
("Chart 5: Priorities Heatmap", create_heatmap_figure, "chart5-priorities-heatmap", {"grouping": "country", "intensity_metric": "influence"}),
29+
("Chart 7: Supplier Connections", create_connection_map_figure, "chart7-supplier-connections", {"selected_supplier": "all"}),
30+
]
31+
32+
generated_files = []
33+
34+
for title, chart_func, filename, kwargs in charts:
35+
try:
36+
print(f"📊 {title}")
37+
fig = chart_func(**kwargs)
38+
html_file = f"{filename}.html"
39+
fig.write_html(html_file)
40+
generated_files.append((title, html_file))
41+
print(f" ✅ Saved: {html_file}")
42+
except Exception as e:
43+
print(f" ❌ Error: {e}")
44+
import traceback
45+
traceback.print_exc()
46+
print()
47+
48+
print("=" * 70)
49+
print(f"✅ EXPORTED {len(generated_files)} CHARTS")
50+
print("=" * 70)
51+
52+
if __name__ == '__main__':
53+
main()
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
"""
2+
Wrap exported charts with navigation tabs and copy to docs folder
3+
"""
4+
5+
import os
6+
import re
7+
import shutil
8+
9+
def wrap_chart_with_navigation(chart_file, chart_id, chart_title):
10+
"""Wrap existing chart HTML with navigation and styling"""
11+
12+
with open(chart_file, 'r', encoding='utf-8', errors='ignore') as f:
13+
original_html = f.read()
14+
15+
# Extract everything between <body> and </body>
16+
body_match = re.search(r'<body[^>]*>(.*?)</body>', original_html, re.DOTALL)
17+
body_content = body_match.group(1) if body_match else ""
18+
19+
# Extract head content (scripts, styles)
20+
head_match = re.search(r'<head[^>]*>(.*?)</head>', original_html, re.DOTALL)
21+
head_content = head_match.group(1) if head_match else ""
22+
23+
# Navigation HTML
24+
nav_html = '''
25+
<nav class="navbar">
26+
<div class="navbar-container">
27+
<a class="navbar-brand" href="index.html">🌍 Geopolitical Dashboard</a>
28+
<div class="nav-tabs">
29+
<a href="threat-perception-analysis.html" class="nav-tab''' + (' active' if chart_id == 'threat' else '') + '''">Threat Perception</a>
30+
<a href="chart1-supplier-influence.html" class="nav-tab''' + (' active' if chart_id == 'chart1' else '') + '''">Supplier Influence</a>
31+
<a href="chart3-defense-systems.html" class="nav-tab''' + (' active' if chart_id == 'chart3' else '') + '''">Defense Systems</a>
32+
<a href="chart4-multi-country-radar.html" class="nav-tab''' + (' active' if chart_id == 'chart4' else '') + '''">Multi-Country Radar</a>
33+
<a href="chart5-priorities-heatmap.html" class="nav-tab''' + (' active' if chart_id == 'chart5' else '') + '''">Priorities Heatmap</a>
34+
<a href="chart7-supplier-connections.html" class="nav-tab''' + (' active' if chart_id == 'chart7' else '') + '''">Supplier Connections</a>
35+
</div>
36+
</div>
37+
</nav>
38+
'''
39+
40+
# Create wrapper HTML
41+
wrapper_html = f'''<!DOCTYPE html>
42+
<html lang="en">
43+
<head>
44+
<meta charset="UTF-8">
45+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
46+
<title>{chart_title} | Geopolitical Dashboard</title>
47+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
48+
<style>
49+
* {{
50+
margin: 0;
51+
padding: 0;
52+
box-sizing: border-box;
53+
}}
54+
55+
body {{
56+
background: linear-gradient(135deg, #0d1b2a 0%, #1a1a2e 100%);
57+
color: #fff;
58+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
59+
}}
60+
61+
.navbar {{
62+
background-color: #0d1b2a;
63+
border-bottom: 2px solid #1e90ff;
64+
padding: 15px 20px;
65+
box-shadow: 0 2px 10px rgba(30, 144, 255, 0.2);
66+
}}
67+
68+
.navbar-container {{
69+
max-width: 100%;
70+
margin: 0 auto;
71+
display: flex;
72+
justify-content: space-between;
73+
align-items: center;
74+
flex-wrap: wrap;
75+
gap: 20px;
76+
}}
77+
78+
.navbar-brand {{
79+
font-size: 1.5rem;
80+
font-weight: bold;
81+
color: #1e90ff;
82+
text-decoration: none;
83+
white-space: nowrap;
84+
}}
85+
86+
.navbar-brand:hover {{
87+
color: #00d4ff;
88+
}}
89+
90+
.nav-tabs {{
91+
display: flex;
92+
gap: 10px;
93+
flex-wrap: wrap;
94+
justify-content: flex-end;
95+
}}
96+
97+
.nav-tab {{
98+
padding: 8px 15px;
99+
background-color: #1a1a2e;
100+
border: 1px solid #1e90ff;
101+
border-radius: 4px;
102+
color: #aaa;
103+
text-decoration: none;
104+
font-size: 0.85rem;
105+
transition: all 0.3s;
106+
white-space: nowrap;
107+
}}
108+
109+
.nav-tab:hover {{
110+
background-color: #1e90ff;
111+
color: #fff;
112+
border-color: #00d4ff;
113+
}}
114+
115+
.nav-tab.active {{
116+
background-color: #1e90ff;
117+
color: #fff;
118+
border-color: #00d4ff;
119+
}}
120+
121+
.content-container {{
122+
padding: 20px;
123+
max-width: 100%;
124+
}}
125+
126+
.footer {{
127+
background-color: #0d1b2a;
128+
border-top: 2px solid #1e90ff;
129+
padding: 20px;
130+
text-align: center;
131+
color: #aaa;
132+
margin-top: 40px;
133+
}}
134+
135+
@media (max-width: 768px) {{
136+
.navbar-container {{
137+
flex-direction: column;
138+
align-items: flex-start;
139+
}}
140+
141+
.nav-tabs {{
142+
justify-content: flex-start;
143+
width: 100%;
144+
}}
145+
146+
.nav-tab {{
147+
flex: 1;
148+
text-align: center;
149+
min-width: 100px;
150+
}}
151+
}}
152+
</style>
153+
{head_content}
154+
</head>
155+
<body>
156+
{nav_html}
157+
<div class="content-container">
158+
{body_content}
159+
</div>
160+
<div class="footer">
161+
<p>© 2025 Geopolitical Analysis Dashboard</p>
162+
</div>
163+
</body>
164+
</html>'''
165+
166+
return wrapper_html
167+
168+
def main():
169+
print("=" * 70)
170+
print("WRAPPING CHARTS WITH NAVIGATION")
171+
print("=" * 70)
172+
print()
173+
174+
charts = [
175+
("threat-perception-analysis.html", "threat", "Threat Perception Analysis"),
176+
("chart1-supplier-influence.html", "chart1", "Supplier Influence"),
177+
("chart3-defense-systems.html", "chart3", "Defense Systems Analysis"),
178+
("chart4-multi-country-radar.html", "chart4", "Multi-Country Radar"),
179+
("chart5-priorities-heatmap.html", "chart5", "Priorities Heatmap"),
180+
("chart7-supplier-connections.html", "chart7", "Supplier Connections"),
181+
]
182+
183+
for chart_file, chart_id, chart_title in charts:
184+
try:
185+
print(f"📊 Wrapping {chart_title}...")
186+
wrapped_html = wrap_chart_with_navigation(chart_file, chart_id, chart_title)
187+
188+
# Write wrapped version back
189+
with open(chart_file, 'w', encoding='utf-8') as f:
190+
f.write(wrapped_html)
191+
192+
print(f" ✅ Wrapped: {chart_file}")
193+
except Exception as e:
194+
print(f" ❌ Error: {e}")
195+
import traceback
196+
traceback.print_exc()
197+
print()
198+
199+
print("=" * 70)
200+
print("COPYING CHARTS TO DOCS FOLDER")
201+
print("=" * 70)
202+
print()
203+
204+
docs_folder = "../docs"
205+
os.makedirs(docs_folder, exist_ok=True)
206+
207+
for chart_file, _, _ in charts:
208+
try:
209+
dest = os.path.join(docs_folder, chart_file)
210+
shutil.copy(chart_file, dest)
211+
print(f"✅ Copied {chart_file} to {dest}")
212+
except Exception as e:
213+
print(f"❌ Error copying {chart_file}: {e}")
214+
215+
print()
216+
print("=" * 70)
217+
print("✅ ALL CHARTS WRAPPED AND DEPLOYED")
218+
print("=" * 70)
219+
220+
if __name__ == '__main__':
221+
main()

0 commit comments

Comments
 (0)