|
3 | 3 |
|
4 | 4 |
|
5 | 5 | def proxy_to_dataframe(proxy_model): |
| 6 | + """Convert Proxy Model to pandas DataFrame.""" |
6 | 7 | rows = proxy_model.rowCount() |
7 | 8 | cols = proxy_model.columnCount() |
8 | 9 |
|
| 10 | + if rows <= 1: # <=1 due to "New row..." in every table |
| 11 | + return pd.DataFrame() |
| 12 | + |
9 | 13 | headers = [proxy_model.headerData(c, Qt.Horizontal) for c in range(cols)] |
10 | | - data = [] |
11 | 14 |
|
| 15 | + # Pre-allocate list of lists (faster than dicts) |
| 16 | + data = [] |
12 | 17 | for r in range(rows - 1): |
13 | | - row = {headers[c]: proxy_model.index(r, c).data() for c in range(cols)} |
14 | | - for key, value in row.items(): |
15 | | - if isinstance(value, str) and value == "": |
16 | | - row[key] = None |
| 18 | + row = [] |
| 19 | + for c in range(cols): |
| 20 | + value = proxy_model.index(r, c).data() |
| 21 | + # Convert empty strings to None |
| 22 | + row.append( |
| 23 | + None if (isinstance(value, str) and value == "") else value |
| 24 | + ) |
17 | 25 | data.append(row) |
| 26 | + |
18 | 27 | if not data: |
19 | 28 | return pd.DataFrame() |
20 | | - if proxy_model.source_model.table_type == "condition": |
21 | | - data = pd.DataFrame(data).set_index("conditionId") |
22 | | - elif proxy_model.source_model.table_type == "observable": |
23 | | - data = pd.DataFrame(data).set_index("observableId") |
24 | | - elif proxy_model.source_model.table_type == "parameter": |
25 | | - data = pd.DataFrame(data).set_index("parameterId") |
26 | | - elif proxy_model.source_model.table_type == "measurement": |
27 | | - # turn measurement and time to float |
28 | | - data = pd.DataFrame(data) |
29 | | - data["measurement"] = data["measurement"].astype(float) |
30 | | - data["time"] = data["time"].astype(float) |
31 | | - elif proxy_model.source_model.table_type == "simulation": |
32 | | - # turn simulation and time to float |
33 | | - data = pd.DataFrame(data) |
34 | | - data["simulation"] = data["simulation"].astype(float) |
35 | | - data["time"] = data["time"].astype(float) |
36 | | - elif proxy_model.source_model.table_type == "visualization": |
37 | | - data = pd.DataFrame(data) |
38 | | - if "xOffset" in data.columns: |
39 | | - data["xOffset"] = data["xOffset"].astype(float) |
40 | | - if "yOffset" in data.columns: |
41 | | - data["yOffset"] = data["yOffset"].astype(float) |
42 | | - else: |
43 | | - data = pd.DataFrame(data) |
44 | | - |
45 | | - return data |
| 29 | + |
| 30 | + # Create DataFrame in one shot |
| 31 | + df = pd.DataFrame(data, columns=headers) |
| 32 | + |
| 33 | + # Apply type-specific transformations |
| 34 | + table_type = proxy_model.source_model.table_type |
| 35 | + |
| 36 | + if table_type == "condition": |
| 37 | + df = df.set_index("conditionId") |
| 38 | + elif table_type == "observable": |
| 39 | + df = df.set_index("observableId") |
| 40 | + elif table_type == "parameter": |
| 41 | + df = df.set_index("parameterId") |
| 42 | + elif table_type == "measurement": |
| 43 | + # Use pd.to_numeric with errors='coerce' for robust conversion |
| 44 | + df["measurement"] = pd.to_numeric(df["measurement"], errors="coerce") |
| 45 | + df["time"] = pd.to_numeric(df["time"], errors="coerce") |
| 46 | + elif table_type == "simulation": |
| 47 | + df["simulation"] = pd.to_numeric(df["simulation"], errors="coerce") |
| 48 | + df["time"] = pd.to_numeric(df["time"], errors="coerce") |
| 49 | + elif table_type == "visualization": |
| 50 | + if "xOffset" in df.columns: |
| 51 | + df["xOffset"] = pd.to_numeric(df["xOffset"], errors="coerce") |
| 52 | + if "yOffset" in df.columns: |
| 53 | + df["yOffset"] = pd.to_numeric(df["yOffset"], errors="coerce") |
| 54 | + |
| 55 | + return df |
0 commit comments