Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional primitives #38

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
eed2ed6
data models for additional primitives
aliaksei-chareshneu Oct 31, 2024
4fad172
more models
aliaksei-chareshneu Oct 31, 2024
73a41d5
more models
aliaksei-chareshneu Oct 31, 2024
22c4324
naming fixes
aliaksei-chareshneu Nov 1, 2024
b4af2fa
types
aliaksei-chareshneu Nov 1, 2024
5605c4e
box
aliaksei-chareshneu Nov 1, 2024
72f2c2c
cage; fix description;
aliaksei-chareshneu Nov 1, 2024
a18e491
fixes; cylinder;
aliaksei-chareshneu Nov 5, 2024
d1e9cb9
Vec3 to PrimitivePositionT for all centers
aliaksei-chareshneu Nov 5, 2024
9b72e3c
Vec3 to PrimitivePositionT
aliaksei-chareshneu Nov 5, 2024
84e128f
Transform mixin
aliaksei-chareshneu Nov 11, 2024
e89eb17
fix cylinder params
aliaksei-chareshneu Nov 11, 2024
99921cb
cage
aliaksei-chareshneu Nov 11, 2024
3959aaf
fix center param type; remove as_edges param; remove outdated comment;
aliaksei-chareshneu Nov 14, 2024
c0b83c6
change rotation implementation from 9d matrix to angle and axis
aliaksei-chareshneu Nov 15, 2024
16db139
cage support; fix params;
aliaksei-chareshneu Nov 15, 2024
9a298e2
cylinder fix params
aliaksei-chareshneu Nov 16, 2024
e2d1ba8
cylinder to cone; no theta
aliaksei-chareshneu Nov 16, 2024
b7712ac
draft for circle
aliaksei-chareshneu Nov 16, 2024
6c53d62
Update molviewspec/molviewspec/nodes.py
aliaksei-chareshneu Nov 16, 2024
b7e191c
examples
aliaksei-chareshneu Nov 16, 2024
4ae6e31
upd example
aliaksei-chareshneu Nov 16, 2024
a20d3bd
ellipsoid prototype (tested, color TODO); ellipsis draft (WIP);
aliaksei-chareshneu Nov 20, 2024
617a8f3
fix: add missing color params
aliaksei-chareshneu Nov 20, 2024
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
113 changes: 113 additions & 0 deletions _examples/build_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from molviewspec.molviewspec.builder import create_builder
from molviewspec.molviewspec.nodes import ComponentExpression


builder = create_builder()

download = builder.download(url="https://www.ebi.ac.uk/pdbe/entry-files/download/1tqn_updated.cif")
structure = download.parse(format="mmcif").model_structure()

component1 = structure.component(selector="ligand").representation(type="ball_and_stick")
structure.component(selector="polymer").representation(type="cartoon")
structure.primitives().box(center=ComponentExpression(auth_seq_id=508), extent=[5,5,5], color="green") # or .cage

# TODO: debug at frontend then try these params
builder.primitives().box(
center=[0.1, 0.1, 0.1],
extent=[1.0, 1.0, 1.0],
color="red",
scaling=[10.0, 1.0, 1.0],
translation=[10.0, 10.0, 10.0],
rotation_axis=[0.0, 1.0, 0.0],
rotation_radians=1.0
)

structure.primitives().cage(
# center=[0.5, 0.5, 0.5],
center=ComponentExpression(auth_seq_id=508),
extent=[5.0, 3.0, 18.0],
color="orange",
scaling=[10.0, 1.0, 1.0],
translation=[10.0, 10.0, 10.0],
rotation_axis=[0.0, 1.0, 0.0],
rotation_radians=1.0,
edge_radius=7.5,
# TODO: as geometry
type="as_lines"
)

structure.primitives().cone(
radius_bottom=1.5,
radius_top=2.5,
bottom_cap=True,
top_cap=False,
color="magenta",
# bottom=[1, 1, 1],
# up=[2,5,10]
bottom=ComponentExpression(auth_seq_id=508),
up=ComponentExpression(auth_seq_id=399)
)

builder.primitives().box(
center=[10, 10, 10],
extent=[2.0, 3.0, 10.0],
color="blue"
)


