From 8691b9c8da3a47b37206c49cb2c0ce9ddb45cb1a Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Wed, 6 Aug 2025 21:19:58 -0400 Subject: [PATCH 1/4] only share x if there are only scopes or only spectra --- src/backend.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend.py b/src/backend.py index e6ba6e3c..b1731b27 100644 --- a/src/backend.py +++ b/src/backend.py @@ -264,10 +264,13 @@ def run_pathsim(): # extra work is needed since spectra and scopes don't share the same x axis csv_payload = make_csv_payload(scopes) + # Share x only if there are only scopes or only spectra + shared_x = len(scopes) * len(spectra) == 0 + fig = make_subplots( rows=len(scopes) + len(spectra), cols=1, - shared_xaxes=False, + shared_xaxes=shared_x, subplot_titles=[scope.label for scope in scopes] + [spec.label for spec in spectra], vertical_spacing=0.2, From 8eb89a3bfc252a942ca5910419701feee32d3cdb Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Wed, 6 Aug 2025 21:26:41 -0400 Subject: [PATCH 2/4] fixed graph + export as HTML --- src/backend.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backend.py b/src/backend.py index b1731b27..b09c4dc3 100644 --- a/src/backend.py +++ b/src/backend.py @@ -273,7 +273,7 @@ def run_pathsim(): shared_xaxes=shared_x, subplot_titles=[scope.label for scope in scopes] + [spec.label for spec in spectra], - vertical_spacing=0.2, + vertical_spacing=0.1, ) # make scope plots @@ -305,16 +305,18 @@ def run_pathsim(): fig.update_xaxes(title_text="Frequency", row=len(scopes) + i + 1, col=1) fig.update_layout( - height=400 * (len(scopes) + len(spectra)), hovermode="x unified" + height=600 * (len(scopes) + len(spectra)), hovermode="x unified" ) # Convert plot to JSON plot_data = plotly_json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) + plot_html = fig.to_html() return jsonify( { "success": True, "plot": plot_data, + "html": plot_html, "csv_data": csv_payload, "message": "Pathsim simulation completed successfully", } From 969f989a277ff42ee602599c648caf1e82e1297b Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Wed, 6 Aug 2025 21:31:56 -0400 Subject: [PATCH 3/4] export to html --- src/App.jsx | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/App.jsx b/src/App.jsx index 34f15f30..7bdebf66 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -44,6 +44,7 @@ const DnDFlow = () => { const [copyFeedback, setCopyFeedback] = useState(''); const ref = useRef(null); const [csvData, setCsvData] = useState(null); + const [htmlData, setHtmlData] = useState(null); const reactFlowWrapper = useRef(null); // const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); // const [edges, setEdges, onEdgesChange] = useEdgesState([]); @@ -481,6 +482,39 @@ const DnDFlow = () => { } }; + const downloadHtml = async () => { + const blob = new Blob([htmlData], { type: "text/html" }); + const filename = `simulation_${new Date().toISOString().replace(/[:.]/g, "-")}.html`; + + try { + if ("showSaveFilePicker" in window) { + const options = { + suggestedName: filename, + types: [{ + description: "HTML File", + accept: { "text/html": [".html"] } + }] + }; + + const handle = await window.showSaveFilePicker(options); + const writable = await handle.createWritable(); + await writable.write(blob); + await writable.close(); + } else { + throw new Error("showSaveFilePicker not supported"); + } + } catch (err) { + console.warn("Falling back to automatic download:", err); + const a = document.createElement("a"); + a.href = URL.createObjectURL(blob); + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(a.href); + } + }; + // Allows user to save to python script @@ -581,6 +615,7 @@ const DnDFlow = () => { // Store results and switch to results tab setSimulationResults(result.plot); setCsvData(result.csv_data); + setHtmlData(result.html); setActiveTab('results'); alert('Pathsim simulation completed successfully! Check the Results tab.'); } else { @@ -1664,6 +1699,19 @@ const DnDFlow = () => { {simulationResults ? ( <>
+