Skip to content

Commit

Permalink
Use better PT widget
Browse files Browse the repository at this point in the history
  • Loading branch information
unkcpz committed Jul 7, 2024
1 parent 18951c1 commit 1cf469b
Show file tree
Hide file tree
Showing 14 changed files with 27,115 additions and 606 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ dependencies = [
"aiida-sssp-workflow",
"solara",
"vaex",
"anywidget",
"anywidget>=0.9.0",
"humanfriendly",
]

Expand Down
102 changes: 102 additions & 0 deletions src/aiidalab_sssp/components/periodic_table/PTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from "react";

import { element_symbols } from "./ptable_symbols";

class Element extends React.Component {
constructor(props) {
super(props);

this.link = `${this.props.link_base}/${this.props.symbol}`;

this.disabled = false;
if (this.props.elem_info == null) {
this.disabled = true;
}

this.state = {};
}

render() {
let e_class = `element element-${this.props.num}`;

if (this.props.num >= 58 && this.props.num <= 71) {
e_class += " lanthanide";
}

let cutoff_text = null;
if (this.disabled) {
// the css class will disable the link
e_class += " element-disabled";
} else {
let wfc_cutoff = this.props.elem_info["cutoff"];
let rho_cutoff = this.props.elem_info["rho_cutoff"];
cutoff_text = (
<div className="elem_num">
{wfc_cutoff}
<sub>({rho_cutoff})</sub>
</div>
);
}

return (
<a
className={e_class}
style={{ background: this.props.color }}
href={this.link}
>
<div className="elem_sym">{this.props.symbol}</div>
{cutoff_text}
</a>
);
}
}

class PTable extends React.Component {
constructor(props) {
super(props);
}

makeElements = (start, end) => {
let items = [];
for (let i = start; i <= end; i++) {
let symbol = element_symbols[i];

// if this returns undefined, the element will be disabled later on
let elem_info = this.props.sssp_data[symbol];

let color = "#dddddd"; // color of disabled elements
if (elem_info) {
let pp = elem_info["pseudopotential"];
color = this.props.pseudo_metadata[pp]["background_color"];
}

items.push(
<Element
key={i}
num={i}
symbol={symbol}
color={color}
elem_info={elem_info}
link_base={this.props.link_base}
/>
);
}
return items;
};

render() {
return (
<div className="ptable_outer">
<div className="ptable">
{this.makeElements(1, 57)}
{this.makeElements(72, 89)}
{this.makeElements(104, 118)}
{this.makeElements(58, 71)}
{this.makeElements(90, 103)}
</div>
</div>
);
}
}

export default PTable;
138 changes: 5 additions & 133 deletions src/aiidalab_sssp/components/periodic_table/__init__.py
Original file line number Diff line number Diff line change
@@ -1,140 +1,12 @@
import pathlib

import anywidget
import traitlets
from traitlets import validate, observe, TraitError

from .utils import color_as_rgb, CHEMICAL_ELEMENTS
from copy import deepcopy

import traitlets as tl

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

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

# in
# element_color_mapping
# elements_disabled

# out
# element_clicked
# hover??? If hover display is not possible, then input a element_description_mapping

_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,
):
super().__init__()
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'
# clicked = tl.Unicode('').tag(sync=True)
my_vector = tl.Int(0).tag(sync=True)

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 TraitError('Element not found')
if state not in range(self.states):
raise TraitError('State value is wrong')
x = deepcopy(self.selected_elements)
x[elementName] = state
self.selected_elements = x

@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'])

@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

@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 TraitError('Element not found')
if not isinstance(y, int) or y not in range(self.states):
raise TraitError('State value is wrong')
return proposal['value']

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

@observe('states')
def _states_change(self, change):
if change['new'] < 1:
raise 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"]]
_esm = pathlib.Path(__file__).parent / "bundle.js"
_css = pathlib.Path(__file__).parent / "widget.css"

def get_elements_by_state(self, state):
if state not in range(self.states):
raise 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 1cf469b

Please sign in to comment.