Skip to content

Commit

Permalink
Implement periodic table component
Browse files Browse the repository at this point in the history
  • Loading branch information
edan-bainglass committed Aug 24, 2024
1 parent 61b3553 commit fd9553e
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 62 deletions.
26 changes: 26 additions & 0 deletions src/aiidalab_sssp/assets/styles/explore.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.v-application .title {
text-align: center;
font-size: 2em !important;
margin-top: 0.5em;
}

.legend {
display: grid;
grid-template-columns: repeat(4, minmax(250px, 1fr));
justify-content: center;
align-items: center;
margin: 1em auto;
}
.legend .legend-item-marker {
width: 1em;
height: 1em;
border-radius: 50%;
margin-right: 0.5em;
}
.legend .legend-item {
display: flex;
align-items: center;
margin-right: 1em;
width: fit-content;
font-size: 14px;
}
90 changes: 90 additions & 0 deletions src/aiidalab_sssp/assets/styles/table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
:root {
--element-box-size: 55px;
}

.ptable-outer {
display: flex;
text-align: center;
align-items: center;
justify-content: center;
width: fit-content;
margin: 0 auto;
}

.v-application .ptable {
display: flex !important;
row-gap: 12px;
}
.v-application .ptable .elements {
display: grid !important;
grid-template-columns: repeat(17, 1fr) 1fr;
}

.element {
height: var(--element-box-size);
width: var(--element-box-size);
margin: 1px;
user-select: none;
position: relative;
border-radius: 20%;
cursor: pointer;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
text-decoration: none;
}
.element.element-2 {
grid-column-start: 18;
}
.element.element-5 {
grid-column-start: 13;
}
.element.element-13 {
grid-column-start: 13;
}
.element.element-57 {
grid-column-start: 4;
}
.element.element-89 {
grid-column-start: 4;
}
.element.disabled {
pointer-events: none;
}
.element:hover {
filter: brightness(85%);
transform: scale(1.2);
z-index: 10;
}
.element .element-symbol {
font-size: calc(0.32 * var(--element-box-size));
line-height: 1;
}
.element .element-info {
font-size: 13px;
line-height: 1;
}

.star-placeholder {
display: flex;
font-weight: bold;
align-self: center;
justify-self: center;
grid-column-start: 3;
}

@media screen and (max-width: 1280px) {
:root {
--element-box-size: 40px;
}

.element_symbol {
font-size: calc(0.4 * var(--element-box-size));
}

.element-info {
display: none;
}
}
2 changes: 0 additions & 2 deletions src/aiidalab_sssp/components/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
from .header import Header # noqa
from .layout import Layout # noqa
Empty file.
14 changes: 14 additions & 0 deletions src/aiidalab_sssp/components/ptable/details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import annotations

from solara import Text, VBox
from solara.core import component

from aiidalab_sssp.models.element import ElementModel


@component
def DetailsBox(element: ElementModel | None):
if element:
with VBox(classes=["border details-box"]):
Text(text=element.symbol)
Text(text=element.number)
33 changes: 33 additions & 0 deletions src/aiidalab_sssp/components/ptable/element.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from __future__ import annotations

import typing as t

from solara import HTML, Div, Text
from solara.core import component

from aiidalab_sssp.models.element import ElementModel


@component
def Element(
element: ElementModel,
on_hover: t.Callable[[ElementModel], None],
):
classes = ["element", f"element-{element.number}"]
if element.disabled:
classes.append("disabled")

with Div(
classes=classes,
style={"background-color": element.background},
) as element_box:
Text(text=element.symbol, classes=["element-symbol"])
if not element.disabled:
with Div(classes=["element-info"]):
HTML("span", f"{int(element.wfc)}", classes=["element-wfc"])
HTML("sub", f"({int(element.rho)})", classes=["element-rho"])

if not element.disabled:
element_box.on("mouseover", lambda: on_hover(element))

return element_box
48 changes: 48 additions & 0 deletions src/aiidalab_sssp/components/ptable/table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations

import typing as t

from reacton import use_state
from solara import Div, Style, Text, VBox
from solara.core import component

from aiidalab_sssp.assets.styles import css
from aiidalab_sssp.components.ptable.details import DetailsBox
from aiidalab_sssp.components.ptable.element import Element
from aiidalab_sssp.models.element import ElementModel


@component
def PTable(elements: list[ElementModel]):
hovered_element, set_hovered_element = use_state(t.cast(ElementModel | None, None))

def on_hover(element: ElementModel):
set_hovered_element(element)

def Placeholder(n: int):
with Div(classes=["star-placeholder"]):
Text("★" * n)

