Skip to content

Commit fd9553e

Browse files
Implement periodic table component
1 parent 61b3553 commit fd9553e

File tree

12 files changed

+283
-62
lines changed

12 files changed

+283
-62
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.v-application .title {
2+
text-align: center;
3+
font-size: 2em !important;
4+
margin-top: 0.5em;
5+
}
6+
7+
.legend {
8+
display: grid;
9+
grid-template-columns: repeat(4, minmax(250px, 1fr));
10+
justify-content: center;
11+
align-items: center;
12+
margin: 1em auto;
13+
}
14+
.legend .legend-item-marker {
15+
width: 1em;
16+
height: 1em;
17+
border-radius: 50%;
18+
margin-right: 0.5em;
19+
}
20+
.legend .legend-item {
21+
display: flex;
22+
align-items: center;
23+
margin-right: 1em;
24+
width: fit-content;
25+
font-size: 14px;
26+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
:root {
2+
--element-box-size: 55px;
3+
}
4+
5+
.ptable-outer {
6+
display: flex;
7+
text-align: center;
8+
align-items: center;
9+
justify-content: center;
10+
width: fit-content;
11+
margin: 0 auto;
12+
}
13+
14+
.v-application .ptable {
15+
display: flex !important;
16+
row-gap: 12px;
17+
}
18+
.v-application .ptable .elements {
19+
display: grid !important;
20+
grid-template-columns: repeat(17, 1fr) 1fr;
21+
}
22+
23+
.element {
24+
height: var(--element-box-size);
25+
width: var(--element-box-size);
26+
margin: 1px;
27+
user-select: none;
28+
position: relative;
29+
border-radius: 20%;
30+
cursor: pointer;
31+
display: flex;
32+
flex-direction: column;
33+
justify-content: center;
34+
align-items: center;
35+
color: white;
36+
text-decoration: none;
37+
}
38+
.element.element-2 {
39+
grid-column-start: 18;
40+
}
41+
.element.element-5 {
42+
grid-column-start: 13;
43+
}
44+
.element.element-13 {
45+
grid-column-start: 13;
46+
}
47+
.element.element-57 {
48+
grid-column-start: 4;
49+
}
50+
.element.element-89 {
51+
grid-column-start: 4;
52+
}
53+
.element.disabled {
54+
pointer-events: none;
55+
}
56+
.element:hover {
57+
filter: brightness(85%);
58+
transform: scale(1.2);
59+
z-index: 10;
60+
}
61+
.element .element-symbol {
62+
font-size: calc(0.32 * var(--element-box-size));
63+
line-height: 1;
64+
}
65+
.element .element-info {
66+
font-size: 13px;
67+
line-height: 1;
68+
}
69+
70+
.star-placeholder {
71+
display: flex;
72+
font-weight: bold;
73+
align-self: center;
74+
justify-self: center;
75+
grid-column-start: 3;
76+
}
77+
78+
@media screen and (max-width: 1280px) {
79+
:root {
80+
--element-box-size: 40px;
81+
}
82+
83+
.element_symbol {
84+
font-size: calc(0.4 * var(--element-box-size));
85+
}
86+
87+
.element-info {
88+
display: none;
89+
}
90+
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
from .header import Header # noqa
2-
from .layout import Layout # noqa

src/aiidalab_sssp/components/ptable/__init__.py

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from __future__ import annotations
2+
3+
from solara import Text, VBox
4+
from solara.core import component
5+
6+
from aiidalab_sssp.models.element import ElementModel
7+
8+
9+
@component
10+
def DetailsBox(element: ElementModel | None):
11+
if element:
12+
with VBox(classes=["border details-box"]):
13+
Text(text=element.symbol)
14+
Text(text=element.number)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from __future__ import annotations
2+
3+
import typing as t
4+
5+
from solara import HTML, Div, Text
6+
from solara.core import component
7+
8+
from aiidalab_sssp.models.element import ElementModel
9+
10+
11+
@component
12+
def Element(
13+
element: ElementModel,
14+
on_hover: t.Callable[[ElementModel], None],
15+
):
16+
classes = ["element", f"element-{element.number}"]
17+
if element.disabled:
18+
classes.append("disabled")
19+
20+
with Div(
21+
classes=classes,
22+
style={"background-color": element.background},
23+
) as element_box:
24+
Text(text=element.symbol, classes=["element-symbol"])
25+
if not element.disabled:
26+
with Div(classes=["element-info"]):
27+
HTML("span", f"{int(element.wfc)}", classes=["element-wfc"])
28+
HTML("sub", f"({int(element.rho)})", classes=["element-rho"])
29+
30+
if not element.disabled:
31+
element_box.on("mouseover", lambda: on_hover(element))
32+
33+
return element_box
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from __future__ import annotations
2+
3+
import typing as t
4+
5+
from reacton import use_state
6+
from solara import Div, Style, Text, VBox
7+
from solara.core import component
8+
9+
from aiidalab_sssp.assets.styles import css
10+
from aiidalab_sssp.components.ptable.details import DetailsBox
11+
from aiidalab_sssp.components.ptable.element import Element
12+
from aiidalab_sssp.models.element import ElementModel
13+
14+
15+
@component
16+
def PTable(elements: list[ElementModel]):
17+
hovered_element, set_hovered_element = use_state(t.cast(ElementModel | None, None))
18+
19+
def on_hover(element: ElementModel):
20+
set_hovered_element(element)
21+
22+
def Placeholder(n: int):
23+
with Div(classes=["star-placeholder"]):
24+
Text("★" * n)
25+
26+
def Table():
27+
def Elements(start, end):
28+
for element in elements[start:end]:
29+
Element(element=element, on_hover=on_hover)
30+
31+
with VBox(classes=["container ptable"]):
32+
with Div(classes=["elements"]):
33+
Elements(0, 56)
34+
Placeholder(1)
35+
Elements(71, 88)
36+
Placeholder(2)
37+
Elements(103, 118)
38+
with Div(classes=["elements rare-earth"]):
39+
Placeholder(1)
40+
Elements(56, 71)
41+
Placeholder(2)
42+
Elements(88, 103)
43+
44+
Style(css / "table.css")
45+
46+
with Div(classes=["container ptable-outer"]):
47+
DetailsBox(element=hovered_element)
48+
Table()

src/aiidalab_sssp/models/__init__.py

Whitespace-only changes.

src/aiidalab_sssp/models/element.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass(frozen=True)
5+
class ElementModel:
6+
number: int
7+
symbol: str
8+
dual: float = 0.0
9+
wfc: float = 0.0
10+
rho: float = 0.0
11+
md5: str = ""
12+
filename: str = ""
13+
pseudopotential: str = ""
14+
background: str = "#dddddd"
15+
disabled: bool = False

src/aiidalab_sssp/pages/__init__.py

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +0,0 @@
1-
import solara
2-
from solara.alias import rv
3-
4-
from aiidalab_sssp.pages import explore, verify
5-
from aiidalab_sssp.data import articles, names
6-
from aiidalab_sssp.components import banner
7-
8-
9-
@solara.component
10-
def PeopleCard(name):
11-
with solara.Card(f"Employee of the Month: {name}") as main:
12-
with rv.CardText():
13-
solara.Markdown(
14-
"""
15-
* Department: foo
16-
* Skills: bar, baz
17-
"""
18-
)
19-
with solara.Link(f"/people/{name}"):
20-
solara.Button("View employee", text=True, icon_name="mdi-profile")
21-
return main
22-
23-
24-
@solara.component
25-
def Layout(children=[]):
26-
router = solara.use_context(solara.routing.router_context)
27-
with solara.VBox() as navigation:
28-
with rv.List(dense=True):
29-
with rv.ListItemGroup(v_model=router.path):
30-
with solara.Link(solara.resolve_path("/")):
31-
with solara.ListItem("Home", icon_name="mdi-home", value="/"):
32-
pass
33-
with solara.ListItem("tabular data", icon_name="mdi-database"):
34-
for name in names:
35-
pathname = f"/tabular/{name}"
36-
with solara.Link(solara.resolve_path(pathname)):
37-
solara.ListItem(name, value=pathname)
38-
with solara.ListItem("Articles", icon_name="mdi-book-open"):
39-
for name, article_ in articles.items():
40-
pathname = f"/article/{name}"
41-
with solara.Link(solara.resolve_path(pathname)):
42-
solara.ListItem(article_.title, value=pathname)
43-
44-
with solara.AppLayout(navigation=navigation, title="Solara demo", children=children) as main:
45-
pass
46-
return main
47-
48-
49-
@solara.component
50-
def Page():
51-
with solara.VBox() as main:
52-
solara.Title("Standard Solid-State Pseudopotential (SSSP) » Home")
53-
with solara.ColumnsResponsive(12):
54-
banner.Overview()
55-
with solara.ColumnsResponsive([6, 6], small=[12]):
56-
explore.Overview()
57-
verify.Overview()
58-
59-
return main
60-

src/aiidalab_sssp/pages/explore.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from __future__ import annotations
2+
3+
import json
4+
from pathlib import Path
5+
6+
from solara import HTML, Div, Style, Text, VBox
7+
from solara.core import component
8+
9+
from aiidalab_sssp.assets.styles import css
10+
from aiidalab_sssp.components.ptable.table import PTable
11+
from aiidalab_sssp.models.element import ElementModel
12+
13+
14+
@component
15+
def Page():
16+
symbols: list[str] = json.loads(Path("data/symbols.json").read_text())
17+
data: dict[str, dict] = json.loads(Path("data/sssp_efficiency.json").read_text())
18+
metadata: dict[str, dict] = json.loads(Path("data/metadata.json").read_text())
19+
20+
elements = [
21+
ElementModel(
22+
number=number,
23+
symbol=symbol,
24+
wfc=data[symbol]["cutoff"],
25+
rho=data[symbol]["rho_cutoff"],
26+
dual=data[symbol]["dual"],
27+
md5=data[symbol]["md5"],
28+
filename=data[symbol]["filename"],
29+
pseudopotential=data[symbol]["pseudopotential"],
30+
background=metadata[data[symbol]["pseudopotential"]]["background_color"],
31+
disabled=data[symbol]["disabled"] if "disabled" in data[symbol] else False,
32+
)
33+
if symbol in data
34+
else ElementModel(
35+
number=number,
36+
symbol=symbol,
37+
disabled=True,
38+
)
39+
for number, symbol in enumerate(symbols, 1)
40+
]
41+
42+
def Legend():
43+
with Div(classes=["legend"]):
44+
for pp in metadata.values():
45+
with Div(classes=["legend-item"]):
46+
HTML(
47+
classes=["legend-item-marker"],
48+
style={"background-color": pp["background_color"]},
49+
)
50+
Text(text=pp["display_name"])
51+
52+
Style(css / "explore.css")
53+
54+
with VBox():
55+
Text(text="SSSP Efficiency (v1.3.0)", classes=["title"])
56+
Legend()
57+
PTable(elements)

src/aiidalab_sssp/pages/verify.py

Whitespace-only changes.

0 commit comments

Comments
 (0)