# let's throw in some lines and labels that intersect each face in the middle
# (
# builder.primitives(color="blue", label_color="blue", tooltip="Generic Axis", transparency=0.5)
# # chain primitives to create desired visuals
# .line(start=(-0.5, 0.5, 0.5), end=(1.5, 0.5, 0.5), thickness=0.05, color="red", tooltip="### Axis\nX")
# # .label(position=(-0.5, 0.5, 0.5), text="X", label_size=0.33, label_color="orange")
# .line(start=(0.5, -0.5, 0.5), end=(0.5, 1.5, 0.5), thickness=0.05, color="green", tooltip="### Axis\nY")
# # .label(position=(0.5, -0.5, 0.5), text="Y", label_size=0.33, label_color="blue")
# .line(start=(0.5, 0.5, -0.5), end=(0.5, 0.5, 1.5), thickness=0.05, color="magenta")
# # .label(position=(0.5, 0.5, -0.5), text="Z", label_size=0.33, color="yellow")
# )
# builder.primitives().mesh(
# vertices=[
# 0.0, 0.0, 0.0,
# 1.0, 0.0, 0.0,
# 1.0, 1.0, 0.0,
# 0.0, 1.0, 0.0,
# 0.0, 0.0, 1.0,
# 1.0, 0.0, 1.0,
# 1.0, 1.0, 1.0,
# 0.0, 1.0, 1.0,
# ],
# indices=[
# # bottom
# 0, 2, 1, 0, 3, 2,
# # top
# 4, 5, 6, 4, 6, 7,
# # front
# 0, 1, 5, 0, 5, 4,
# # back
# 2, 3, 7, 2, 7, 6,
# # left
# 0, 7, 3, 0, 4, 7,
# # right
# 1, 2, 6, 1, 6, 5,
# ],
# triangle_groups=[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5],
# group_colors={0: "red", 1: "green", 2: "blue", 3: "yellow", 4: "magenta", 5: "cyan"},
# group_tooltips={0: "### Side\nbottom", 1: "### Side\ntop", 2: "### Side\nfront", 3: "### Side\nback", 4: "### Side\nleft", 5: "### Side\nright"},
# show_wireframe=True,
# wireframe_radius=2,
# wireframe_color="black",
# )
# # let's throw in some lines and labels that intersect each face in the middle
# (
# builder.primitives(color="blue", label_color="blue", tooltip="Generic Axis", transparency=0.5)
# # chain primitives to create desired visuals
# .line(start=(-0.5, 0.5, 0.5), end=(1.5, 0.5, 0.5), thickness=0.05, color="red", tooltip="### Axis\nX")
# .label(position=(-0.5, 0.5, 0.5), text="X", label_size=0.33, label_color="red")
# .line(start=(0.5, -0.5, 0.5), end=(0.5, 1.5, 0.5), thickness=0.05, color="green", tooltip="### Axis\nY")
# .label(position=(0.5, -0.5, 0.5), text="Y", label_size=0.33, label_color="green")
# .line(start=(0.5, 0.5, -0.5), end=(0.5, 0.5, 1.5), thickness=0.05)
# .label(position=(0.5, 0.5, -0.5), text="Z", label_size=0.33)
# )

builder.save_state(destination='./_examples/state.mvsj')
153 changes: 152 additions & 1 deletion molviewspec/molviewspec/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
from pydantic import BaseModel, PrivateAttr

from molviewspec.nodes import (
# from molviewspec.molviewspec.nodes import (
BoxParams,
CageParams,
CameraParams,
CanvasParams,
EllipsisParams,
ColorFromSourceParams,
ColorFromUriParams,
ColorInlineParams,
Expand All @@ -24,9 +28,11 @@
ComponentInlineParams,
ComponentSelectorT,
CustomT,
CylinderParams,
DescriptionFormatT,
DistanceMeasurementParams,
DownloadParams,
EllipsoidParams,
FocusInlineParams,
LabelFromSourceParams,
LabelFromUriParams,
Expand Down Expand Up @@ -57,7 +63,7 @@
TransparencyInlineParams,
Vec3,
)
from molviewspec.utils import get_major_version_tag, make_params
from molviewspec.molviewspec.utils import get_major_version_tag, make_params


