Commit ·
8df11ed
1
Parent(s): 61c08f7
Fix score name typo: RM/RM+ -> RW/RW+ (Random-Walk potential)
Browse filesRM/RM+ were mislabeled as RosettaMembrane; they are the Random-Walk
(RW) / RWplus statistical potential. Rename columns, API/model fields,
frontend table headers, and docs accordingly. Rosetta and RMSD unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend/app/protein/api/routes/protein.py +2 -2
- backend/app/protein/data_loader.py +2 -2
- backend/app/protein/models.py +2 -2
- backend/app/protein/tsv_loader.py +7 -7
- backend/assets/MuSProt_documentation.md +4 -4
- backend/scripts/generate_node_lookup.py +2 -2
- frontend/src/components/datasets/protein/DataTable.tsx +5 -5
- frontend/src/types/protein.ts +2 -2
backend/app/protein/api/routes/protein.py
CHANGED
|
@@ -136,8 +136,8 @@ async def get_data(filters: FilterParams):
|
|
| 136 |
delta_rosetta=_safe_float(getattr(row, "delta_Rosetta", None)),
|
| 137 |
delta_foldx=_safe_float(getattr(row, "delta_FoldX", None)),
|
| 138 |
delta_evoef2=_safe_float(getattr(row, "delta_EvoEF2", None)),
|
| 139 |
-
|
| 140 |
-
|
| 141 |
state_id_b=getattr(row, "state_id_B", None) or None,
|
| 142 |
state_fidelity=getattr(row, "state_fidelity", None) or None,
|
| 143 |
avg_sim=getattr(row, "avg_sim", None) or None,
|
|
|
|
| 136 |
delta_rosetta=_safe_float(getattr(row, "delta_Rosetta", None)),
|
| 137 |
delta_foldx=_safe_float(getattr(row, "delta_FoldX", None)),
|
| 138 |
delta_evoef2=_safe_float(getattr(row, "delta_EvoEF2", None)),
|
| 139 |
+
delta_rw=_safe_float(getattr(row, "delta_RW", None)),
|
| 140 |
+
delta_rw_plus=_safe_float(getattr(row, "delta_RW_plus", None)),
|
| 141 |
state_id_b=getattr(row, "state_id_B", None) or None,
|
| 142 |
state_fidelity=getattr(row, "state_fidelity", None) or None,
|
| 143 |
avg_sim=getattr(row, "avg_sim", None) or None,
|
backend/app/protein/data_loader.py
CHANGED
|
@@ -174,7 +174,7 @@ class DataManager:
|
|
| 174 |
CAST(e.RMSD AS REAL) AS RMSD,
|
| 175 |
CAST(e.structure_sim AS REAL) AS structure_sim,
|
| 176 |
e."delta_Rosetta", e."delta_FoldX", e."delta_EvoEF2",
|
| 177 |
-
e."
|
| 178 |
e.state_id_B, e.state_fidelity, e.avg_sim, e.observation_fidelity
|
| 179 |
FROM edge e
|
| 180 |
{where_sql}
|
|
@@ -189,7 +189,7 @@ class DataManager:
|
|
| 189 |
conn.close()
|
| 190 |
|
| 191 |
# Rename columns with special characters so itertuples works cleanly
|
| 192 |
-
df = df.rename(columns={"
|
| 193 |
|
| 194 |
df["cluster_id"] = df["TM1"].apply(
|
| 195 |
lambda t: _assign_cluster(t) if pd.notna(t) else "cluster_low"
|
|
|
|
| 174 |
CAST(e.RMSD AS REAL) AS RMSD,
|
| 175 |
CAST(e.structure_sim AS REAL) AS structure_sim,
|
| 176 |
e."delta_Rosetta", e."delta_FoldX", e."delta_EvoEF2",
|
| 177 |
+
e."delta_RW", e."delta_RW+",
|
| 178 |
e.state_id_B, e.state_fidelity, e.avg_sim, e.observation_fidelity
|
| 179 |
FROM edge e
|
| 180 |
{where_sql}
|
|
|
|
| 189 |
conn.close()
|
| 190 |
|
| 191 |
# Rename columns with special characters so itertuples works cleanly
|
| 192 |
+
df = df.rename(columns={"delta_RW+": "delta_RW_plus"})
|
| 193 |
|
| 194 |
df["cluster_id"] = df["TM1"].apply(
|
| 195 |
lambda t: _assign_cluster(t) if pd.notna(t) else "cluster_low"
|
backend/app/protein/models.py
CHANGED
|
@@ -112,8 +112,8 @@ class DataRecord(BaseModel):
|
|
| 112 |
delta_rosetta: Optional[float] = None
|
| 113 |
delta_foldx: Optional[float] = None
|
| 114 |
delta_evoef2: Optional[float] = None
|
| 115 |
-
|
| 116 |
-
|
| 117 |
# Alternative state similarity fields from edge table
|
| 118 |
state_id_b: Optional[str] = None
|
| 119 |
state_fidelity: Optional[str] = None
|
|
|
|
| 112 |
delta_rosetta: Optional[float] = None
|
| 113 |
delta_foldx: Optional[float] = None
|
| 114 |
delta_evoef2: Optional[float] = None
|
| 115 |
+
delta_rw: Optional[float] = None
|
| 116 |
+
delta_rw_plus: Optional[float] = None
|
| 117 |
# Alternative state similarity fields from edge table
|
| 118 |
state_id_b: Optional[str] = None
|
| 119 |
state_fidelity: Optional[str] = None
|
backend/app/protein/tsv_loader.py
CHANGED
|
@@ -32,7 +32,7 @@ def _load() -> Dict[Tuple[str, str], _Row]:
|
|
| 32 |
cur = conn.cursor()
|
| 33 |
cur.execute(
|
| 34 |
'SELECT pdb_id, auth_asym_id, base_label, sequence, sequence_length,'
|
| 35 |
-
' CATH_ID, cath_superfamily, Rosetta, FoldX, EvoEF2,
|
| 36 |
' state_id, experimental_method, pH, temp_K'
|
| 37 |
' FROM node'
|
| 38 |
)
|
|
@@ -50,8 +50,8 @@ def _load() -> Dict[Tuple[str, str], _Row]:
|
|
| 50 |
"Rosetta": row["Rosetta"] or "",
|
| 51 |
"FoldX": row["FoldX"] or "",
|
| 52 |
"EvoEF2": row["EvoEF2"] or "",
|
| 53 |
-
"
|
| 54 |
-
"
|
| 55 |
"ranked_functions": row["ranked_functions"] or "",
|
| 56 |
"state_id": row["state_id"] or "",
|
| 57 |
"experimental_method": row["experimental_method"] or "",
|
|
@@ -87,7 +87,7 @@ def _lookup_node_row(pdb_id: str, auth_asym_id: str) -> Optional[_Row]:
|
|
| 87 |
conn.row_factory = sqlite3.Row
|
| 88 |
row = conn.execute(
|
| 89 |
'SELECT base_label, sequence, sequence_length, CATH_ID, cath_superfamily,'
|
| 90 |
-
' Rosetta, FoldX, EvoEF2,
|
| 91 |
' state_id, experimental_method, pH, temp_K'
|
| 92 |
' FROM node WHERE LOWER(pdb_id) = ? AND UPPER(auth_asym_id) = ? LIMIT 1',
|
| 93 |
(pdb_id.lower(), auth_asym_id.upper()),
|
|
@@ -126,7 +126,7 @@ def _parse_float(val: str) -> Optional[float]:
|
|
| 126 |
|
| 127 |
|
| 128 |
def get_energy_scores(pdb_id: str, auth_asym_id: str) -> Optional[Dict[str, Any]]:
|
| 129 |
-
"""Return energy scores (Rosetta, FoldX, EvoEF2,
|
| 130 |
row = get_node_row(pdb_id, auth_asym_id)
|
| 131 |
if row is None:
|
| 132 |
return None
|
|
@@ -134,8 +134,8 @@ def get_energy_scores(pdb_id: str, auth_asym_id: str) -> Optional[Dict[str, Any]
|
|
| 134 |
"Rosetta": _parse_float(row.get("Rosetta", "")),
|
| 135 |
"FoldX": _parse_float(row.get("FoldX", "")),
|
| 136 |
"EvoEF2": _parse_float(row.get("EvoEF2", "")),
|
| 137 |
-
"
|
| 138 |
-
"
|
| 139 |
}
|
| 140 |
|
| 141 |
|
|
|
|
| 32 |
cur = conn.cursor()
|
| 33 |
cur.execute(
|
| 34 |
'SELECT pdb_id, auth_asym_id, base_label, sequence, sequence_length,'
|
| 35 |
+
' CATH_ID, cath_superfamily, Rosetta, FoldX, EvoEF2, RW, "RW+", ranked_functions,'
|
| 36 |
' state_id, experimental_method, pH, temp_K'
|
| 37 |
' FROM node'
|
| 38 |
)
|
|
|
|
| 50 |
"Rosetta": row["Rosetta"] or "",
|
| 51 |
"FoldX": row["FoldX"] or "",
|
| 52 |
"EvoEF2": row["EvoEF2"] or "",
|
| 53 |
+
"RW": row["RW"] or "",
|
| 54 |
+
"RW+": row["RW+"] or "",
|
| 55 |
"ranked_functions": row["ranked_functions"] or "",
|
| 56 |
"state_id": row["state_id"] or "",
|
| 57 |
"experimental_method": row["experimental_method"] or "",
|
|
|
|
| 87 |
conn.row_factory = sqlite3.Row
|
| 88 |
row = conn.execute(
|
| 89 |
'SELECT base_label, sequence, sequence_length, CATH_ID, cath_superfamily,'
|
| 90 |
+
' Rosetta, FoldX, EvoEF2, RW, "RW+", ranked_functions,'
|
| 91 |
' state_id, experimental_method, pH, temp_K'
|
| 92 |
' FROM node WHERE LOWER(pdb_id) = ? AND UPPER(auth_asym_id) = ? LIMIT 1',
|
| 93 |
(pdb_id.lower(), auth_asym_id.upper()),
|
|
|
|
| 126 |
|
| 127 |
|
| 128 |
def get_energy_scores(pdb_id: str, auth_asym_id: str) -> Optional[Dict[str, Any]]:
|
| 129 |
+
"""Return energy scores (Rosetta, FoldX, EvoEF2, RW, RW+) or None if not found."""
|
| 130 |
row = get_node_row(pdb_id, auth_asym_id)
|
| 131 |
if row is None:
|
| 132 |
return None
|
|
|
|
| 134 |
"Rosetta": _parse_float(row.get("Rosetta", "")),
|
| 135 |
"FoldX": _parse_float(row.get("FoldX", "")),
|
| 136 |
"EvoEF2": _parse_float(row.get("EvoEF2", "")),
|
| 137 |
+
"RW": _parse_float(row.get("RW", "")),
|
| 138 |
+
"RW+": _parse_float(row.get("RW+", "")),
|
| 139 |
}
|
| 140 |
|
| 141 |
|
backend/assets/MuSProt_documentation.md
CHANGED
|
@@ -49,8 +49,8 @@ Each row represents a single protein chain instance (one PDB entry + chain).
|
|
| 49 |
| `Rosetta` | FLOAT | Rosetta total energy score |
|
| 50 |
| `FoldX` | FLOAT | FoldX total energy score |
|
| 51 |
| `EvoEF2` | FLOAT | EvoEF2 total energy score |
|
| 52 |
-
| `
|
| 53 |
-
| `
|
| 54 |
| `ranked_functions` | TEXT | JSON-encoded list of ranked GO/functional annotations |
|
| 55 |
|
| 56 |
|
|
@@ -72,8 +72,8 @@ Each row represents a pairwise structural comparison between two chain instances
|
|
| 72 |
| `delta_Rosetta` | FLOAT | Rosetta energy difference (B − A) |
|
| 73 |
| `delta_FoldX` | FLOAT | FoldX energy difference (B − A) |
|
| 74 |
| `delta_EvoEF2` | FLOAT | EvoEF2 energy difference (B − A) |
|
| 75 |
-
| `
|
| 76 |
-
| `
|
| 77 |
| `state_id_A` | TEXT | Conformational state cluster of chain A |
|
| 78 |
| `state_id_B` | TEXT | Conformational state cluster of chain B |
|
| 79 |
| `avg_sim` | TEXT | Average structural similarity within the state cluster (`>0.95` or a numeric value) |
|
|
|
|
| 49 |
| `Rosetta` | FLOAT | Rosetta total energy score |
|
| 50 |
| `FoldX` | FLOAT | FoldX total energy score |
|
| 51 |
| `EvoEF2` | FLOAT | EvoEF2 total energy score |
|
| 52 |
+
| `RW` | FLOAT | Random-Walk (RW) energy score |
|
| 53 |
+
| `RW+` | FLOAT | Random-Walk+ (RWplus) energy score |
|
| 54 |
| `ranked_functions` | TEXT | JSON-encoded list of ranked GO/functional annotations |
|
| 55 |
|
| 56 |
|
|
|
|
| 72 |
| `delta_Rosetta` | FLOAT | Rosetta energy difference (B − A) |
|
| 73 |
| `delta_FoldX` | FLOAT | FoldX energy difference (B − A) |
|
| 74 |
| `delta_EvoEF2` | FLOAT | EvoEF2 energy difference (B − A) |
|
| 75 |
+
| `delta_RW` | FLOAT | Random-Walk (RW) energy difference (B − A) |
|
| 76 |
+
| `delta_RW+` | FLOAT | Random-Walk+ (RWplus) energy difference (B − A) |
|
| 77 |
| `state_id_A` | TEXT | Conformational state cluster of chain A |
|
| 78 |
| `state_id_B` | TEXT | Conformational state cluster of chain B |
|
| 79 |
| `avg_sim` | TEXT | Average structural similarity within the state cluster (`>0.95` or a numeric value) |
|
backend/scripts/generate_node_lookup.py
CHANGED
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
| 9 |
|
| 10 |
NODE_COLUMNS = (
|
| 11 |
"pdb_id", "auth_asym_id", "base_label", "sequence", "sequence_length",
|
| 12 |
-
"CATH_ID", "cath_superfamily", "Rosetta", "FoldX", "EvoEF2", "
|
| 13 |
"ranked_functions", "state_id", "experimental_method", "pH", "temp_K",
|
| 14 |
)
|
| 15 |
|
|
@@ -30,7 +30,7 @@ def main() -> None:
|
|
| 30 |
conn.execute(
|
| 31 |
'CREATE TABLE node (pdb_id, auth_asym_id, base_label, sequence BLOB,'
|
| 32 |
' sequence_length, CATH_ID, cath_superfamily, Rosetta, FoldX, EvoEF2,'
|
| 33 |
-
'
|
| 34 |
)
|
| 35 |
source = sqlite3.connect(f"file:{args.source.resolve()}?mode=ro", uri=True)
|
| 36 |
try:
|
|
|
|
| 9 |
|
| 10 |
NODE_COLUMNS = (
|
| 11 |
"pdb_id", "auth_asym_id", "base_label", "sequence", "sequence_length",
|
| 12 |
+
"CATH_ID", "cath_superfamily", "Rosetta", "FoldX", "EvoEF2", "RW", "RW+",
|
| 13 |
"ranked_functions", "state_id", "experimental_method", "pH", "temp_K",
|
| 14 |
)
|
| 15 |
|
|
|
|
| 30 |
conn.execute(
|
| 31 |
'CREATE TABLE node (pdb_id, auth_asym_id, base_label, sequence BLOB,'
|
| 32 |
' sequence_length, CATH_ID, cath_superfamily, Rosetta, FoldX, EvoEF2,'
|
| 33 |
+
' RW, "RW+", ranked_functions BLOB, state_id, experimental_method, pH, temp_K)'
|
| 34 |
)
|
| 35 |
source = sqlite3.connect(f"file:{args.source.resolve()}?mode=ro", uri=True)
|
| 36 |
try:
|
frontend/src/components/datasets/protein/DataTable.tsx
CHANGED
|
@@ -111,11 +111,11 @@ export const DataTable: React.FC<DataTableProps> = ({ data, loading, total, filt
|
|
| 111 |
<th onClick={() => handleSort('delta_evoef2')}>
|
| 112 |
ΔEvoEF2 {getSortIcon('delta_evoef2')}
|
| 113 |
</th>
|
| 114 |
-
<th onClick={() => handleSort('
|
| 115 |
-
Δ
|
| 116 |
</th>
|
| 117 |
-
<th onClick={() => handleSort('
|
| 118 |
-
Δ
|
| 119 |
</th>
|
| 120 |
<th onClick={() => handleSort('state_id_b')}>
|
| 121 |
State ID {getSortIcon('state_id_b')}
|
|
@@ -154,7 +154,7 @@ export const DataTable: React.FC<DataTableProps> = ({ data, loading, total, filt
|
|
| 154 |
<td className="numeric">
|
| 155 |
{formatPH(record.pH)}
|
| 156 |
</td>
|
| 157 |
-
{(['delta_rosetta', 'delta_foldx', 'delta_evoef2', '
|
| 158 |
const val = record[field];
|
| 159 |
return (
|
| 160 |
<td key={field} className={`numeric delta-cell${val == null ? '' : val > 0 ? ' delta-pos' : val < 0 ? ' delta-neg' : ''}`}>
|
|
|
|
| 111 |
<th onClick={() => handleSort('delta_evoef2')}>
|
| 112 |
ΔEvoEF2 {getSortIcon('delta_evoef2')}
|
| 113 |
</th>
|
| 114 |
+
<th onClick={() => handleSort('delta_rw')}>
|
| 115 |
+
ΔRW {getSortIcon('delta_rw')}
|
| 116 |
</th>
|
| 117 |
+
<th onClick={() => handleSort('delta_rw_plus')}>
|
| 118 |
+
ΔRW+ {getSortIcon('delta_rw_plus')}
|
| 119 |
</th>
|
| 120 |
<th onClick={() => handleSort('state_id_b')}>
|
| 121 |
State ID {getSortIcon('state_id_b')}
|
|
|
|
| 154 |
<td className="numeric">
|
| 155 |
{formatPH(record.pH)}
|
| 156 |
</td>
|
| 157 |
+
{(['delta_rosetta', 'delta_foldx', 'delta_evoef2', 'delta_rw', 'delta_rw_plus'] as const).map(field => {
|
| 158 |
const val = record[field];
|
| 159 |
return (
|
| 160 |
<td key={field} className={`numeric delta-cell${val == null ? '' : val > 0 ? ' delta-pos' : val < 0 ? ' delta-neg' : ''}`}>
|
frontend/src/types/protein.ts
CHANGED
|
@@ -89,8 +89,8 @@ export interface DataRecord {
|
|
| 89 |
delta_rosetta?: number | null;
|
| 90 |
delta_foldx?: number | null;
|
| 91 |
delta_evoef2?: number | null;
|
| 92 |
-
|
| 93 |
-
|
| 94 |
structure_sim?: number | null;
|
| 95 |
// Alternative state similarity fields from edge table
|
| 96 |
state_id_b?: string | null;
|
|
|
|
| 89 |
delta_rosetta?: number | null;
|
| 90 |
delta_foldx?: number | null;
|
| 91 |
delta_evoef2?: number | null;
|
| 92 |
+
delta_rw?: number | null;
|
| 93 |
+
delta_rw_plus?: number | null;
|
| 94 |
structure_sim?: number | null;
|
| 95 |
// Alternative state similarity fields from edge table
|
| 96 |
state_id_b?: string | null;
|