Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
"mrbump = dlstbx.wrapper.mrbump:MrBUMPWrapper",
"pandda_xchem = dlstbx.wrapper.pandda_xchem:PanDDAWrapper",
"pandda_post = dlstbx.wrapper.pandda_post:PanDDApostWrapper",
"pandda_rhofit = dlstbx.wrapper.pandda_rhofit:PanDDARhofitWrapper",
"pipedream_xchem = dlstbx.wrapper.pipedream_xchem:PipedreamWrapper",
"phaser_ellg = dlstbx.wrapper.phaser_ellg:PhasereLLGWrapper",
"rlv = dlstbx.wrapper.rlv:RLVWrapper",
Expand Down
55 changes: 55 additions & 0 deletions src/dlstbx/util/mvs/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from __future__ import annotations

from pathlib import Path

import gemmi


def find_residue_by_name(structure, name):
for model in structure:
for chain in model:
for res in chain:
if res.name == name:
return chain, res
raise ValueError(f"Residue {name} not found")


def residue_centroid(residue):
n = 0
x = y = z = 0.0
for at in residue:
p = at.pos
x += p.x
y += p.y
z += p.z
n += 1
if n == 0:
raise ValueError("Residue has no atoms")
return gemmi.Position(x / n, y / n, z / n)


def save_cropped_map(pdb_file, map_file, resname, radius):
st = gemmi.read_structure(pdb_file)
cell = st.cell
m = gemmi.read_ccp4_map(map_file, setup=True)
grid = m.grid

chain, res = find_residue_by_name(st, resname)
center = residue_centroid(res) # ligand center

mask = grid.clone()
mask.fill(0.0)

mask.set_points_around(center, radius, 1.0, use_pbc=True) # spherical mask in Å

dl = gemmi.Position(radius, radius, radius) # box d/2
box = gemmi.FractionalBox()
box.extend(cell.fractionalize(center - dl))
box.extend(cell.fractionalize(center + dl))

grid.array[:] *= mask.array
m.set_extent(box)
path = Path(map_file)
map_out = str(path.parents[0] / f"{path.stem}_cropped.ccp4")
m.write_ccp4_map(map_out)
return map_out
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from __future__ import annotations

import gemmi
import molviewspec as mvs

from dlstbx.util.mvs.helpers import find_residue_by_name


def gen_html_ligandfit(pdb_file, map_file, resname, outdir, acr, smiles, cc):
# make an mvs story from snapshots
st = gemmi.read_structure(pdb_file)
chain, res = find_residue_by_name(st, resname)
residue = mvs.ComponentExpression(label_seq_id=res.seqid.num)

def gen_html_ligandfit(pdb_file, map_file, outdir, acr, smiles, cc):
# make a story from snapshots
builder = mvs.create_builder()
structure = builder.download(url=pdb_file).parse(format="pdb").model_structure()
structure.component(selector="polymer").representation(
Expand All @@ -30,21 +37,28 @@ def gen_html_ligandfit(pdb_file, map_file, outdir, acr, smiles, cc):

snapshot1 = builder.get_snapshot(
title="Main View",
description=f"## Ligand_Fit Results: \n ### {acr} with ligand & electron density map \n - SMILES: {smiles} \n - 2FO-FC at 1.5σ, blue \n - Fitting CC = {cc}",
transition_duration_ms=2000,
linger_duration_ms=5000,
description=f"## Ligand_Fit Results: \n ### {acr} with ligand & electron density map \n - SMILES: {smiles} \n - 2FO-FC map at 1.5σ, blue \n - Fitting CC = {cc}",
transition_duration_ms=700,
linger_duration_ms=4000,
)

# SNAPSHOT2
builder = mvs.create_builder()
structure = builder.download(url=pdb_file).parse(format="pdb").model_structure()
structure.component(selector="polymer").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.5).color(color="#D8BFD8")
structure.component(selector="polymer").representation().opacity(opacity=0.6).color(
color="grey"
).opacity(opacity=0.2).color(color="#AABDF1")
structure.component(selector="polymer").representation().opacity(
opacity=0.25
).color(custom={"molstar_color_theme_name": "chain_id"})
structure.component(selector="ligand").representation(type="ball_and_stick").color(
custom={"molstar_color_theme_name": "element-symbol"}
)
structure.component(selector="ligand").focus().representation(
structure.component(selector="ligand").representation(type="surface").opacity(
opacity=0.1
).color(custom={"molstar_color_theme_name": "element-symbol"})

structure.component(selector=residue).focus().representation(
type="ball_and_stick"
).color(custom={"molstar_color_theme_name": "element-symbol"})

Expand All @@ -56,25 +70,19 @@ def gen_html_ligandfit(pdb_file, map_file, outdir, acr, smiles, cc):
show_faces=False,
).color(color="blue").opacity(opacity=0.25)