def Table():
def Elements(start, end):
for element in elements[start:end]:
Element(element=element, on_hover=on_hover)

with VBox(classes=["container ptable"]):
with Div(classes=["elements"]):
Elements(0, 56)
Placeholder(1)
Elements(71, 88)
Placeholder(2)
Elements(103, 118)
with Div(classes=["elements rare-earth"]):
Placeholder(1)
Elements(56, 71)
Placeholder(2)
Elements(88, 103)

Style(css / "table.css")

with Div(classes=["container ptable-outer"]):
DetailsBox(element=hovered_element)
Table()
Empty file.
15 changes: 15 additions & 0 deletions src/aiidalab_sssp/models/element.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from dataclasses import dataclass


@dataclass(frozen=True)
class ElementModel:
number: int
symbol: str
dual: float = 0.0
wfc: float = 0.0
rho: float = 0.0
md5: str = ""
filename: str = ""
pseudopotential: str = ""
background: str = "#dddddd"
disabled: bool = False
60 changes: 0 additions & 60 deletions src/aiidalab_sssp/pages/__init__.py
Original file line number Diff line number Diff line change
@@ -1,60 +0,0 @@
import solara
from solara.alias import rv

from aiidalab_sssp.pages import explore, verify
from aiidalab_sssp.data import articles, names
from aiidalab_sssp.components import banner


@solara.component
def PeopleCard(name):
with solara.Card(f"Employee of the Month: {name}") as main:
with rv.CardText():
solara.Markdown(
"""
* Department: foo
* Skills: bar, baz
"""
)
with solara.Link(f"/people/{name}"):
solara.Button("View employee", text=True, icon_name="mdi-profile")
return main


@solara.component
def Layout(children=[]):
router = solara.use_context(solara.routing.router_context)
with solara.VBox() as navigation:
with rv.List(dense=True):
with rv.ListItemGroup(v_model=router.path):
with solara.Link(solara.resolve_path("/")):
with solara.ListItem("Home", icon_name="mdi-home", value="/"):
pass
with solara.ListItem("tabular data", icon_name="mdi-database"):
for name in names:
pathname = f"/tabular/{name}"
with solara.Link(solara.resolve_path(pathname)):
solara.ListItem(name, value=pathname)
with solara.ListItem("Articles", icon_name="mdi-book-open"):
for name, article_ in articles.items():
pathname = f"/article/{name}"
with solara.Link(solara.resolve_path(pathname)):
solara.ListItem(article_.title, value=pathname)

with solara.AppLayout(navigation=navigation, title="Solara demo", children=children) as main:
pass
return main


@solara.component
def Page():
with solara.VBox() as main:
solara.Title("Standard Solid-State Pseudopotential (SSSP) » Home")
with solara.ColumnsResponsive(12):
banner.Overview()
with solara.ColumnsResponsive([6, 6], small=[12]):
explore.Overview()
verify.Overview()

return main

57 changes: 57 additions & 0 deletions src/aiidalab_sssp/pages/explore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

import json
from pathlib import Path

from solara import HTML, Div, Style, Text, VBox
from solara.core import component

from aiidalab_sssp.assets.styles import css
from aiidalab_sssp.components.ptable.table import PTable
from aiidalab_sssp.models.element import ElementModel


@component
def Page():
symbols: list[str] = json.loads(Path("data/symbols.json").read_text())
data: dict[str, dict] = json.loads(Path("data/sssp_efficiency.json").read_text())
metadata: dict[str, dict] = json.loads(Path("data/metadata.json").read_text())

elements = [
ElementModel(
number=number,
symbol=symbol,
wfc=data[symbol]["cutoff"],
rho=data[symbol]["rho_cutoff"],
dual=data[symbol]["dual"],
md5=data[symbol]["md5"],
filename=data[symbol]["filename"],
pseudopotential=data[symbol]["pseudopotential"],
background=metadata[data[symbol]["pseudopotential"]]["background_color"],
disabled=data[symbol]["disabled"] if "disabled" in data[symbol] else False,
)
if symbol in data
else ElementModel(
number=number,
symbol=symbol,
disabled=True,
)
for number, symbol in enumerate(symbols, 1)
]

def Legend():
with Div(classes=["legend"]):
for pp in metadata.values():
with Div(classes=["legend-item"]):
HTML(
classes=["legend-item-marker"],
style={"background-color": pp["background_color"]},
)
Text(text=pp["display_name"])

Style(css / "explore.css")

with VBox():
Text(text="SSSP Efficiency (v1.3.0)", classes=["title"])
Legend()
PTable(elements)
Empty file.

0 comments on commit fd9553e

Please sign in to comment.