Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1171,7 +1171,8 @@ def create_histogram(file_path: str, dataset_path: str, slice_str: str = "",
|
|
| 1171 |
|
| 1172 |
def create_line_plot(file_path: str, dataset_path: str, slice_str: str = "",
|
| 1173 |
title_override: str = "", xlabel_override: str = "", ylabel_override: str = "",
|
| 1174 |
-
x_dataset_path: str = "",
|
|
|
|
| 1175 |
"""
|
| 1176 |
Create line plot for 1D data or time series.
|
| 1177 |
|
|
@@ -1183,6 +1184,7 @@ def create_line_plot(file_path: str, dataset_path: str, slice_str: str = "",
|
|
| 1183 |
xlabel_override: Optional custom x-axis label
|
| 1184 |
ylabel_override: Optional custom y-axis label
|
| 1185 |
x_dataset_path: Optional path to X-axis data (if empty, uses indices)
|
|
|
|
| 1186 |
memory_limit_mb: Memory limit in MB (default: tiered 100/500/2000)
|
| 1187 |
|
| 1188 |
Returns:
|
|
@@ -1284,16 +1286,45 @@ def create_line_plot(file_path: str, dataset_path: str, slice_str: str = "",
|
|
| 1284 |
# Create figure
|
| 1285 |
fig = go.Figure()
|
| 1286 |
|
| 1287 |
-
# Add
|
| 1288 |
fig.add_trace(go.Scatter(
|
| 1289 |
x=x_data,
|
| 1290 |
y=y_data,
|
| 1291 |
mode='lines+markers',
|
| 1292 |
-
name=
|
| 1293 |
-
line=dict(color='steelblue', width=
|
| 1294 |
-
marker=dict(size=
|
|
|
|
| 1295 |
))
|
| 1296 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1297 |
# Set title and labels
|
| 1298 |
title = title_override if title_override else f"Line Plot: {dataset_path}"
|
| 1299 |
xlabel = xlabel_override if xlabel_override else (x_dataset_path if x_dataset_path else "Index")
|
|
@@ -1327,6 +1358,9 @@ def create_line_plot(file_path: str, dataset_path: str, slice_str: str = "",
|
|
| 1327 |
"download_info": "Download the HTML file to view the interactive line plot in your browser"
|
| 1328 |
}
|
| 1329 |
|
|
|
|
|
|
|
|
|
|
| 1330 |
return result, html_path
|
| 1331 |
|
| 1332 |
except Exception as e:
|
|
@@ -1483,8 +1517,8 @@ def create_heatmap(file_path: str, dataset_path: str, slice_str: str = "",
|
|
| 1483 |
|
| 1484 |
|
| 1485 |
def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str,
|
| 1486 |
-
|
| 1487 |
-
xlabel_override: str = "", ylabel_override: str = "",
|
| 1488 |
memory_limit_mb: float = None) -> Tuple[Dict[str, Any], Optional[str]]:
|
| 1489 |
"""
|
| 1490 |
Create scatter plot comparing two variables.
|
|
@@ -1493,7 +1527,8 @@ def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str
|
|
| 1493 |
file_path: Path to the HDF5/NetCDF file
|
| 1494 |
x_dataset_path: Path to X-axis dataset/variable
|
| 1495 |
y_dataset_path: Path to Y-axis dataset/variable
|
| 1496 |
-
|
|
|
|
| 1497 |
title_override: Optional custom title
|
| 1498 |
xlabel_override: Optional custom x-axis label
|
| 1499 |
ylabel_override: Optional custom y-axis label
|
|
@@ -1528,8 +1563,8 @@ def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str
|
|
| 1528 |
x_var = f.variables[x_dataset_path]
|
| 1529 |
y_var = f.variables[y_dataset_path]
|
| 1530 |
|
| 1531 |
-
# Check memory safety for
|
| 1532 |
-
x_safety = check_memory_safety(x_var.shape, x_var.dtype,
|
| 1533 |
if not x_safety["safe"]:
|
| 1534 |
error_result = {
|
| 1535 |
"error": f"X data: {x_safety['error']}",
|
|
@@ -1537,10 +1572,11 @@ def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str
|
|
| 1537 |
"status": "failed"
|
| 1538 |
}
|
| 1539 |
if "suggested_slice" in x_safety:
|
| 1540 |
-
error_result["
|
| 1541 |
return error_result, None
|
| 1542 |
|
| 1543 |
-
|
|
|
|
| 1544 |
if not y_safety["safe"]:
|
| 1545 |
error_result = {
|
| 1546 |
"error": f"Y data: {y_safety['error']}",
|
|
@@ -1548,16 +1584,21 @@ def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str
|
|
| 1548 |
"status": "failed"
|
| 1549 |
}
|
| 1550 |
if "suggested_slice" in y_safety:
|
| 1551 |
-
error_result["
|
| 1552 |
return error_result, None
|
| 1553 |
|
| 1554 |
-
# Read data
|
| 1555 |
-
if
|
| 1556 |
-
|
| 1557 |
-
x_data = x_var[
|
| 1558 |
-
y_data = y_var[idx]
|
| 1559 |
else:
|
| 1560 |
x_data = x_var[:]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1561 |
y_data = y_var[:]
|
| 1562 |
|
| 1563 |
# Convert to numpy and flatten
|
|
@@ -1572,7 +1613,10 @@ def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str
|
|
| 1572 |
# Check lengths match
|
| 1573 |
if len(x_data) != len(y_data):
|
| 1574 |
return {
|
| 1575 |
-
"error": f"X and Y data length mismatch: {len(x_data)} vs {len(y_data)}",
|
|
|
|
|
|
|
|
|
|
| 1576 |
"status": "failed"
|
| 1577 |
}, None
|
| 1578 |
|
|
@@ -2137,6 +2181,13 @@ def build_mcp_tools():
|
|
| 2137 |
value="",
|
| 2138 |
info="Path to X-axis data (if empty, uses indices)"
|
| 2139 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2140 |
gr.Number(
|
| 2141 |
label="Memory Limit (MB) - optional",
|
| 2142 |
value=None,
|
|
@@ -2235,10 +2286,16 @@ def build_mcp_tools():
|
|
| 2235 |
info="Path to Y-axis dataset/variable"
|
| 2236 |
),
|
| 2237 |
gr.Textbox(
|
| 2238 |
-
label="Slice (optional)",
|
| 2239 |
-
placeholder="0
|
| 2240 |
value="",
|
| 2241 |
-
info="Numpy-style slice
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2242 |
),
|
| 2243 |
gr.Textbox(
|
| 2244 |
label="Title (optional)",
|
|
|
|
| 1171 |
|
| 1172 |
def create_line_plot(file_path: str, dataset_path: str, slice_str: str = "",
|
| 1173 |
title_override: str = "", xlabel_override: str = "", ylabel_override: str = "",
|
| 1174 |
+
x_dataset_path: str = "", moving_avg_window: int = 0,
|
| 1175 |
+
memory_limit_mb: float = None) -> Tuple[Dict[str, Any], Optional[str]]:
|
| 1176 |
"""
|
| 1177 |
Create line plot for 1D data or time series.
|
| 1178 |
|
|
|
|
| 1184 |
xlabel_override: Optional custom x-axis label
|
| 1185 |
ylabel_override: Optional custom y-axis label
|
| 1186 |
x_dataset_path: Optional path to X-axis data (if empty, uses indices)
|
| 1187 |
+
moving_avg_window: Window size for moving average (0 or 1 = no smoothing, 2-1000 = apply smoothing)
|
| 1188 |
memory_limit_mb: Memory limit in MB (default: tiered 100/500/2000)
|
| 1189 |
|
| 1190 |
Returns:
|
|
|
|
| 1286 |
# Create figure
|
| 1287 |
fig = go.Figure()
|
| 1288 |
|
| 1289 |
+
# Add raw data trace
|
| 1290 |
fig.add_trace(go.Scatter(
|
| 1291 |
x=x_data,
|
| 1292 |
y=y_data,
|
| 1293 |
mode='lines+markers',
|
| 1294 |
+
name='Raw Data',
|
| 1295 |
+
line=dict(color='steelblue', width=1),
|
| 1296 |
+
marker=dict(size=3),
|
| 1297 |
+
opacity=0.7
|
| 1298 |
))
|
| 1299 |
|
| 1300 |
+
# Add moving average if requested
|
| 1301 |
+
smoothed_info = None
|
| 1302 |
+
if moving_avg_window and moving_avg_window > 1:
|
| 1303 |
+
# Validate window size
|
| 1304 |
+
if moving_avg_window > len(y_data):
|
| 1305 |
+
smoothed_info = f"Moving average window ({moving_avg_window}) larger than data length ({len(y_data)}), skipping smoothing"
|
| 1306 |
+
else:
|
| 1307 |
+
# Calculate moving average using convolution
|
| 1308 |
+
window = np.ones(moving_avg_window) / moving_avg_window
|
| 1309 |
+
y_smooth = np.convolve(y_data, window, mode='valid')
|
| 1310 |
+
|
| 1311 |
+
# Adjust X data to match smoothed Y length
|
| 1312 |
+
# 'valid' mode reduces length by (window_size - 1)
|
| 1313 |
+
offset = (moving_avg_window - 1) // 2
|
| 1314 |
+
x_smooth = x_data[offset:offset + len(y_smooth)]
|
| 1315 |
+
|
| 1316 |
+
# Add smoothed trace
|
| 1317 |
+
fig.add_trace(go.Scatter(
|
| 1318 |
+
x=x_smooth,
|
| 1319 |
+
y=y_smooth,
|
| 1320 |
+
mode='lines',
|
| 1321 |
+
name=f'Moving Avg (n={moving_avg_window})',
|
| 1322 |
+
line=dict(color='red', width=2),
|
| 1323 |
+
opacity=0.9
|
| 1324 |
+
))
|
| 1325 |
+
|
| 1326 |
+
smoothed_info = f"Applied moving average with window size {moving_avg_window}"
|
| 1327 |
+
|
| 1328 |
# Set title and labels
|
| 1329 |
title = title_override if title_override else f"Line Plot: {dataset_path}"
|
| 1330 |
xlabel = xlabel_override if xlabel_override else (x_dataset_path if x_dataset_path else "Index")
|
|
|
|
| 1358 |
"download_info": "Download the HTML file to view the interactive line plot in your browser"
|
| 1359 |
}
|
| 1360 |
|
| 1361 |
+
if smoothed_info:
|
| 1362 |
+
result["smoothing"] = smoothed_info
|
| 1363 |
+
|
| 1364 |
return result, html_path
|
| 1365 |
|
| 1366 |
except Exception as e:
|
|
|
|
| 1517 |
|
| 1518 |
|
| 1519 |
def create_scatter_plot(file_path: str, x_dataset_path: str, y_dataset_path: str,
|
| 1520 |
+
x_slice_str: str = "", y_slice_str: str = "",
|
| 1521 |
+
title_override: str = "", xlabel_override: str = "", ylabel_override: str = "",
|
| 1522 |
memory_limit_mb: float = None) -> Tuple[Dict[str, Any], Optional[str]]:
|
| 1523 |
"""
|
| 1524 |
Create scatter plot comparing two variables.
|
|
|
|
| 1527 |
file_path: Path to the HDF5/NetCDF file
|
| 1528 |
x_dataset_path: Path to X-axis dataset/variable
|
| 1529 |
y_dataset_path: Path to Y-axis dataset/variable
|
| 1530 |
+
x_slice_str: Optional numpy-style slice for X data
|
| 1531 |
+
y_slice_str: Optional numpy-style slice for Y data
|
| 1532 |
title_override: Optional custom title
|
| 1533 |
xlabel_override: Optional custom x-axis label
|
| 1534 |
ylabel_override: Optional custom y-axis label
|
|
|
|
| 1563 |
x_var = f.variables[x_dataset_path]
|
| 1564 |
y_var = f.variables[y_dataset_path]
|
| 1565 |
|
| 1566 |
+
# Check memory safety for X
|
| 1567 |
+
x_safety = check_memory_safety(x_var.shape, x_var.dtype, x_slice_str, memory_limit_mb)
|
| 1568 |
if not x_safety["safe"]:
|
| 1569 |
error_result = {
|
| 1570 |
"error": f"X data: {x_safety['error']}",
|
|
|
|
| 1572 |
"status": "failed"
|
| 1573 |
}
|
| 1574 |
if "suggested_slice" in x_safety:
|
| 1575 |
+
error_result["suggested_slice_x"] = x_safety["suggested_slice"]
|
| 1576 |
return error_result, None
|
| 1577 |
|
| 1578 |
+
# Check memory safety for Y
|
| 1579 |
+
y_safety = check_memory_safety(y_var.shape, y_var.dtype, y_slice_str, memory_limit_mb)
|
| 1580 |
if not y_safety["safe"]:
|
| 1581 |
error_result = {
|
| 1582 |
"error": f"Y data: {y_safety['error']}",
|
|
|
|
| 1584 |
"status": "failed"
|
| 1585 |
}
|
| 1586 |
if "suggested_slice" in y_safety:
|
| 1587 |
+
error_result["suggested_slice_y"] = y_safety["suggested_slice"]
|
| 1588 |
return error_result, None
|
| 1589 |
|
| 1590 |
+
# Read X data
|
| 1591 |
+
if x_slice_str and x_slice_str.strip():
|
| 1592 |
+
x_idx = parse_slice(x_slice_str)
|
| 1593 |
+
x_data = x_var[x_idx]
|
|
|
|
| 1594 |
else:
|
| 1595 |
x_data = x_var[:]
|
| 1596 |
+
|
| 1597 |
+
# Read Y data
|
| 1598 |
+
if y_slice_str and y_slice_str.strip():
|
| 1599 |
+
y_idx = parse_slice(y_slice_str)
|
| 1600 |
+
y_data = y_var[y_idx]
|
| 1601 |
+
else:
|
| 1602 |
y_data = y_var[:]
|
| 1603 |
|
| 1604 |
# Convert to numpy and flatten
|
|
|
|
| 1613 |
# Check lengths match
|
| 1614 |
if len(x_data) != len(y_data):
|
| 1615 |
return {
|
| 1616 |
+
"error": f"X and Y data length mismatch after slicing: {len(x_data)} vs {len(y_data)}",
|
| 1617 |
+
"x_slice": x_slice_str if x_slice_str else "no slice",
|
| 1618 |
+
"y_slice": y_slice_str if y_slice_str else "no slice",
|
| 1619 |
+
"suggestion": "Adjust slices to produce equal-length arrays",
|
| 1620 |
"status": "failed"
|
| 1621 |
}, None
|
| 1622 |
|
|
|
|
| 2181 |
value="",
|
| 2182 |
info="Path to X-axis data (if empty, uses indices)"
|
| 2183 |
),
|
| 2184 |
+
gr.Number(
|
| 2185 |
+
label="Moving Average Window (optional)",
|
| 2186 |
+
value=0,
|
| 2187 |
+
minimum=0,
|
| 2188 |
+
maximum=1000,
|
| 2189 |
+
info="Window size for smoothing (0 or 1 = no smoothing, 2-1000 = apply moving average)"
|
| 2190 |
+
),
|
| 2191 |
gr.Number(
|
| 2192 |
label="Memory Limit (MB) - optional",
|
| 2193 |
value=None,
|
|
|
|
| 2286 |
info="Path to Y-axis dataset/variable"
|
| 2287 |
),
|
| 2288 |
gr.Textbox(
|
| 2289 |
+
label="X Slice (optional)",
|
| 2290 |
+
placeholder="0, :, :",
|
| 2291 |
value="",
|
| 2292 |
+
info="Numpy-style slice for X data (can differ from Y slice)"
|
| 2293 |
+
),
|
| 2294 |
+
gr.Textbox(
|
| 2295 |
+
label="Y Slice (optional)",
|
| 2296 |
+
placeholder="1, :, :",
|
| 2297 |
+
value="",
|
| 2298 |
+
info="Numpy-style slice for Y data (can differ from X slice)"
|
| 2299 |
),
|
| 2300 |
gr.Textbox(
|
| 2301 |
label="Title (optional)",
|