# add a label
# info = get_chain_and_residue_numbers(pdb_file, "LIG")
# resid = info[0][1]
residue = mvs.ComponentExpression(label_seq_id=202)
(
structure.component(
selector=residue,
custom={
"molstar_show_non_covalent_interactions": True,
"molstar_non_covalent_interactions_radius_ang": 5.0,
},
).label(text=f"CC = {cc}")
structure.component(
selector=residue,
custom={
"molstar_show_non_covalent_interactions": True,
"molstar_non_covalent_interactions_radius_ang": 5,
},
)

snapshot2 = builder.get_snapshot(
title="Focus View",
description=f"## Ligand_Fit Results: \n ### {acr} with ligand & electron density map \n - SMILES: {smiles} \n - 2FO-FC at 1.5σ, blue \n - Fitting CC = {cc}",
transition_duration_ms=2000,
linger_duration_ms=5000,
transition_duration_ms=700,
linger_duration_ms=4000,
)

states = mvs.States(
Expand Down
120 changes: 120 additions & 0 deletions src/dlstbx/util/mvs/viewer_pandda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from __future__ import annotations

from pathlib import Path

import gemmi
import molviewspec as mvs

from dlstbx.util.mvs.helpers import find_residue_by_name


def gen_html_pandda(pdb_file, event_map, z_map, resname, outdir, dtag, smiles, score):
# make an mvs story from snapshots
st = gemmi.read_structure(pdb_file)
chain, res = find_residue_by_name(st, resname)
residue = mvs.ComponentExpression(label_seq_id=res.seqid.num)

builder = mvs.create_builder()
structure = builder.download(url=pdb_file).parse(format="pdb").model_structure()
structure.component(selector="polymer").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.2).color(color="#AABDF1")
structure.component(selector="polymer").representation().opacity(
opacity=0.25
).color(custom={"molstar_color_theme_name": "chain_id"})
structure.component(selector="ligand").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.1).color(custom={"molstar_color_theme_name": "element-symbol"})

structure.component(selector=residue).focus().representation(
type="ball_and_stick"
).color(custom={"molstar_color_theme_name": "element-symbol"})

ccp4 = builder.download(url=event_map).parse(format="map")
ccp4.volume().representation(
type="isosurface",
relative_isovalue=3,
show_wireframe=True,
show_faces=False,
).color(color="blue").opacity(opacity=0.25)

structure.component(
selector=residue,
custom={
"molstar_show_non_covalent_interactions": True,
"molstar_non_covalent_interactions_radius_ang": 5,
},
)

snapshot1 = builder.get_snapshot(
title="Event_map",
description=f"## PanDDA2 Results: \n ### {dtag} \n - Ligand score: {score} \n - SMILES: {smiles} \n - Event map at 3σ, blue",
transition_duration_ms=700,
linger_duration_ms=4000,
)

# SNAPSHOT2
builder = mvs.create_builder()
structure = builder.download(url=pdb_file).parse(format="pdb").model_structure()
structure.component(selector="polymer").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.2).color(color="#AABDF1")
structure.component(selector="polymer").representation().opacity(
opacity=0.25
).color(custom={"molstar_color_theme_name": "chain_id"})
structure.component(selector="ligand").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.1).color(custom={"molstar_color_theme_name": "element-symbol"})

structure.component(selector=residue).focus().representation(
type="ball_and_stick"
).color(custom={"molstar_color_theme_name": "element-symbol"})

ccp4 = builder.download(url=z_map).parse(format="map")
ccp4.volume().representation(
type="isosurface",
relative_isovalue=3,
show_wireframe=True,
show_faces=False,
).color(color="green").opacity(opacity=0.25)

