In [ ]:
Copied!
!pip install pygx
!pip install pygx
In [2]:
Copied!
from typing import Literal
import pygx as pg
from typing import Literal
import pygx as pg
In [3]:
Copied!
import abc
from IPython.display import display, HTML
Color = Literal['white', 'black', 'yellow', 'blue', 'red', 'green']
class Shape(pg.Object, topo=True):
fill: Color = 'white'
stroke: Color = 'white'
stroke_width: int = pg.field(value_spec=pg.typing.Int(min_value=1))
TAG = None
def on_sym_post_init(self):
_CANVAS.shapes.append(self)
def __del__(self):
_CANVAS.shapes.remove(self)
super().__del__(self)
def to_svg(self):
return self._to_svg(self.TAG, **self.sym_init_args)
def _to_svg(self, tag_name, **kwargs):
svg = f'<{tag_name}'
for k, v in kwargs.items():
svg += f' {k}="{v}"'
svg += '/>'
return svg
class Circle(Shape):
cx: int
cy: int
r: int = pg.field(value_spec=pg.typing.Int(min_value=1))
TAG = 'circle'
class Canvas(pg.Object, topo=True):
# `pg.List[...]` (not builtin `list`) keeps the members symbolic, so
# they join the tree and changes propagate to the canvas.
shapes: pg.List[Shape] = []
def on_sym_bound(self):
super().on_sym_bound()
if self.shapes:
self.render()
def render(self):
svg = '<html><body><svg>\n'
for s in self.shapes:
svg += s.to_svg() + '\n'
svg += '</svg></body></html>'
display(HTML(svg))
_CANVAS = Canvas()
import abc
from IPython.display import display, HTML
Color = Literal['white', 'black', 'yellow', 'blue', 'red', 'green']
class Shape(pg.Object, topo=True):
fill: Color = 'white'
stroke: Color = 'white'
stroke_width: int = pg.field(value_spec=pg.typing.Int(min_value=1))
TAG = None
def on_sym_post_init(self):
_CANVAS.shapes.append(self)
def __del__(self):
_CANVAS.shapes.remove(self)
super().__del__(self)
def to_svg(self):
return self._to_svg(self.TAG, **self.sym_init_args)
def _to_svg(self, tag_name, **kwargs):
svg = f'<{tag_name}'
for k, v in kwargs.items():
svg += f' {k}="{v}"'
svg += '/>'
return svg
class Circle(Shape):
cx: int
cy: int
r: int = pg.field(value_spec=pg.typing.Int(min_value=1))
TAG = 'circle'
class Canvas(pg.Object, topo=True):
# `pg.List[...]` (not builtin `list`) keeps the members symbolic, so
# they join the tree and changes propagate to the canvas.
shapes: pg.List[Shape] = []
def on_sym_bound(self):
super().on_sym_bound()
if self.shapes:
self.render()
def render(self):
svg = '<html><body><svg>\n'
for s in self.shapes:
svg += s.to_svg() + '\n'
svg += '</svg></body></html>'
display(HTML(svg))
_CANVAS = Canvas()
In [4]:
Copied!
# Create a circle and render it using SVG.
circle = Circle(cx=50, cy=50, r=25, stroke='blue', stroke_width=4, fill='white')
# Create a circle and render it using SVG.
circle = Circle(cx=50, cy=50, r=25, stroke='blue', stroke_width=4, fill='white')
Let's create patcher to move a circle by command. As a result, we can use URI-like string to manipulate a circle object.
In [5]:
Copied!
@pg.patcher([
('x', pg.typing.Int()),
('y', pg.typing.Int()),
])
def move(circle, x, y):
return {
'cx': circle.cx + x,
'cy': circle.cy + y,
}
def action(shape, command):
pg.patch(shape, [command])
@pg.patcher([
('x', pg.typing.Int()),
('y', pg.typing.Int()),
])
def move(circle, x, y):
return {
'cx': circle.cx + x,
'cy': circle.cy + y,
}
def action(shape, command):
pg.patch(shape, [command])
Invoke the patcher to move the circle:
In [6]:
Copied!
action(circle, 'move?x=50&y=20')
action(circle, 'move?x=50&y=0')
action(circle, 'move?x=50&y=0')
action(circle, 'move?x=50&y=20')
action(circle, 'move?x=50&y=0')
action(circle, 'move?x=50&y=0')
In [7]:
Copied!
del circle
del circle