Skip to content

Commit 7aa12a3

Browse files
committed
Fixed molstar visualization, changed aplpha fold api interaction
1 parent 9a933b0 commit 7aa12a3

File tree

1 file changed

+109
-16
lines changed

1 file changed

+109
-16
lines changed

src/components/structure/StructureViewer.tsx

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,39 @@ export const StructureViewer: React.FC<StructureViewerProps> = ({
177177
let isBinary = false;
178178
let finalPdbId = pdbId;
179179

180-
// Handle UniProt ID by loading AlphaFold structure directly
180+
// Handle UniProt ID by loading AlphaFold structure via API
181181
if (uniprotId && !pdbId) {
182-
// For UniProt IDs, we'll use AlphaFold exclusively for complete structures
183-
url = `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-model_v4.cif`;
184-
isBinary = true; // AlphaFold uses mmCIF format
182+
try {
183+
// Use the new AlphaFold API to get the structure URLs
184+
const response = await fetch(`https://alphafold.ebi.ac.uk/api/prediction/${uniprotId}`);
185+
if (!response.ok) {
186+
throw new Error(`AlphaFold API returned ${response.status}: ${response.statusText}`);
187+
}
188+
189+
const predictions = await response.json();
190+
if (!predictions || predictions.length === 0) {
191+
throw new Error(`No AlphaFold predictions found for UniProt ID: ${uniprotId}`);
192+
}
193+
194+
// Use the first prediction (usually the canonical sequence)
195+
const prediction = predictions[0];
196+
197+
// Prefer CIF format over PDB for better structure quality
198+
if (prediction.cifUrl) {
199+
url = prediction.cifUrl;
200+
isBinary = true; // CIF format
201+
} else if (prediction.pdbUrl) {
202+
url = prediction.pdbUrl;
203+
isBinary = false; // PDB format
204+
} else {
205+
throw new Error(`No structure files available for UniProt ID: ${uniprotId}`);
206+
}
207+
208+
console.log(`Loading AlphaFold structure from API: ${url}`);
209+
} catch (apiError) {
210+
console.error('AlphaFold API error:', apiError);
211+
throw new Error(`Failed to fetch AlphaFold structure: ${apiError}`);
212+
}
185213
} else if (pdbContent) {
186214
// Load from content string
187215
const blob = new Blob([pdbContent], { type: 'text/plain' });
@@ -197,31 +225,78 @@ export const StructureViewer: React.FC<StructureViewerProps> = ({
197225
throw new Error('No PDB ID, UniProt ID, URL, or content provided');
198226
}
199227

200-
// Load the structure
228+
// Load the structure with better error handling
229+
console.log(`Loading structure from: ${url}, format: ${isBinary ? 'mmcif' : 'pdb'}`);
230+
201231
const data = await pluginRef.current.builders.data.download(
202232
{ url: Asset.Url(url) },
203233
{ state: { isGhost: false } }
204234
);
205235

206-
// Parse the structure format
236+
if (!data) {
237+
throw new Error('Failed to download structure data');
238+
}
239+
240+
// Parse the structure format with improved format detection
241+
let format = isBinary ? 'mmcif' : 'pdb';
242+
243+
// Better format detection based on URL
244+
if (url.toLowerCase().includes('.cif')) {
245+
format = 'mmcif';
246+
} else if (url.toLowerCase().includes('.bcif')) {
247+
format = 'mmcif'; // Binary CIF is also mmcif format
248+
} else if (url.toLowerCase().includes('.pdb')) {
249+
format = 'pdb';
250+
}
251+
207252
const trajectory = await pluginRef.current.builders.structure.parseTrajectory(
208253
data,
209-
isBinary ? 'mmcif' : 'pdb'
254+
format
210255
);
211256

257+
if (!trajectory) {
258+
throw new Error('Failed to parse structure trajectory');
259+
}
260+
212261
// Create the structure
213262
const model = await pluginRef.current.builders.structure.createModel(trajectory);
263+
264+
if (!model) {
265+
throw new Error('Failed to create structure model');
266+
}
267+
214268
const structure = await pluginRef.current.builders.structure.createStructure(model);
215269

270+
if (!structure) {
271+
throw new Error('Failed to create structure representation');
272+
}
273+
216274
// Apply default representation (cartoon + ball-and-stick for ligands)
217-
await pluginRef.current.builders.structure.representation.addRepresentation(
218-
structure,
219-
{
220-
type: 'cartoon',
221-
color: 'chain-id',
222-
size: 'uniform',
275+
try {
276+
await pluginRef.current.builders.structure.representation.addRepresentation(
277+
structure,
278+
{
279+
type: 'cartoon',
280+
color: 'chain-id',
281+
size: 'uniform',
282+
}
283+
);
284+
} catch (reprError) {
285+
console.warn('Could not add cartoon representation, trying alternative:', reprError);
286+
// Try a simpler representation if cartoon fails
287+
try {
288+
await pluginRef.current.builders.structure.representation.addRepresentation(
289+
structure,
290+
{
291+
type: 'ball-and-stick',
292+
color: 'element-symbol',
293+
}
294+
);
295+
} catch (altReprError) {
296+
console.warn('Alternative representation also failed:', altReprError);
297+
// Structure is loaded but no representation - this is still partially successful
223298
}
224-
);
299+
}
225300

226301
// Focus on the structure
227302
await PluginCommands.Camera.Reset(pluginRef.current, {});
@@ -235,10 +310,28 @@ export const StructureViewer: React.FC<StructureViewerProps> = ({
235310
onStructureLoaded?.();
236311

237312
} catch (err) {
238-
const errorMsg = `Failed to load structure: ${err}`;
313+
let errorMsg = 'Failed to load structure';
314+
315+
// Provide more specific error messages based on the error type
316+
if (err instanceof Error) {
317+
if (err.message.includes('404') || err.message.includes('Not Found')) {
318+
errorMsg = `Structure not found. The ${uniprotId ? 'UniProt ID' : 'PDB ID'} "${uniprotId || pdbId}" may not have an available structure in the database.`;
319+
} else if (err.message.includes('Invalid data cell')) {
320+
errorMsg = `Structure file format error. The structure data appears to be corrupted or in an unsupported format.`;
321+
} else if (err.message.includes('AlphaFold API')) {
322+
errorMsg = `AlphaFold database error: ${err.message}`;
323+
} else if (err.message.includes('Network')) {
324+
errorMsg = `Network error: Unable to download structure. Please check your internet connection.`;
325+
} else {
326+
errorMsg = `Structure loading error: ${err.message}`;
327+
}
328+
} else {
329+
errorMsg = `Unknown error occurred while loading structure: ${err}`;
330+
}
331+
239332
setError(errorMsg);
240333
onError?.(errorMsg);
241-
console.error(errorMsg);
334+
console.error('Structure loading error:', err);
242335
} finally {
243336
setIsLoading(false);
244337
}

0 commit comments

Comments
 (0)