structure.component(
selector=residue,
custom={
"molstar_show_non_covalent_interactions": True,
"molstar_non_covalent_interactions_radius_ang": 5,
},
)

snapshot2 = builder.get_snapshot(
title="Z_map",
description=f"## PanDDA2 Results: \n ### {dtag} \n - Ligand score: {score} \n - SMILES: {smiles} \n - Z_map at 3σ, green",
transition_duration_ms=700,
linger_duration_ms=4000,
)

states = mvs.States(
snapshots=[snapshot1, snapshot2], # [snapshot1, snapshot2]
metadata=mvs.GlobalMetadata(description="PanDDA2 Results"),
)

with open(pdb_file) as f:
pdb_data = f.read()

# with open(event_map, mode="rb") as f:
# map_data1 = f.read()

with open(z_map, mode="rb") as f:
map_data2 = f.read()

html = mvs.molstar_html(
states,
data={pdb_file: pdb_data, z_map: map_data2}, # event_map: map_data1,
ui="stories",
)

out_file = Path(f"{outdir}/pandda2_mvs.html")
with open(out_file, "w") as f:
f.write(html)

return out_file
74 changes: 74 additions & 0 deletions src/dlstbx/util/mvs/viewer_pipedream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from __future__ import annotations

from pathlib import Path

import gemmi
import molviewspec as mvs

from dlstbx.util.mvs.helpers import find_residue_by_name


def gen_html_pipedream(pdb_file, map_file, resname, outdir, dtag, smiles):
# make an mvs story from snapshots
st = gemmi.read_structure(pdb_file)
chain, res = find_residue_by_name(st, resname)
residue = mvs.ComponentExpression(label_seq_id=res.seqid.num)

builder = mvs.create_builder()
structure = builder.download(url=pdb_file).parse(format="pdb").model_structure()
structure.component(selector="polymer").representation(
type="surface", size_factor=0.7
).opacity(opacity=0.2).color(color="#AABDF1")
structure.component(selector="polymer").representation().opacity(
opacity=0.25
).color(custom={"molstar_color_theme_name": "chain_id"})

structure.component(selector=residue).focus().representation(
type="ball_and_stick"
).color(custom={"molstar_color_theme_name": "element-symbol"})

ccp4 = builder.download(url=map_file).parse(format="map")
ccp4.volume().representation(
type="isosurface",
relative_isovalue=1.5,
show_wireframe=True,
show_faces=False,
).color(color="blue").opacity(opacity=0.25)

structure.component(
selector=residue,
custom={
"molstar_show_non_covalent_interactions": True,
"molstar_non_covalent_interactions_radius_ang": 5,
},
)

snapshot1 = builder.get_snapshot(
title="Main View",
description=f"## Pipedream Results: \n ### {dtag} \n - SMILES: {smiles} \n - 2FO-FC map map at 1.5σ, blue",
transition_duration_ms=700,
linger_duration_ms=4000,
)

states = mvs.States(
snapshots=[snapshot1],
metadata=mvs.GlobalMetadata(description="Pipedream Results"),
)

with open(pdb_file) as f:
pdb_data = f.read()

with open(map_file, mode="rb") as f:
map_data = f.read()

html = mvs.molstar_html(
states,
data={pdb_file: pdb_data, map_file: map_data},
ui="stories",
)

out_file = Path(f"{outdir}/pipedream_mvs.html")
with open(out_file, "w") as f:
f.write(html)

return out_file
10 changes: 8 additions & 2 deletions src/dlstbx/wrapper/ligand_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from shutil import ignore_patterns

import dlstbx.util.symlink
from dlstbx.util.mvs.ligandfit import gen_html_ligandfit
from dlstbx.util.mvs.viewer_ligandfit import gen_html_ligandfit
from dlstbx.wrapper import Wrapper


Expand Down Expand Up @@ -149,7 +149,13 @@ def run(self):
CC = self.pull_CC_from_log(pipeline_directory)
try:
gen_html_ligandfit(
out_pdb, out_map, pipeline_directory, cc=CC, smiles=smiles, acr=acr
out_pdb,
out_map,
resname="LIG",
outdir=pipeline_directory,
cc=CC,
smiles=smiles,
acr=acr,
)
except Exception as e:
self.log.debug(f"Exception generating mvs html: {e}")
Expand Down
Loading