Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
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([]);
Expand All @@ -58,7 +59,7 @@
}, []);

const onDragStart = (event, nodeType) => {
setType(nodeType);

Check failure on line 62 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

'setType' is not defined

Check failure on line 62 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

'setType' is not defined
event.dataTransfer.setData('text/plain', nodeType);
event.dataTransfer.effectAllowed = 'move';
};
Expand Down Expand Up @@ -215,7 +216,7 @@
setNodes((nds) => [...nds, newNode]);
setNodeCounter((count) => count + 1);
},
[screenToFlowPosition, type, nodeCounter, fetchDefaultValues, setDefaultValues, setNodes, setNodeCounter],

Check warning on line 219 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useCallback has an unnecessary dependency: 'setDefaultValues'. Either exclude it or remove the dependency array

Check warning on line 219 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useCallback has an unnecessary dependency: 'setDefaultValues'. Either exclude it or remove the dependency array
);

// Function to save a graph to computer with "Save As" dialog
Expand Down Expand Up @@ -481,6 +482,39 @@
}
};

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
Expand Down Expand Up @@ -581,6 +615,7 @@
// 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 {
Expand Down Expand Up @@ -897,7 +932,7 @@
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [selectedEdge, selectedNode, copiedNode, duplicateNode, setCopyFeedback]);

Check warning on line 935 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.10)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

Check warning on line 935 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test (20.x, 3.11)

React Hook useEffect has missing dependencies: 'deleteSelectedEdge' and 'deleteSelectedNode'. Either include them or remove the dependency array

return (
<div style={{ width: '100vw', height: '100vh', display: 'flex', flexDirection: 'column' }}>
Expand Down Expand Up @@ -1664,6 +1699,19 @@
{simulationResults ? (
<>
<div style={{ textAlign: 'right', padding: '0 20px 10px 20px' }}>
<button
style={{
backgroundColor: '#78A083',
color: 'white',
border: 'none',
borderRadius: 5,
cursor: 'pointer',
marginRight: '10px',
}}
onClick={downloadHtml}
>
Download HTML
</button>
<button
style={{
backgroundColor: '#78A083',
Expand Down
15 changes: 11 additions & 4 deletions src/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,18 @@ 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
n_rows = len(scopes) + len(spectra)
absolute_vertical_spacing = 0.05
relative_vertical_spacing = absolute_vertical_spacing / n_rows
fig = make_subplots(
rows=len(scopes) + len(spectra),
rows=n_rows,
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,
vertical_spacing=relative_vertical_spacing,
)

# make scope plots
Expand Down Expand Up @@ -302,16 +307,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=500 * (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",
}
Expand Down
Loading