I am trying to build a GUI using html and javascript. The idea is to receive a file and then do some processing, resulting in a 2d plot and a 3d interactive plot. The 2d plot is displayed correctly, however, the 3d interactive plotly does not appear, instead a blank box appears in its place. I know the 3d plot is correct since when I write it to html using '''fig_plotly.write_html(html_filename, auto_open=True)''' it shows the correct interactive plot. Below is all my code, including python code, htlm, javascript and css. Additionally, you can find a screenshot of the webpage.screen shot
''' #python code app = Flask(name)
def process_dicom(file_path, net_path):
V = # 3d image
net = # my model
slices = []
fig, axes = plt.subplots(2, 2, figsize=(10, 10))
axes[0, 0].imshow(B_2CH, cmap='gray', extent=extent_2CH, origin='lower')
for line, plane_id in zip(intersections_2D_2CH, plane_ids_2CH):
if len(line) == 0:
continue
axes[0, 0].plot(line[:, 0], line[:, 1], plane_color[plane_id], linewidth=2, label = plane_id)
axes[0, 0].set_title('2-chamber')
axes[0,0].legend()
# rest of plot
plt.tight_layout()
# saving figure into memory
buf = io.BytesIO()
plt.savefig(buf, format = 'png')
buf.seek(0)
img = Image.open(buf)
img_byte_array = io.BytesIO()
img.save(img_byte_array, format='PNG')
img_byte_array.seek(0)
plot_2D = "data:image/png;base64," + base64.b64encode(img_byte_array.read()).decode('utf-8')
plt.close(fig)
fig_plotly = go.Figure()
fig_plotly.add_trace(go.Surface(
x=coords_3D_2CH[0], y=coords_3D_2CH[1], z=coords_3D_2CH[2],
surfacecolor=B_2CH, colorscale="gray", opacity=0.7, showscale=False
))
for line in intersections_3D_2CH:
fig_plotly.add_trace(go.Scatter3d(
x=line[:, 0], y=line[:, 1], z=line[:, 2], mode="lines",
line=dict(color="red", width=5)
))
html_filename = 'first_figure.html'
fig_plotly.write_html(html_filename, auto_open=True)
with open(html_filename, 'r', encoding='utf-8') as f:
plot_3D_html = f.read()
return [plot_2D], plot_3D_html
@app.route('/')
def index():
return render_template('index.html')
NET_PATH = "./models/model.pth"
# flask route to handle DICOM uploads
@app.route('/upload', methods=['POST'])
def upload_file():
if 'dicom_file' not in request.files:
return jsonify({'error': 'No file uploaded'}), 400
file = request.files['dicom_file']
file_path = f"./uploads/{file.filename}"
file.save(file_path)
# Process the DICOM file
plot_2D, plot_3D_html = process_dicom(file_path, NET_PATH)
return jsonify({'plot_2D': plot_2D, 'plot_3D': plot_3D_html})
if __name__ == '__main__':
app.run(debug=True)
'''
'''
html code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DICOM Image Viewer</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
<script src=".min.js"></script>
</head>
<body>
<header>
<h1> My Website </h1>
<p> Upload a 3D image.</p>
</header>
<section id="upload-section">
<form id="uploadForm" enctype="multipart/form-data">
<input type="file" id="dicomFile" name="dicom_file" accept=".dcm">
<button type="submit">Upload</button>
</form>
<div id="loading" class="hidden">
<p>Processing...</p>
</div>
</section>
<section id="plot2D-section">
<h2>2D Slice</h2>
<div id="plot2DContainer"></div>
</section>
<section id="plot3D-section">
<h2>Interactive 3D Plot</h2>
<div id="plot3DContainer" style="width: 100%; height: 600px;"></div>
</section>
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>
'''
'''
javascript
document.getElementById('uploadForm').addEventListener('submit', async function (event) {
event.preventDefault();
const formData = new FormData();
const dicomFile = document.getElementById('dicomFile').files[0];
formData.append('dicom_file', dicomFile);
document.getElementById('loading').style.display = 'block';
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData,
});
document.getElementById('loading').style.display = 'none';
const data = await response.json();
// render 2D plot
if (data.plot_2D) {
const container2D = document.getElementById('plot2DContainer');
container2D.innerHTML = '';
const img2D = document.createElement('img');
img2D.src = data.plot_2D;
img2D.style.width = "100%";
container2D.appendChild(img2D);
}
// 3D plot, embed the returned HTML into an iframe
if (data.plot_3D_html) {
const container3D = document.getElementById('plot3DContainer');
container3D.innerHTML = '';
// iframe and set its srcdoc to the returned HTML content
const iframe = document.createElement('iframe');
iframe.style.width = "100%";
iframe.style.height = "100%";
iframe.style.border = "none";
iframe.srcdoc = data.plot_3D_html;
container3D.appendChild(iframe);
}
} catch (error) {
document.getElementById('loading').style.display = 'none';
alert('Error processing the file.');
console.error(error);
}
});
'''
'''
css file
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
text-align: center;
background-color: #f8f9fa;
}
header {
background-color: #007bff;
color: white;
padding: 20px;
}
#upload-section {
margin: 20px;
}
#uploadForm input[type="file"] {
padding: 10px;
}
#uploadForm button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
}
#plot2DContainer img {
width: 90%;
max-width: 600px;
margin: 10px;
}
#plot3DContainer {
width: 90%;
max-width: 800px;
height: 600px;
margin: auto;
border: 1px solid #ccc;
}
'''