def create_builder() -> Root:
Expand Down Expand Up @@ -566,6 +572,7 @@ def tooltip_from_source(
def transform(
self,
*,
# TODO: given as Optional[Mat3[float]] in nodes.py
rotation: Sequence[float] | None = None,
translation: Sequence[float] | None = None,
custom: CustomT = None,
Expand Down Expand Up @@ -935,3 +942,147 @@ def label(
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

def box(self,
*,
center: PrimitivePositionT,
extent: Vec3,
color: ColorT | None = None,
scaling: Vec3[float] | None = [1.0, 1.0, 1.0],
rotation_axis: Vec3[float] | None = None,
rotation_radians: float | None = None,
translation: Vec3[float] | None = None,
custom: CustomT = None,
ref: RefT = None,
) -> Primitives:
# TODO: annotation
# """
# Defines a box
# :param center: center of the box
# :param extent: height and width of the box
# :param scaling: scaling
# :param as_edges: 3d vector describing the scaling.
# :param label_offset: camera-facing offset to prevent overlap with geometry
# :param custom: optional, custom data to attach to this node
# :param ref: optional, reference that can be used to access this node
# :return: this builder
# """
params = make_params(BoxParams, {"kind": "box", **locals()})
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

def cage(self,
*,
center: PrimitivePositionT,
extent: Vec3,
color: ColorT | None = None,
scaling: Vec3[float] | None = [1.0, 1.0, 1.0],
edge_radius: float | None = None,
rotation_axis: Vec3[float] | None = None,
rotation_radians: float | None = None,
translation: Vec3[float] | None = None,
type: Literal["as_lines", "as_geometry"] = "as_lines",
custom: CustomT = None,
ref: RefT = None,
) -> Primitives:
# TODO annotation
# """
# Defines a box
# :param center: center of the box
# :param extent: height and width of the box
# :param scaling: scaling
# :param as_edges: 3d vector describing the scaling.
# :param label_offset: camera-facing offset to prevent overlap with geometry
# :param custom: optional, custom data to attach to this node
# :param ref: optional, reference that can be used to access this node
# :return: this builder
# """
params = make_params(CageParams, {"kind": "cage", **locals()})
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

# TODO: sphere
def ellipsoid(
self,
*,
color: ColorT | None = None,
direction_major: Vec3[float],
direction_minor: Vec3[float],
center: PrimitivePositionT,
radius_scale: Vec3[float] | None = None
):
# TODO annotation
# """
# Defines a box
# :param center: center of the box
# :param extent: height and width of the box
# :param scaling: scaling
# :param as_edges: 3d vector describing the scaling.
# :param label_offset: camera-facing offset to prevent overlap with geometry
# :param custom: optional, custom data to attach to this node
# :param ref: optional, reference that can be used to access this node
# :return: this builder
# """
params = make_params(EllipsoidParams, {"kind": "ellipsoid", **locals()})
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

def ellipsis(self,
*,
center: PrimitivePositionT,
color: ColorT | None = None,
major_axis: PrimitivePositionT,
minor_axis: PrimitivePositionT
):
# TODO annotation
# """
# Defines a box
# :param center: center of the box
# :param extent: height and width of the box
# :param scaling: scaling
# :param as_edges: 3d vector describing the scaling.
# :param label_offset: camera-facing offset to prevent overlap with geometry
# :param custom: optional, custom data to attach to this node
# :param ref: optional, reference that can be used to access this node
# :return: this builder
# """
params = make_params(EllipsisParams, {"kind": "circle", **locals()})
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

# TODO: cone
def cylinder(self,
*,
bottom: Vec3[float],
up: Vec3[float],
radius_top: float,
radius_bottom: float,
bottom_cap: bool,
top_cap: bool,
color: ColorT | None = None,
rotation_axis: Vec3[float] | None = None,
rotation_radians: float | None = None,
custom: CustomT = None,
ref: RefT = None,
) -> Primitives:
# TODO annotation
# """
# Defines a box
# :param center: center of the box
# :param extent: height and width of the box
# :param scaling: scaling
# :param as_edges: 3d vector describing the scaling.
# :param label_offset: camera-facing offset to prevent overlap with geometry
# :param custom: optional, custom data to attach to this node
# :param ref: optional, reference that can be used to access this node
# :return: this builder
# """
params = make_params(CylinderParams, {"kind": "cylinder", **locals()})
node = Node(kind="primitive", params=params)
self._add_child(node)
return self

Loading