Skip to content

Commit 370bde8

Browse files
committed
Double click on a node opens program info in a new page
1 parent 8683d05 commit 370bde8

File tree

1 file changed

+69
-3
lines changed

1 file changed

+69
-3
lines changed

scripts/visualizer.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
position: absolute;
2727
text-align: left;
2828
width: 400px;
29+
max-width: 90vw;
30+
max-height: 60vh;
31+
overflow: auto;
2932
padding: 10px;
3033
font: 12px sans-serif;
3134
background: #fff;
@@ -35,7 +38,14 @@
3538
box-shadow: 2px 2px 8px #aaa;
3639
z-index: 10;
3740
}
38-
pre { background: #f0f0f0; padding: 6px; border-radius: 4px; }
41+
pre {
42+
background: #f0f0f0;
43+
padding: 6px;
44+
border-radius: 4px;
45+
max-height: 200px;
46+
overflow: auto;
47+
white-space: pre;
48+
}
3949
</style>
4050
</head>
4151
<body>
@@ -95,6 +105,12 @@
95105
hideTooltip(true);
96106
}
97107
108+
function openInNewTab(event, d) {
109+
const url = `/program/${d.id}`;
110+
window.open(url, '_blank');
111+
event.stopPropagation(); // Prevent tooltip from closing
112+
}
113+
98114
function renderGraph(data) {
99115
g.selectAll("*").remove();
100116
const simulation = d3.forceSimulation(data.nodes)
@@ -120,6 +136,7 @@
120136
.attr("fill", d => d.island !== undefined ? d3.schemeCategory10[d.island % 10] : "#888")
121137
.on("mouseover", showTooltip)
122138
.on("click", showTooltipSticky)
139+
.on("dblclick", openInNewTab)
123140
.on("mouseout", hideTooltip)
124141
.call(d3.drag()
125142
.on("start", dragstarted)
@@ -164,7 +181,7 @@
164181
});
165182
166183
function fetchAndRender() {
167-
fetch('/data')
184+
fetch('/api/data')
168185
.then(resp => resp.json())
169186
.then(data => {
170187
const dataStr = JSON.stringify(data);
@@ -189,6 +206,33 @@
189206
</body>
190207
</html>
191208
"""
209+
HTML_TEMPLATE_PROGRAM_PAGE = """
210+
<!DOCTYPE html>
211+
<html lang="en">
212+
<head>
213+
<meta charset="UTF-8">
214+
<title>Program {{ program_data.id }}</title>
215+
<style>
216+
body { font-family: Arial, sans-serif; padding: 20px; }
217+
pre { background: #f0f0f0; padding: 10px; border-radius: 5px; }
218+
</style>
219+
</head>
220+
<body>
221+
<h1>Program ID: {{ program_data.id }}</h1>
222+
<h2>Island: {{ program_data.island }}</h2>
223+
<h3>Generation: {{ program_data.generation }}</h3>
224+
<h3>Parent ID: {{ program_data.parent_id or 'None' }}</h3>
225+
<h3>Metrics:</h3>
226+
<ul>
227+
{% for key, value in program_data.metrics.items() %}
228+
<li><strong>{{ key }}:</strong> {{ value }}</li>
229+
{% endfor %}
230+
</ul>
231+
<h3>Code:</h3>
232+
<pre>{{ program_data.code }}</pre>
233+
</body>
234+
</html>
235+
"""
192236

193237
logger = logging.getLogger("openevolve.visualizer")
194238

@@ -242,19 +286,41 @@ def load_evolution_data(checkpoint_folder):
242286
def index():
243287
return render_template_string(HTML_TEMPLATE)
244288

245-
@app.route('/data')
289+
checkpoint_dir = None # Global variable to store the checkpoint directory
290+
@app.route('/api/data')
246291
def data():
247292
base_folder = os.environ.get('EVOLVE_OUTPUT', 'examples/')
248293
checkpoint = find_latest_checkpoint(base_folder)
249294
if not checkpoint:
250295
logger.info(f"No checkpoints found in {base_folder}")
251296
return jsonify({"nodes": [], "edges": []})
252297

298+
# Memorize checkpoint directory for usage in other routes
299+
global checkpoint_dir
300+
checkpoint_dir = checkpoint
301+
253302
logger.info(f"Loading data from checkpoint: {checkpoint}")
254303
data = load_evolution_data(checkpoint)
255304
logger.debug(f"Data: {data}")
256305
return jsonify(data)
257306

307+
308+
@app.route("/program/<program_id>")
309+
def program_page(program_id):
310+
global checkpoint_dir
311+
if checkpoint_dir is None:
312+
return "No checkpoint loaded", 500
313+
314+
program_path = os.path.join(checkpoint_dir, f"programs/{program_id}.json")
315+
if not os.path.exists(program_path):
316+
return "Program not found", 404
317+
318+
with open(program_path) as f:
319+
program_data = json.load(f)
320+
321+
return render_template_string(HTML_TEMPLATE_PROGRAM_PAGE, program_data=program_data)
322+
323+
258324
if __name__ == '__main__':
259325
import argparse
260326

0 commit comments

Comments
 (0)