Skip to content

Commit

Permalink
WIP: periodic-table implement with anywidget
Browse files Browse the repository at this point in the history
  • Loading branch information
unkcpz committed Feb 28, 2024
1 parent 5afa479 commit b947d05
Show file tree
Hide file tree
Showing 6 changed files with 861 additions and 7 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ dependencies = [
"ase~=3.22",
"pandas~=2.1",
"requests~=2.31",
"widget_periodictable~=3.1",
"semver~=3.0",
"anywidget~=0.9",
]

[project.optional-dependencies]
Expand Down
132 changes: 132 additions & 0 deletions src/ipyoptimade/subwidgets/_periodic_table/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import anywidget
import traitlets as tl
import pathlib
import copy

from .utils import CHEMICAL_ELEMENTS, color_as_rgb


class PeriodicTableWidget(anywidget.AnyWidget):
_esm = pathlib.Path(__file__).parent / "index.js"
_css = pathlib.Path(__file__).parent / "style.css"

selected_elements = tl.Dict({}).tag(sync=True)
disabled_elements = tl.List([]).tag(sync=True)
display_names_replacements = tl.Dict({}).tag(sync=True)
disabled_color = tl.Unicode("gray").tag(sync=True)
unselected_color = tl.Unicode("pink").tag(sync=True)
states = tl.Int(1).tag(sync=True)
selected_colors = tl.List([]).tag(sync=True)
border_color = tl.Unicode("#cc7777").tag(sync=True)
disabled = tl.Bool(False, help="Enable or disable user changes.").tag(sync=True)
width = tl.Unicode("38px").tag(sync=True)
allElements = tl.List(CHEMICAL_ELEMENTS).tag(sync=True)

_STANDARD_COLORS = [
"#a6cee3",
"#b2df8a",
"#fdbf6f",
"#6a3d9a",
"#b15928",
"#e31a1c",
"#1f78b4",
"#33a02c",
"#ff7f00",
"#cab2d6",
"#ffff99",
]

def __init__(
self,
states=1,
selected_elements=None,
disabled_elements=None,
disabled_color=None,
unselected_color=None,
selected_colors=[],
border_color=None,
width=None,
layout=None,
*args,
**kwargs,
):
super().__init__(*args, **kwargs)
self.states = states if states else 1
self.selected_elements = selected_elements if selected_elements else {}
self.disabled_elements = disabled_elements if disabled_elements else []
self.disabled_color = disabled_color if disabled_color else "gray"
self.unselected_color = unselected_color if unselected_color else "pink"
self.selected_colors = (
selected_colors if selected_colors else self._STANDARD_COLORS
)
self.border_color = border_color if border_color else "#cc7777"
self.width = width if width else "38px"

if layout is not None:
self.layout = layout

if len(selected_colors) < states:
self.selected_colors = selected_colors + self._STANDARD_COLORS * (
1 + (states - len(selected_colors)) // len(self._STANDARD_COLORS)
)
self.selected_colors = self.selected_colors[:states]

def set_element_state(self, elementName, state):
if elementName not in self.allElements:
raise tl.TraitError("Element not found")
if state not in range(self.states):
raise tl.TraitError("State value is wrong")
x = copy.deepcopy(self.selected_elements)
x[elementName] = state
self.selected_elements = x

@tl.validate("disabled_color", "unselected_color", "border_color")
def _color_change(self, proposal):
"""Convert to rgb(X, Y, Z) type color"""
return color_as_rgb(proposal["value"])

@tl.validate("selected_colors")
def _selectedColors_change(self, proposal):
"""Convert to rgb(X, Y, Z) type color"""
res = []
for color in proposal["value"]:
res.append(color_as_rgb(color))
return res

@tl.validate("selected_elements")
def _selectedElements_change(self, proposal):
for x, y in proposal["value"].items():
if x not in self.allElements and x != "Du":
raise tl.TraitError("Element not found")
if not isinstance(y, int) or y not in range(self.states):
raise tl.TraitError("State value is wrong")
return proposal["value"]

@tl.observe("disabled_elements")
def _disabledList_change(self, change):
for i in change["new"]:
if i in self.selected_elements:
del self.selected_elements[i]

@tl.observe("states")
def _states_change(self, change):
if change["new"] < 1:
raise tl.TraitError("State value cannot smaller than 1")
else:
if len(self.selected_colors) < change["new"]:
self.selected_colors = self.selected_colors + self._STANDARD_COLORS * (
1
+ (change["new"] - len(self.selected_colors))
// len(self._STANDARD_COLORS)
)
self.selected_colors = self.selected_colors[: change["new"]]
elif len(self.selected_colors) > change["new"]:
self.selected_colors = self.selected_colors[: change["new"]]

def get_elements_by_state(self, state):
if state not in range(self.states):
raise tl.TraitError("State value is wrong")
else:
return [
i for i in self.selected_elements if self.selected_elements[i] == state
]
Loading

0 comments on commit b947d05

Please sign in to comment.