Skip to content

Commit

Permalink
Add colors to sequence + started on chain selection in 3D
Browse files Browse the repository at this point in the history
  • Loading branch information
sverhoeven committed Mar 28, 2024
1 parent c3c6d59 commit ccb43aa
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
5 changes: 4 additions & 1 deletion app/scenarios/MoleculeSubForm.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ export function MoleculeSubForm({
</FormItem>
<div className="h-[500px] w-full">
{molecule ? (
<Viewer structure={molecule?.structure} />
<Viewer
structure={molecule?.structure}
chain={actpass.active.chain}
/>
) : (
<p>Load a structure first</p>
)}
Expand Down
26 changes: 23 additions & 3 deletions app/scenarios/ResiduesSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { ChangeEvent, useState } from "react";
import { FormDescription } from "./FormDescription";
import { Residue } from "./molecule.client";
import { Residue, SecondaryStructure } from "./molecule.client";
import clsx from "clsx";

const residueVariants: Record<SecondaryStructure, string> = {
sheet: "bg-amber-200 dark:bg-amber-700",
helix: "bg-red-200 dark:bg-red-900",
turn: "",
"": "",
};

export function ResiduesSelect({
options,
Expand Down Expand Up @@ -46,13 +54,19 @@ export function ResiduesSelect({
return (
<div
key={r.resno}
className="inline-block w-4"
className="inline-block w-4 text-center font-mono"
title={`${r.resno}`}
>
<span>{r.seq}</span>
<label
htmlFor={`residue-${r.resno}`}
className={residueVariants[r.sec]}
>
{r.seq}
</label>
<input
type="checkbox"
value={r.resno}
id={`residue-${r.resno}`}
checked={selected.includes(r.resno)}
onChange={(e) => handleChange(e, index)}
/>
Expand All @@ -61,6 +75,12 @@ export function ResiduesSelect({
})}
</div>
<FormDescription>
<span className={clsx("p-1 font-mono", residueVariants["helix"])}>
Helix
</span>{" "}
<span className={clsx("p-1 font-mono", residueVariants["sheet"])}>
Sheet
</span>{" "}
(Hold Shift to select a range of residues)
</FormDescription>
{/* TODO add buttons to select all, none, invert */}
Expand Down
28 changes: 21 additions & 7 deletions app/scenarios/Viewer.client.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { useEffect, useRef, useState } from "react";
import { Stage, Structure } from "ngl";
import { Stage, Structure, StructureComponent } from "ngl";

Check failure on line 2 in app/scenarios/Viewer.client.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'StructureComponent' is defined but never used

export function Viewer({ structure }: { structure: Structure }) {
export function Viewer({
structure,
chain,
}: {
structure: Structure;
chain?: string;
}) {
const viewportRef = useRef<HTMLDivElement>(null);
const stage = useRef<Stage | null>(null);
const [isLoaded, setIsLoaded] = useState(false);
Expand Down Expand Up @@ -45,11 +51,7 @@ export function Viewer({ structure }: { structure: Structure }) {
console.error("Could not load structure");
return;
}
component.addRepresentation("cartoon", { sele: "polymer" });
component.addRepresentation("ball+stick", { sele: "ligand" });
component.addRepresentation("base", { sele: "nucleic" });

component.autoView();
stage.current.defaultFileRepresentation(component);

setIsLoaded(true);

Expand All @@ -65,5 +67,17 @@ export function Viewer({ structure }: { structure: Structure }) {
// };
}, [structure, isLoaded]);

useEffect(() => {
if (stage.current === null) {
return;
}

stage.current.eachRepresentation((repr) => {

Check failure on line 75 in app/scenarios/Viewer.client.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'repr' is defined but never used
const selection = chain ? `:${chain}` : "";

Check failure on line 76 in app/scenarios/Viewer.client.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'selection' is assigned a value but never used
// TODO figure out how to set selection
// repr.setSelection(selection);
});
}, [chain]);

return <div ref={viewportRef} className="h-full w-full"></div>;
}
21 changes: 20 additions & 1 deletion app/scenarios/molecule.client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
import { Structure, autoLoad } from "ngl";
import ResidueProxy from "ngl/dist/declarations/proxy/residue-proxy";

export type Residue = { resno: number; seq: string };
export type Residue = { resno: number; seq: string; sec: SecondaryStructure };
export type Chains = Record<string, Residue[]>;
export type Molecule = { structure: Structure; chains: Chains; file: File };

export type SecondaryStructure = "sheet" | "helix" | "turn" | "";

function secondaryStructureOfResidue(
residue: ResidueProxy
): SecondaryStructure {
if (residue.isSheet()) {
return "sheet";
}
if (residue.isHelix()) {
return "helix";
}
if (residue.isTurn()) {
return "turn";
}
return "";
}

export function chainsFromStructure(structure: Structure) {
const chains: Chains = {};
structure.eachChain((c) => {
Expand All @@ -13,6 +31,7 @@ export function chainsFromStructure(structure: Structure) {
residues.push({
resno: r.resno,
seq: r.getResname1(),
sec: secondaryStructureOfResidue(r),
});
});
chains[chainName] = residues;
Expand Down

0 comments on commit ccb43aa

Please sign in to comment.