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

Fea/anywidget periodic table #18

Closed
wants to merge 3 commits into from
Closed
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
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