curryparty 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {curryparty-0.2.0 → curryparty-0.2.2}/PKG-INFO +1 -1
- {curryparty-0.2.0 → curryparty-0.2.2}/pyproject.toml +1 -1
- {curryparty-0.2.0 → curryparty-0.2.2}/src/curryparty/__init__.py +45 -18
- {curryparty-0.2.0 → curryparty-0.2.2}/src/curryparty/display.py +4 -0
- {curryparty-0.2.0 → curryparty-0.2.2}/src/curryparty/utils.py +26 -3
- {curryparty-0.2.0 → curryparty-0.2.2}/README.md +0 -0
- {curryparty-0.2.0 → curryparty-0.2.2}/src/curryparty/core.py +0 -0
- {curryparty-0.2.0 → curryparty-0.2.2}/src/curryparty/py.typed +0 -0
|
@@ -6,10 +6,12 @@ except ImportError:
|
|
|
6
6
|
raise ImportError(
|
|
7
7
|
"curryparty needs the `polars` library. \n Please install it, typically with `pip install polars`"
|
|
8
8
|
)
|
|
9
|
-
from svg import SVG
|
|
9
|
+
from svg import SVG, Rect
|
|
10
|
+
import uuid
|
|
10
11
|
|
|
11
12
|
from .core import SCHEMA, beta_reduce, compose, find_redexes, find_variables, subtree
|
|
12
13
|
from .display import (
|
|
14
|
+
compute_height,
|
|
13
15
|
compute_svg_frame_final,
|
|
14
16
|
compute_svg_frame_init,
|
|
15
17
|
compute_svg_frame_phase_a,
|
|
@@ -55,23 +57,29 @@ class Term:
|
|
|
55
57
|
if term is None:
|
|
56
58
|
break
|
|
57
59
|
|
|
58
|
-
def show_beta(self):
|
|
60
|
+
def show_beta(self, x0=-10, width=30):
|
|
61
|
+
"""
|
|
62
|
+
Generates an HTML representation that toggles visibility between
|
|
63
|
+
a static state and a SMIL animation on hover using pure CSS.
|
|
64
|
+
"""
|
|
59
65
|
candidates = find_redexes(self.nodes)
|
|
60
66
|
if len(candidates) == 0:
|
|
61
|
-
return
|
|
67
|
+
return self._repr_html_()
|
|
68
|
+
|
|
62
69
|
_redex, lamb, b = candidates.row(0)
|
|
63
70
|
new_nodes = beta_reduce(self.nodes, lamb, b)
|
|
64
71
|
vars = find_variables(self.nodes, lamb)["id"]
|
|
65
72
|
b_subtree = subtree(self.nodes, b)
|
|
73
|
+
height = compute_height(self.nodes) + 3
|
|
66
74
|
shapes: dict[int, ShapeAnim] = {}
|
|
67
|
-
N_STEPS =
|
|
75
|
+
N_STEPS = 6
|
|
68
76
|
|
|
69
77
|
for t in range(N_STEPS):
|
|
70
|
-
if t
|
|
78
|
+
if t == 0:
|
|
71
79
|
items = compute_svg_frame_init(self.nodes)
|
|
72
|
-
elif t ==
|
|
80
|
+
elif t == 1 or t == 2:
|
|
73
81
|
items = compute_svg_frame_phase_a(self.nodes, lamb, b_subtree, vars)
|
|
74
|
-
elif t ==
|
|
82
|
+
elif t == 3 or t == 4:
|
|
75
83
|
items = compute_svg_frame_phase_b(
|
|
76
84
|
self.nodes, lamb, b_subtree, new_nodes
|
|
77
85
|
)
|
|
@@ -82,28 +90,47 @@ class Term:
|
|
|
82
90
|
shapes[k] = ShapeAnim(e)
|
|
83
91
|
shapes[k].append_frame(t, attributes.items())
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
|
|
93
|
+
figure_id = uuid.uuid4()
|
|
94
|
+
box_id = f"lambda_box_{figure_id}".replace("-", "")
|
|
95
|
+
anim_elements = [
|
|
96
|
+
x.to_element(N_STEPS, begin=f"{box_id}.click", reset=f"{box_id}.mouseover")
|
|
97
|
+
for x in shapes.values()
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
anim_elements.append(
|
|
101
|
+
Rect(
|
|
102
|
+
id=box_id,
|
|
103
|
+
x=str(x0),
|
|
104
|
+
y="0",
|
|
105
|
+
width="100%",
|
|
106
|
+
height="100%",
|
|
107
|
+
fill="transparent",
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
anim_svg = SVG(
|
|
112
|
+
xmlns="http://www.w3.org/2000/svg",
|
|
113
|
+
viewBox=f"{x0} 0 {width} {height}",
|
|
114
|
+
height=f"{35 * height}px",
|
|
115
|
+
elements=anim_elements,
|
|
116
|
+
).as_str()
|
|
117
|
+
|
|
87
118
|
return Html(
|
|
88
|
-
|
|
89
|
-
xmlns="http://www.w3.org/2000/svg",
|
|
90
|
-
viewBox=f"-10 0 30 {height}", # type: ignore
|
|
91
|
-
height=f"{35 * height}px", # type: ignore
|
|
92
|
-
elements=elements,
|
|
93
|
-
).as_str()
|
|
119
|
+
f"<div><div style=\"margin:5px\">click to animate, move away and back to reset</div>{anim_svg}</div>"
|
|
94
120
|
)
|
|
95
121
|
|
|
96
|
-
def _repr_html_(self):
|
|
122
|
+
def _repr_html_(self, x0=-10, width=30):
|
|
97
123
|
frame = compute_svg_frame_init(self.nodes)
|
|
98
124
|
elements = []
|
|
99
|
-
|
|
125
|
+
|
|
126
|
+
height = compute_height(self.nodes) + 1
|
|
100
127
|
for _, e, attributes in frame:
|
|
101
128
|
for name, v in attributes.items():
|
|
102
129
|
e.__setattr__(name, v)
|
|
103
130
|
elements.append(e)
|
|
104
131
|
return SVG(
|
|
105
132
|
xmlns="http://www.w3.org/2000/svg",
|
|
106
|
-
viewBox=f"
|
|
133
|
+
viewBox=f"{x0} 0 {width} {height}", # type: ignore
|
|
107
134
|
height=f"{35 * height}px", # type: ignore
|
|
108
135
|
elements=elements,
|
|
109
136
|
).as_str()
|
|
@@ -38,6 +38,10 @@ def compute_layout(
|
|
|
38
38
|
y[node] = y[child] | y[node]
|
|
39
39
|
return x, y
|
|
40
40
|
|
|
41
|
+
def compute_height(nodes: pl.DataFrame):
|
|
42
|
+
_, y = compute_layout(nodes)
|
|
43
|
+
return max(interval[1] for interval in y.values() if interval)
|
|
44
|
+
|
|
41
45
|
|
|
42
46
|
def draw(
|
|
43
47
|
x: dict[Union[int, tuple[int, int]], Interval],
|
|
@@ -56,7 +56,7 @@ class ShapeAnim:
|
|
|
56
56
|
self.attributes.add(name)
|
|
57
57
|
self.values[i, name] = v
|
|
58
58
|
|
|
59
|
-
def to_element(self, n: int):
|
|
59
|
+
def to_element(self, n: int, begin: str, reset: str):
|
|
60
60
|
elements = []
|
|
61
61
|
|
|
62
62
|
visible = [
|
|
@@ -74,12 +74,24 @@ class ShapeAnim:
|
|
|
74
74
|
for i in range(n):
|
|
75
75
|
if (i, name) not in self.values:
|
|
76
76
|
self.values[i, name] = non_nulls[0]
|
|
77
|
+
self.shape.__setattr__(name, non_nulls[0])
|
|
78
|
+
|
|
77
79
|
elements.append(
|
|
78
80
|
Animate(
|
|
79
81
|
attributeName=name,
|
|
80
82
|
values=";".join(str(self.values[i, name]) for i in range(n)),
|
|
81
83
|
dur=timedelta(seconds=self.duration),
|
|
82
|
-
|
|
84
|
+
begin=begin,
|
|
85
|
+
fill="freeze",
|
|
86
|
+
repeatCount="1",
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
elements.append(
|
|
90
|
+
Animate(
|
|
91
|
+
attributeName=name,
|
|
92
|
+
values=f"{non_nulls[0]}",
|
|
93
|
+
dur=0,
|
|
94
|
+
begin=reset,
|
|
83
95
|
)
|
|
84
96
|
)
|
|
85
97
|
elements.append(
|
|
@@ -87,10 +99,21 @@ class ShapeAnim:
|
|
|
87
99
|
attributeName="opacity",
|
|
88
100
|
values=";".join("1" if v else "0" for v in visible),
|
|
89
101
|
dur=timedelta(seconds=self.duration),
|
|
90
|
-
|
|
102
|
+
begin=begin,
|
|
103
|
+
fill="freeze",
|
|
104
|
+
repeatCount="1",
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
elements.append(
|
|
108
|
+
Animate(
|
|
109
|
+
attributeName="opacity",
|
|
110
|
+
values="1" if visible[0] else "0",
|
|
111
|
+
dur=0,
|
|
112
|
+
begin=reset,
|
|
91
113
|
)
|
|
92
114
|
)
|
|
93
115
|
|
|
94
116
|
assert not self.shape.elements
|
|
117
|
+
self.shape
|
|
95
118
|
self.shape.elements = elements
|
|
96
119
|
return self.shape
|
|
File without changes
|
|
File without changes
|
|
File without changes
|