| | <!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> |
| |
|
| |
|