Spaces:
Sleeping
Sleeping
Commit
·
68c0258
1
Parent(s):
435a716
Added the DOWNLOAD menu in the Time Series Plot section
Browse files- em_trame.py +175 -13
- pages/__pycache__/qlbm_page.cpython-310.pyc +0 -0
em_trame.py
CHANGED
|
@@ -697,7 +697,9 @@ def export_qpu_timeseries_csv():
|
|
| 697 |
temp_path = tmp.name
|
| 698 |
|
| 699 |
content = Path(temp_path).read_bytes()
|
| 700 |
-
|
|
|
|
|
|
|
| 701 |
Path(temp_path).unlink()
|
| 702 |
|
| 703 |
state.export_status_message = f"Exported QPU CSV to {filename}"
|
|
@@ -724,7 +726,9 @@ def export_qpu_timeseries_png():
|
|
| 724 |
fig.write_image(temp_path, scale=2, width=900, height=660)
|
| 725 |
|
| 726 |
content = Path(temp_path).read_bytes()
|
| 727 |
-
|
|
|
|
|
|
|
| 728 |
Path(temp_path).unlink()
|
| 729 |
|
| 730 |
state.export_status_message = f"Exported QPU PNG to {filename}"
|
|
@@ -755,7 +759,9 @@ def export_qpu_timeseries_html():
|
|
| 755 |
pio.write_html(fig, file=temp_path, include_plotlyjs="cdn", full_html=True)
|
| 756 |
|
| 757 |
content = Path(temp_path).read_bytes()
|
| 758 |
-
|
|
|
|
|
|
|
| 759 |
Path(temp_path).unlink()
|
| 760 |
|
| 761 |
state.export_status_message = f"Exported QPU HTML to {filename}"
|
|
@@ -764,6 +770,143 @@ def export_qpu_timeseries_html():
|
|
| 764 |
finally:
|
| 765 |
state.show_export_status = True
|
| 766 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
def setup_surface_plot_data(simulation_data, nx):
|
| 768 |
global data_frames, z_scale, X_grids, Y_grids, surface_clims
|
| 769 |
mask = np.arange(1, nx * nx + 1) % nx != 0
|
|
@@ -1274,7 +1417,7 @@ def _build_sim_timeseries_plotly(field_type: str, positions, nx: int, times, sim
|
|
| 1274 |
return None
|
| 1275 |
|
| 1276 |
def generate_plot():
|
| 1277 |
-
global current_mesh
|
| 1278 |
if not state.simulation_has_run:
|
| 1279 |
return
|
| 1280 |
|
|
@@ -1296,6 +1439,9 @@ def generate_plot():
|
|
| 1296 |
raise ValueError("No valid monitor positions found. Enter (x, y) pairs in [0,1] x [0,1].")
|
| 1297 |
fig = _build_sim_timeseries_plotly(state.timeseries_field, positions, nx, snapshot_times, simulation_data)
|
| 1298 |
if fig is not None:
|
|
|
|
|
|
|
|
|
|
| 1299 |
try:
|
| 1300 |
ctrl.sim_ts_update(fig)
|
| 1301 |
except Exception:
|
|
@@ -2297,7 +2443,10 @@ def export_vtk():
|
|
| 2297 |
with tempfile.NamedTemporaryFile(suffix=".vtp", delete=False) as tmp:
|
| 2298 |
current_mesh.save(tmp.name)
|
| 2299 |
content = Path(tmp.name).read_bytes()
|
| 2300 |
-
|
|
|
|
|
|
|
|
|
|
| 2301 |
Path(tmp.name).unlink() # Clean up
|
| 2302 |
|
| 2303 |
state.export_status_message = f"Exported VTK to {filename}"
|
|
@@ -2345,7 +2494,9 @@ def export_vtk_all_frames():
|
|
| 2345 |
Path(tmp_vtp_path).unlink()
|
| 2346 |
|
| 2347 |
content = Path(temp_zip_path).read_bytes()
|
| 2348 |
-
|
|
|
|
|
|
|
| 2349 |
Path(temp_zip_path).unlink()
|
| 2350 |
|
| 2351 |
state.export_status_message = f"Exported {len(frames)} frames to {zip_filename}"
|
|
@@ -2435,7 +2586,9 @@ def export_mp4():
|
|
| 2435 |
|
| 2436 |
# Read the file content and trigger download
|
| 2437 |
content = Path(temp_path).read_bytes()
|
| 2438 |
-
|
|
|
|
|
|
|
| 2439 |
Path(temp_path).unlink() # Clean up
|
| 2440 |
|
| 2441 |
state.export_status_message = f"Exported MP4 to {filename}"
|
|
@@ -3104,13 +3257,13 @@ with SinglePageLayout(server) as layout:
|
|
| 3104 |
with vuetify3.VCol(cols=7, classes="pa-1 d-flex flex-column"):
|
| 3105 |
# Output Configuration (appears after simulation) – hidden for QPU
|
| 3106 |
with vuetify3.VCard(v_if="simulation_has_run && backend_type !== 'QPU'", classes="mb-1", style="font-size: 0.8rem;"):
|
| 3107 |
-
with vuetify3.VCardSubtitle("Output Configuration", classes="text-subtitle-1 text-primary", style="font-size: 0.9rem; padding: 6px 10px;"):
|
| 3108 |
-
with vuetify3.VCardText(classes="py-1 px-2"):
|
| 3109 |
with vuetify3.VRadioGroup(v_model=("output_type", "Surface Plot"), row=True, density="compact", color="primary"):
|
| 3110 |
-
vuetify3.VRadio(label="Surface", value="Surface Plot")
|
| 3111 |
-
vuetify3.VRadio(label="Time Series", value="Time Series Plot")
|
| 3112 |
with vuetify3.VContainer(v_if="output_type === 'Surface Plot'", classes="pa-0"):
|
| 3113 |
-
vuetify3.VSelect(v_model=("surface_field", "Ez"), items=("surface_field_options", ["Ez", "Hx", "Hy"]), label="Field Component", density="compact", color="primary")
|
| 3114 |
# Replace export format dropdown and individual buttons with a single Export menu
|
| 3115 |
with vuetify3.VMenu(open_on_hover=True, close_on_content_click=True, location="end"):
|
| 3116 |
with vuetify3.Template(v_slot_activator="{ props }"):
|
|
@@ -3122,7 +3275,7 @@ with SinglePageLayout(server) as layout:
|
|
| 3122 |
vuetify3.VDivider()
|
| 3123 |
vuetify3.VListItem(title="Animation (MP4)", prepend_icon="mdi-movie", click=export_mp4)
|
| 3124 |
with vuetify3.VContainer(v_if="output_type === 'Time Series Plot'", classes="pa-0"):
|
| 3125 |
-
vuetify3.VSelect(v_model=("timeseries_field", "Ez"), items=("timeseries_field_options", ["All", "Ez", "Hx", "Hy"]), label="Field Component", density="compact", color="primary")
|
| 3126 |
vuetify3.VTextarea(
|
| 3127 |
v_model=("timeseries_points", "(0.5, 0.5)"),
|
| 3128 |
label="Monitor Position(s) (x, y) in [0,1]",
|
|
@@ -3130,6 +3283,7 @@ with SinglePageLayout(server) as layout:
|
|
| 3130 |
rows=2,
|
| 3131 |
auto_grow=True,
|
| 3132 |
color="primary",
|
|
|
|
| 3133 |
)
|
| 3134 |
vuetify3.VAlert(
|
| 3135 |
v_if="timeseries_point_info",
|
|
@@ -3140,6 +3294,14 @@ with SinglePageLayout(server) as layout:
|
|
| 3140 |
classes="mt-1",
|
| 3141 |
style="white-space: pre-line;",
|
| 3142 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3143 |
|
| 3144 |
# Main plot area (PyVista) – keep visible for QPU until data replaces it
|
| 3145 |
with vuetify3.VCard(
|
|
|
|
| 697 |
temp_path = tmp.name
|
| 698 |
|
| 699 |
content = Path(temp_path).read_bytes()
|
| 700 |
+
# Encode content as base64 for browser download
|
| 701 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 702 |
+
server.js_call("utils", "download", filename, f"data:text/csv;base64,{content_b64}")
|
| 703 |
Path(temp_path).unlink()
|
| 704 |
|
| 705 |
state.export_status_message = f"Exported QPU CSV to {filename}"
|
|
|
|
| 726 |
fig.write_image(temp_path, scale=2, width=900, height=660)
|
| 727 |
|
| 728 |
content = Path(temp_path).read_bytes()
|
| 729 |
+
# Encode content as base64 for browser download
|
| 730 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 731 |
+
server.js_call("utils", "download", filename, f"data:image/png;base64,{content_b64}")
|
| 732 |
Path(temp_path).unlink()
|
| 733 |
|
| 734 |
state.export_status_message = f"Exported QPU PNG to {filename}"
|
|
|
|
| 759 |
pio.write_html(fig, file=temp_path, include_plotlyjs="cdn", full_html=True)
|
| 760 |
|
| 761 |
content = Path(temp_path).read_bytes()
|
| 762 |
+
# Encode content as base64 for browser download
|
| 763 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 764 |
+
server.js_call("utils", "download", filename, f"data:text/html;base64,{content_b64}")
|
| 765 |
Path(temp_path).unlink()
|
| 766 |
|
| 767 |
state.export_status_message = f"Exported QPU HTML to {filename}"
|
|
|
|
| 770 |
finally:
|
| 771 |
state.show_export_status = True
|
| 772 |
|
| 773 |
+
# --- Cache for Simulator Time Series (for export) ---
|
| 774 |
+
sim_ts_cache = {
|
| 775 |
+
"fig": None,
|
| 776 |
+
"field": None,
|
| 777 |
+
}
|
| 778 |
+
|
| 779 |
+
# --- Export functions for Simulator Time Series ---
|
| 780 |
+
|
| 781 |
+
def export_sim_timeseries_csv():
|
| 782 |
+
"""Export simulator time series data to CSV."""
|
| 783 |
+
try:
|
| 784 |
+
global simulation_data, snapshot_times
|
| 785 |
+
if simulation_data is None or snapshot_times is None:
|
| 786 |
+
raise ValueError("No simulator time series to export.")
|
| 787 |
+
|
| 788 |
+
field = state.timeseries_field or "Ez"
|
| 789 |
+
nx_val = int(state.nx or 0)
|
| 790 |
+
filename = f"sim_timeseries_{field}_nx{nx_val}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
|
| 791 |
+
|
| 792 |
+
# Parse positions from state
|
| 793 |
+
positions = []
|
| 794 |
+
pts_str = state.timeseries_points or "(0.5, 0.5)"
|
| 795 |
+
for m in _SAMPLE_PAIR_RE.finditer(pts_str):
|
| 796 |
+
x_norm, y_norm = float(m.group(1)), float(m.group(2))
|
| 797 |
+
px = int(round(x_norm * (nx_val - 1)))
|
| 798 |
+
py = int(round(y_norm * (nx_val - 1)))
|
| 799 |
+
positions.append((px, py))
|
| 800 |
+
|
| 801 |
+
if not positions:
|
| 802 |
+
positions = [(nx_val // 2, nx_val // 2)]
|
| 803 |
+
|
| 804 |
+
import csv
|
| 805 |
+
with tempfile.NamedTemporaryFile(mode='w', newline='', suffix=".csv", delete=False) as tmp:
|
| 806 |
+
writer = csv.writer(tmp)
|
| 807 |
+
header = ["time_s"] + [f"({px},{py})" for (px, py) in positions]
|
| 808 |
+
writer.writerow(header)
|
| 809 |
+
|
| 810 |
+
times = np.asarray(snapshot_times)
|
| 811 |
+
n_frames = simulation_data.shape[0]
|
| 812 |
+
for i, t in enumerate(times):
|
| 813 |
+
if i >= n_frames:
|
| 814 |
+
break
|
| 815 |
+
row = [t]
|
| 816 |
+
for (px, py) in positions:
|
| 817 |
+
if field == 'Ez':
|
| 818 |
+
val = simulation_data[i, py * nx_val + px]
|
| 819 |
+
elif field == 'Hx':
|
| 820 |
+
gw, gh = nx_val, nx_val - 1
|
| 821 |
+
if 0 <= px < gw and 0 <= py < gh:
|
| 822 |
+
block = simulation_data[i, 2*nx_val*nx_val : 3*nx_val*nx_val-nx_val].reshape(gh, gw)
|
| 823 |
+
val = block[py, px]
|
| 824 |
+
else:
|
| 825 |
+
val = 0.0
|
| 826 |
+
else: # Hy
|
| 827 |
+
mask = np.arange(1, nx_val * nx_val + 1) % nx_val != 0
|
| 828 |
+
raw_block = simulation_data[i, -nx_val*nx_val:]
|
| 829 |
+
gw, gh = nx_val - 1, nx_val
|
| 830 |
+
if 0 <= px < gw and 0 <= py < gh:
|
| 831 |
+
val = raw_block[mask].reshape(nx_val, nx_val - 1)[py, px]
|
| 832 |
+
else:
|
| 833 |
+
val = 0.0
|
| 834 |
+
row.append(val)
|
| 835 |
+
writer.writerow(row)
|
| 836 |
+
temp_path = tmp.name
|
| 837 |
+
|
| 838 |
+
content = Path(temp_path).read_bytes()
|
| 839 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 840 |
+
server.js_call("utils", "download", filename, f"data:text/csv;base64,{content_b64}")
|
| 841 |
+
Path(temp_path).unlink()
|
| 842 |
+
|
| 843 |
+
state.export_status_message = f"Exported Simulator CSV to {filename}"
|
| 844 |
+
except Exception as e:
|
| 845 |
+
state.export_status_message = f"Simulator CSV export failed: {e}"
|
| 846 |
+
finally:
|
| 847 |
+
state.show_export_status = True
|
| 848 |
+
|
| 849 |
+
|
| 850 |
+
def export_sim_timeseries_png():
|
| 851 |
+
"""Export simulator time series Plotly figure as PNG."""
|
| 852 |
+
try:
|
| 853 |
+
fig = sim_ts_cache.get("fig")
|
| 854 |
+
field = state.timeseries_field or "Ez"
|
| 855 |
+
if fig is None:
|
| 856 |
+
raise ValueError("No simulator time series to export.")
|
| 857 |
+
|
| 858 |
+
nx_val = int(state.nx or 0)
|
| 859 |
+
filename = f"sim_timeseries_{field}_nx{nx_val}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
|
| 860 |
+
|
| 861 |
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
|
| 862 |
+
temp_path = tmp.name
|
| 863 |
+
|
| 864 |
+
fig.write_image(temp_path, scale=2, width=900, height=660)
|
| 865 |
+
|
| 866 |
+
content = Path(temp_path).read_bytes()
|
| 867 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 868 |
+
server.js_call("utils", "download", filename, f"data:image/png;base64,{content_b64}")
|
| 869 |
+
Path(temp_path).unlink()
|
| 870 |
+
|
| 871 |
+
state.export_status_message = f"Exported Simulator PNG to {filename}"
|
| 872 |
+
except Exception as e:
|
| 873 |
+
msg = str(e)
|
| 874 |
+
if "kaleido" in msg.lower():
|
| 875 |
+
state.export_status_message = "Simulator PNG export failed: kaleido is not installed. Run `pip install -U kaleido`."
|
| 876 |
+
else:
|
| 877 |
+
state.export_status_message = f"Simulator PNG export failed: {e}"
|
| 878 |
+
finally:
|
| 879 |
+
state.show_export_status = True
|
| 880 |
+
|
| 881 |
+
|
| 882 |
+
def export_sim_timeseries_html():
|
| 883 |
+
"""Export simulator time series Plotly figure as standalone HTML."""
|
| 884 |
+
try:
|
| 885 |
+
fig = sim_ts_cache.get("fig")
|
| 886 |
+
field = state.timeseries_field or "Ez"
|
| 887 |
+
if fig is None:
|
| 888 |
+
raise ValueError("No simulator time series to export.")
|
| 889 |
+
|
| 890 |
+
nx_val = int(state.nx or 0)
|
| 891 |
+
filename = f"sim_timeseries_{field}_nx{nx_val}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html"
|
| 892 |
+
|
| 893 |
+
with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as tmp:
|
| 894 |
+
temp_path = tmp.name
|
| 895 |
+
|
| 896 |
+
pio.write_html(fig, file=temp_path, include_plotlyjs="cdn", full_html=True)
|
| 897 |
+
|
| 898 |
+
content = Path(temp_path).read_bytes()
|
| 899 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 900 |
+
server.js_call("utils", "download", filename, f"data:text/html;base64,{content_b64}")
|
| 901 |
+
Path(temp_path).unlink()
|
| 902 |
+
|
| 903 |
+
state.export_status_message = f"Exported Simulator HTML to {filename}"
|
| 904 |
+
except Exception as e:
|
| 905 |
+
state.export_status_message = f"Simulator HTML export failed: {e}"
|
| 906 |
+
finally:
|
| 907 |
+
state.show_export_status = True
|
| 908 |
+
|
| 909 |
+
|
| 910 |
def setup_surface_plot_data(simulation_data, nx):
|
| 911 |
global data_frames, z_scale, X_grids, Y_grids, surface_clims
|
| 912 |
mask = np.arange(1, nx * nx + 1) % nx != 0
|
|
|
|
| 1417 |
return None
|
| 1418 |
|
| 1419 |
def generate_plot():
|
| 1420 |
+
global current_mesh, sim_ts_cache
|
| 1421 |
if not state.simulation_has_run:
|
| 1422 |
return
|
| 1423 |
|
|
|
|
| 1439 |
raise ValueError("No valid monitor positions found. Enter (x, y) pairs in [0,1] x [0,1].")
|
| 1440 |
fig = _build_sim_timeseries_plotly(state.timeseries_field, positions, nx, snapshot_times, simulation_data)
|
| 1441 |
if fig is not None:
|
| 1442 |
+
# Cache the figure for export
|
| 1443 |
+
sim_ts_cache["fig"] = fig
|
| 1444 |
+
sim_ts_cache["field"] = state.timeseries_field
|
| 1445 |
try:
|
| 1446 |
ctrl.sim_ts_update(fig)
|
| 1447 |
except Exception:
|
|
|
|
| 2443 |
with tempfile.NamedTemporaryFile(suffix=".vtp", delete=False) as tmp:
|
| 2444 |
current_mesh.save(tmp.name)
|
| 2445 |
content = Path(tmp.name).read_bytes()
|
| 2446 |
+
# Encode content as base64 for browser download
|
| 2447 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 2448 |
+
# Trigger browser download via JavaScript
|
| 2449 |
+
server.js_call("utils", "download", filename, f"data:application/octet-stream;base64,{content_b64}")
|
| 2450 |
Path(tmp.name).unlink() # Clean up
|
| 2451 |
|
| 2452 |
state.export_status_message = f"Exported VTK to {filename}"
|
|
|
|
| 2494 |
Path(tmp_vtp_path).unlink()
|
| 2495 |
|
| 2496 |
content = Path(temp_zip_path).read_bytes()
|
| 2497 |
+
# Encode content as base64 for browser download
|
| 2498 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 2499 |
+
server.js_call("utils", "download", zip_filename, f"data:application/zip;base64,{content_b64}")
|
| 2500 |
Path(temp_zip_path).unlink()
|
| 2501 |
|
| 2502 |
state.export_status_message = f"Exported {len(frames)} frames to {zip_filename}"
|
|
|
|
| 2586 |
|
| 2587 |
# Read the file content and trigger download
|
| 2588 |
content = Path(temp_path).read_bytes()
|
| 2589 |
+
# Encode content as base64 for browser download
|
| 2590 |
+
content_b64 = base64.b64encode(content).decode("ascii")
|
| 2591 |
+
server.js_call("utils", "download", filename, f"data:video/mp4;base64,{content_b64}")
|
| 2592 |
Path(temp_path).unlink() # Clean up
|
| 2593 |
|
| 2594 |
state.export_status_message = f"Exported MP4 to {filename}"
|
|
|
|
| 3257 |
with vuetify3.VCol(cols=7, classes="pa-1 d-flex flex-column"):
|
| 3258 |
# Output Configuration (appears after simulation) – hidden for QPU
|
| 3259 |
with vuetify3.VCard(v_if="simulation_has_run && backend_type !== 'QPU'", classes="mb-1", style="font-size: 0.8rem;"):
|
| 3260 |
+
with vuetify3.VCardSubtitle("Output Configuration", classes="text-subtitle-1 text-primary", style="font-size: 0.9rem; padding: 6px 10px; font-weight: 600; color: #1A1A1A;"):
|
| 3261 |
+
with vuetify3.VCardText(classes="py-1 px-2", style="color: #1A1A1A;"):
|
| 3262 |
with vuetify3.VRadioGroup(v_model=("output_type", "Surface Plot"), row=True, density="compact", color="primary"):
|
| 3263 |
+
vuetify3.VRadio(label="Surface", value="Surface Plot", style="font-weight: 500;")
|
| 3264 |
+
vuetify3.VRadio(label="Time Series", value="Time Series Plot", style="font-weight: 500;")
|
| 3265 |
with vuetify3.VContainer(v_if="output_type === 'Surface Plot'", classes="pa-0"):
|
| 3266 |
+
vuetify3.VSelect(v_model=("surface_field", "Ez"), items=("surface_field_options", ["Ez", "Hx", "Hy"]), label="Field Component", density="compact", color="primary", style="font-weight: 500;")
|
| 3267 |
# Replace export format dropdown and individual buttons with a single Export menu
|
| 3268 |
with vuetify3.VMenu(open_on_hover=True, close_on_content_click=True, location="end"):
|
| 3269 |
with vuetify3.Template(v_slot_activator="{ props }"):
|
|
|
|
| 3275 |
vuetify3.VDivider()
|
| 3276 |
vuetify3.VListItem(title="Animation (MP4)", prepend_icon="mdi-movie", click=export_mp4)
|
| 3277 |
with vuetify3.VContainer(v_if="output_type === 'Time Series Plot'", classes="pa-0"):
|
| 3278 |
+
vuetify3.VSelect(v_model=("timeseries_field", "Ez"), items=("timeseries_field_options", ["All", "Ez", "Hx", "Hy"]), label="Field Component", density="compact", color="primary", style="font-weight: 500;")
|
| 3279 |
vuetify3.VTextarea(
|
| 3280 |
v_model=("timeseries_points", "(0.5, 0.5)"),
|
| 3281 |
label="Monitor Position(s) (x, y) in [0,1]",
|
|
|
|
| 3283 |
rows=2,
|
| 3284 |
auto_grow=True,
|
| 3285 |
color="primary",
|
| 3286 |
+
style="font-weight: 500;",
|
| 3287 |
)
|
| 3288 |
vuetify3.VAlert(
|
| 3289 |
v_if="timeseries_point_info",
|
|
|
|
| 3294 |
classes="mt-1",
|
| 3295 |
style="white-space: pre-line;",
|
| 3296 |
)
|
| 3297 |
+
# DOWNLOAD menu for Simulator Time Series
|
| 3298 |
+
with vuetify3.VMenu(open_on_hover=True, close_on_content_click=True, location="end"):
|
| 3299 |
+
with vuetify3.Template(v_slot_activator="{ props }"):
|
| 3300 |
+
vuetify3.VBtn(v_bind="props", text="DOWNLOAD", color="primary", variant="tonal", block=True, classes="mt-1")
|
| 3301 |
+
with vuetify3.VList(density="compact"):
|
| 3302 |
+
vuetify3.VListItem(title="Download CSV", prepend_icon="mdi-download", click=export_sim_timeseries_csv)
|
| 3303 |
+
vuetify3.VListItem(title="Download PNG", prepend_icon="mdi-image", click=export_sim_timeseries_png)
|
| 3304 |
+
vuetify3.VListItem(title="Download HTML", prepend_icon="mdi-file-html", click=export_sim_timeseries_html)
|
| 3305 |
|
| 3306 |
# Main plot area (PyVista) – keep visible for QPU until data replaces it
|
| 3307 |
with vuetify3.VCard(
|
pages/__pycache__/qlbm_page.cpython-310.pyc
CHANGED
|
Binary files a/pages/__pycache__/qlbm_page.cpython-310.pyc and b/pages/__pycache__/qlbm_page.cpython-310.pyc differ
|
|
|