-
Notifications
You must be signed in to change notification settings - Fork 3
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
Feature: only one element can be choose #23
Comments
Hi @dou-du, I extend this as a class. I think we can have a discussion and make the decision on how to integrate class PeriodicTable(ipw.VBox):
"""Wrapper-widget for PTableWidget"""
selected_element = traitlets.Unicode(allow_none=True)
def __init__(self, cache_folder, **kwargs):
self._disabled = kwargs.get("disabled", False)
self._cache_folder = cache_folder
self.ptable = PTableWidget(states=1, selected_colors=["green"], **kwargs)
self._last_selected = None
self.ptable.observe(self._on_element_select)
# if cache empty run update: first time
if os.path.exists(os.path.join(cache_folder, _DB_FOLDER)):
self._update_db(download=False)
else:
self._update_db(download=True)
disable_elements = [
e for e in self.ptable.allElements if e not in self.elements
]
self.ptable.disabled_elements = disable_elements
db_update = ipw.Button(
description="Update Database.",
)
db_update.on_click(self._update_db)
super().__init__(
children=(
self.ptable,
db_update,
),
layout=kwargs.get("layout", {}),
)
def _on_element_select(self, event):
if event["name"] == "selected_elements" and event["type"] == "change":
if tuple(event["new"].keys()) == ("Du",):
self._last_selected = event["old"]
elif tuple(event["old"].keys()) == ("Du",):
if len(event["new"]) != 1:
# Reset to only one element only if there is more than one selected,
# to avoid infinite loops
newly_selected = set(event["new"]).difference(self._last_selected)
# If this is empty it's ok, unselect all
# If there is more than one, that's weird... to avoid problems, anyway, I pick one of the two
if newly_selected:
element = list(newly_selected)[0]
self.ptable.selected_elements = {element: 0}
self.selected_element = element
else:
self.ptable.selected_elements = {}
self.selected_element = None
# To have the correct 'last' value for next calls
self._last_selected = self.ptable.selected_elements
else:
# first time set: len(event['new']) -> 1
self.selected_element = list(event["new"])[0]
def _update_db(self, _=None, download=True):
"""update cached db fetch from remote. and update ptable"""
# download from remote
if download:
self._download(self._cache_folder)
self.elements = self._get_enabled_elements(self._cache_folder)
disable_elements = [
e for e in self.ptable.allElements if e not in self.elements
]
self.ptable.disabled_elements = disable_elements
@staticmethod
def _get_enabled_elements(cache_folder):
elements = []
for fn in os.listdir(os.path.join(cache_folder, _DB_FOLDER)):
if "band" not in fn:
elements.append(fn.split(".")[0])
return elements
@staticmethod
def _download(cache_folder):
"""
The original sssp_db folder is deleted and re-downloaded from
source and extracted.
:params cache_folder: folder where cache stored
"""
# Purge whole db folder filst
db_dir = f"{cache_folder}/sssp_db"
if os.path.exists(db_dir) and os.path.isdir(db_dir):
shutil.rmtree(db_dir)
# download DB tar file from source
tar_file = f"{cache_folder}/sssp_db.tar.gz"
request.urlretrieve(_DB_URL, tar_file)
# decompress to the db folder
tar = tarfile.open(tar_file)
os.chdir(cache_folder)
tar.extractall()
tar.close()
os.remove(tar_file)
@property
def value(self) -> dict:
"""Return value for wrapped PTableWidget"""
return not self.select_any_all.value, self.ptable.selected_elements.copy()
@property
def disabled(self) -> None:
"""Disable widget"""
return self._disabled
@disabled.setter
def disabled(self, value: bool) -> None:
"""Disable widget"""
if not isinstance(value, bool):
raise TypeError("disabled must be a boolean")
self.select_any_all.disabled = self.ptable.disabled = value
def reset(self):
"""Reset widget"""
self.select_any_all.value = False
self.ptable.selected_elements = {}
self.selected_element = None
def freeze(self):
"""Disable widget"""
self.disabled = True
def unfreeze(self):
"""Activate widget (in its current state)"""
self.disabled = False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Like in the aiidalab sssp app and commonwf-oxides app, we want the periodic table can only have one element been chosen.
The following code works well for my sssp app, I assume it can be inside the widget and set by option with the periodic table instance.
The code now implemented is (copy from commonwf-oxides):
The text was updated successfully, but these errors were encountered: