| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>D3 Python Visualizer</title> |
| <link rel="stylesheet" href="/static/style.css"> |
| <script src="https://d3js.org/d3.v7.min.js"></script> |
| </head> |
| <body> |
| <h2>🐍 Python Visualizer with D3.js</h2> |
|
|
| <form method="post" action="/run"> |
| <textarea name="code" rows="10" cols="70" placeholder="Enter Python code here...">{{ code or '' }}</textarea><br> |
| <button type="submit">Run Code</button> |
| </form> |
|
|
| {% if output %} |
| <h3>Output:</h3> |
| <pre>{{ output }}</pre> |
| {% endif %} |
|
|
| <div id="viz"></div> |
|
|
| <script> |
| const traceData = {{ trace_json | safe if trace_json else '[]' }}; |
| if (traceData.length > 0) { |
| const width = 700, height = 400; |
| const svg = d3.select("#viz") |
| .append("svg") |
| .attr("width", width) |
| .attr("height", height) |
| .style("background", "#f8f8f8") |
| .style("border-radius", "10px"); |
| |
| let currentStep = 0; |
| |
| const frameGroup = svg.append("g").attr("transform", "translate(50,80)"); |
| |
| function renderStep(step) { |
| frameGroup.selectAll("*").remove(); |
| |
| const stepData = traceData[step]; |
| if (stepData.error) { |
| frameGroup.append("text") |
| .text("Error: " + stepData.error) |
| .attr("fill", "red") |
| .attr("x", 50) |
| .attr("y", 20); |
| return; |
| } |
| |
| frameGroup.append("text") |
| .text("Line: " + stepData.line) |
| .attr("x", 0) |
| .attr("y", -30) |
| .attr("font-weight", "bold"); |
| |
| const vars = Object.entries(stepData.locals); |
| vars.forEach((v, i) => { |
| const [name, val] = v; |
| const boxY = i * 50; |
| frameGroup.append("rect") |
| .attr("x", 0) |
| .attr("y", boxY) |
| .attr("width", 200) |
| .attr("height", 40) |
| .attr("fill", "#fff") |
| .attr("stroke", "#000"); |
| |
| frameGroup.append("text") |
| .text(name + " = " + val) |
| .attr("x", 10) |
| .attr("y", boxY + 25) |
| .attr("font-family", "monospace"); |
| }); |
| } |
| |
| function addButtons() { |
| const controls = d3.select("body").append("div").attr("id", "controls"); |
| controls.append("button").text("◀ Prev").on("click", () => { |
| if (currentStep > 0) { currentStep--; renderStep(currentStep); } |
| }); |
| controls.append("button").text("▶ Next").on("click", () => { |
| if (currentStep < traceData.length - 1) { currentStep++; renderStep(currentStep); } |
| }); |
| controls.append("span") |
| .text(" Step " + (currentStep+1) + " of " + traceData.length) |
| .attr("id", "stepInfo"); |
| } |
| |
| addButtons(); |
| renderStep(0); |
| } |
| </script> |
| </body> |
| </html> |
|
|
|
|