Skip to content

Commit 671fb74

Browse files
authored
Merge pull request #132 from chalk-diagrams/newmonoid
Rewrite and simplification of Chalk core
2 parents 587f1ca + 8ae2138 commit 671fb74

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+484
-572
lines changed

chalk/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
from chalk.align import * # noqa: F403
1212
from chalk.arrow import ArrowOpts, arrow_at, arrow_between, arrow_v
1313
from chalk.combinators import * # noqa: F403
14-
from chalk.core import empty, set_svg_draw_height, set_svg_height
14+
from chalk.core import set_svg_draw_height, set_svg_height
1515
from chalk.envelope import Envelope
16+
from chalk.monoid import Maybe, MList, Monoid
1617
from chalk.shapes import * # noqa: F403
1718
from chalk.style import Style
1819
from chalk.subdiagram import Name

chalk/backend/cairo.py

+26-37
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Any, List, Optional
3+
from typing import TYPE_CHECKING, Any, Optional
44

5+
from chalk.monoid import MList
56
from chalk.shapes import (
67
ArcSegment,
78
ArrowHead,
@@ -20,14 +21,7 @@
2021
from chalk.visitor import DiagramVisitor, ShapeVisitor
2122

2223
if TYPE_CHECKING:
23-
from chalk.core import (
24-
ApplyName,
25-
ApplyStyle,
26-
ApplyTransform,
27-
Compose,
28-
Empty,
29-
Primitive,
30-
)
24+
from chalk.core import ApplyName, ApplyStyle, ApplyTransform, Primitive
3125

3226

3327
Ident = Affine.identity()
@@ -44,52 +38,47 @@ def convert(a, b, c, d, e, f): # type: ignore
4438
return convert(*affine[:6]) # type: ignore
4539

4640

47-
class ToList(DiagramVisitor[List["Primitive"]]):
41+
class ToList(DiagramVisitor[MList[Any], Affine]):
4842
"""Compiles a `Diagram` to a list of `Primitive`s. The transformation `t`
4943
is accumulated upwards, from the tree's leaves.
5044
"""
5145

46+
A_type = MList[Any]
47+
5248
def visit_primitive(
5349
self, diagram: Primitive, t: Affine = Ident
54-
) -> List[Primitive]:
55-
return [diagram.apply_transform(t)]
56-
57-
def visit_empty(
58-
self, diagram: Empty, t: Affine = Ident
59-
) -> List[Primitive]:
60-
return []
61-
62-
def visit_compose(
63-
self, diagram: Compose, t: Affine = Ident
64-
) -> List[Primitive]:
65-
elems1 = diagram.diagram1.accept(self, t=t)
66-
elems2 = diagram.diagram2.accept(self, t=t)
67-
return elems1 + elems2
50+
) -> MList[Primitive]:
51+
return MList([diagram.apply_transform(t)])
6852

6953
def visit_apply_transform(
7054
self, diagram: ApplyTransform, t: Affine = Ident
71-
) -> List[Primitive]:
55+
) -> MList[Primitive]:
7256
t_new = t * diagram.transform
73-
return [
74-
prim.apply_transform(t_new)
75-
for prim in diagram.diagram.accept(self, t=t)
76-
]
57+
return MList(
58+
[
59+
prim.apply_transform(t_new)
60+
for prim in diagram.diagram.accept(self, t).data
61+
]
62+
)
7763

7864
def visit_apply_style(
7965
self, diagram: ApplyStyle, t: Affine = Ident
80-
) -> List[Primitive]:
81-
return [
82-
prim.apply_style(diagram.style)
83-
for prim in diagram.diagram.accept(self, t=t)
84-
]
66+
) -> MList[Primitive]:
67+
return MList(
68+
[
69+
prim.apply_style(diagram.style)
70+
for prim in diagram.diagram.accept(self, t).data
71+
]
72+
)
8573

8674
def visit_apply_name(
8775
self, diagram: ApplyName, t: Affine = Ident
88-
) -> List[Primitive]:
89-
return [prim for prim in diagram.diagram.accept(self, t=t)]
76+
) -> MList[Primitive]:
77+
return MList([prim for prim in diagram.diagram.accept(self, t).data])
9078

9179

9280
class ToCairoShape(ShapeVisitor[None]):
81+
9382
def render_segment(
9483
self, seg: SegmentLike, ctx: PyCairoContext, p: P2
9584
) -> None:
@@ -183,7 +172,7 @@ def render_cairo_prims(
183172
) -> None:
184173
base = base._style(style)
185174
shape_renderer = ToCairoShape()
186-
for prim in base.accept(ToList()):
175+
for prim in base.accept(ToList(), Ident):
187176
# apply transformation
188177
matrix = tx_to_cairo(prim.transform)
189178
ctx.transform(matrix)

chalk/backend/svg.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ def get_xml(self) -> ET.Element:
6262
return self.xml
6363

6464

65-
class ToSVG(DiagramVisitor[BaseElement]):
65+
class ToSVG(DiagramVisitor[BaseElement, Style]):
66+
A_type = BaseElement
67+
6668
def __init__(self, dwg: Drawing):
6769
self.dwg = dwg
6870
self.shape_renderer = ToSVGShape(dwg)
@@ -92,27 +94,28 @@ def visit_compose(
9294
self, diagram: Compose, style: Style = EMPTY_STYLE
9395
) -> BaseElement:
9496
g = self.dwg.g()
95-
g.add(diagram.diagram1.accept(self, style=style))
96-
g.add(diagram.diagram2.accept(self, style=style))
97+
98+
for d in diagram.diagrams:
99+
g.add(d.accept(self, style))
97100
return g
98101

99102
def visit_apply_transform(
100103
self, diagram: ApplyTransform, style: Style = EMPTY_STYLE
101104
) -> BaseElement:
102105
g = self.dwg.g(transform=tx_to_svg(diagram.transform))
103-
g.add(diagram.diagram.accept(self, style=style))
106+
g.add(diagram.diagram.accept(self, style))
104107
return g
105108

106109
def visit_apply_style(
107110
self, diagram: ApplyStyle, style: Style = EMPTY_STYLE
108111
) -> BaseElement:
109-
return diagram.diagram.accept(self, style=diagram.style.merge(style))
112+
return diagram.diagram.accept(self, diagram.style.merge(style))
110113

111114
def visit_apply_name(
112115
self, diagram: ApplyName, style: Style = EMPTY_STYLE
113116
) -> BaseElement:
114117
g = self.dwg.g()
115-
g.add(diagram.diagram.accept(self, style=style))
118+
g.add(diagram.diagram.accept(self, style))
116119
return g
117120

118121

@@ -195,7 +198,7 @@ def visit_image(
195198

196199

197200
def to_svg(self: Diagram, dwg: Drawing, style: Style) -> BaseElement:
198-
return self.accept(ToSVG(dwg), style=style)
201+
return self.accept(ToSVG(dwg), style)
199202

200203

201204
def render(

chalk/backend/tikz.py

+14-35
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import TYPE_CHECKING, Any, List
44

55
from chalk import transform as tx
6+
from chalk.monoid import MList
67
from chalk.shapes import (
78
ArcSegment,
89
ArrowHead,
@@ -20,14 +21,7 @@
2021
from chalk.visitor import DiagramVisitor, ShapeVisitor
2122

2223
if TYPE_CHECKING:
23-
from chalk.core import (
24-
ApplyName,
25-
ApplyStyle,
26-
ApplyTransform,
27-
Compose,
28-
Empty,
29-
Primitive,
30-
)
24+
from chalk.core import ApplyStyle, ApplyTransform, Primitive
3125

3226

3327
PyLatex = Any
@@ -45,58 +39,43 @@ def convert(
4539
return convert(*affine[:6])
4640

4741

48-
class ToTikZ(DiagramVisitor[List[PyLatexElement]]):
42+
class ToTikZ(DiagramVisitor[MList[PyLatexElement], Style]):
43+
A_type = MList[PyLatexElement]
44+
4945
def __init__(self, pylatex: PyLatex):
5046
self.pylatex = pylatex
5147
self.shape_renderer = ToTikZShape(pylatex)
5248

5349
def visit_primitive(
5450
self, diagram: Primitive, style: Style = EMPTY_STYLE
55-
) -> List[PyLatexElement]:
51+
) -> MList[PyLatexElement]:
5652
transform = tx_to_tikz(diagram.transform)
5753
style_new = diagram.style.merge(style)
5854
inner = diagram.shape.accept(self.shape_renderer, style=style_new)
5955
if not style_new and not transform:
60-
return [inner]
56+
return MList([inner])
6157
else:
6258
options = {"cm": tx_to_tikz(diagram.transform)}
6359
s = self.pylatex.TikZScope(
6460
options=self.pylatex.TikZOptions(**options)
6561
)
6662
s.append(inner)
67-
return [s]
68-
69-
def visit_empty(
70-
self, diagram: Empty, style: Style = EMPTY_STYLE
71-
) -> List[PyLatexElement]:
72-
return []
73-
74-
def visit_compose(
75-
self, diagram: Compose, style: Style = EMPTY_STYLE
76-
) -> List[PyLatexElement]:
77-
elems1 = diagram.diagram1.accept(self, style=style)
78-
elems2 = diagram.diagram2.accept(self, style=style)
79-
return elems1 + elems2
63+
return MList([s])
8064

8165
def visit_apply_transform(
8266
self, diagram: ApplyTransform, style: Style = EMPTY_STYLE
83-
) -> List[PyLatexElement]:
67+
) -> MList[PyLatexElement]:
8468
options = {"cm": tx_to_tikz(diagram.transform)}
8569
s = self.pylatex.TikZScope(options=self.pylatex.TikZOptions(**options))
86-
for x in diagram.diagram.accept(self, style=style):
70+
for x in diagram.diagram.accept(self, style).data:
8771
s.append(x)
88-
return [s]
72+
return MList([s])
8973

9074
def visit_apply_style(
9175
self, diagram: ApplyStyle, style: Style = EMPTY_STYLE
92-
) -> List[PyLatexElement]:
76+
) -> MList[PyLatexElement]:
9377
style_new = diagram.style.merge(style)
94-
return diagram.diagram.accept(self, style=style_new)
95-
96-
def visit_apply_name(
97-
self, diagram: ApplyName, style: Style = EMPTY_STYLE
98-
) -> List[PyLatexElement]:
99-
return diagram.diagram.accept(self, style=style)
78+
return diagram.diagram.accept(self, style_new)
10079

10180

10281
class ToTikZShape(ShapeVisitor[PyLatexElement]):
@@ -206,7 +185,7 @@ def visit_image(
206185
def to_tikz(
207186
self: Diagram, pylatex: PyLatex, style: Style
208187
) -> List[PyLatexElement]:
209-
return self.accept(ToTikZ(pylatex), style=style)
188+
return self.accept(ToTikZ(pylatex), style).data
210189

211190

212191
def render(self: Diagram, path: str, height: int = 128) -> None:

chalk/combinators.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
from typing import Iterable, List, Optional, Tuple
22

33
from chalk.envelope import Envelope
4+
from chalk.monoid import associative_reduce
45
from chalk.shapes import Path, Spacer
5-
from chalk.transform import (
6-
V2,
7-
Affine,
8-
associative_reduce,
9-
origin,
10-
unit_x,
11-
unit_y,
12-
)
6+
from chalk.transform import V2, Affine, origin, unit_x, unit_y
137
from chalk.types import Diagram
148

159
# Functions mirroring Diagrams.Combinators and Diagrams.2d.Combinators
@@ -111,15 +105,14 @@ def place_on_path(diagrams: Iterable[Diagram], path: Path) -> Diagram:
111105
def cat(
112106
diagrams: Iterable[Diagram], v: V2, sep: Optional[float] = None
113107
) -> Diagram:
114-
from chalk.core import empty
115108

116109
diagrams = iter(diagrams)
117110
start = next(diagrams, None)
118111
sep_dia = hstrut(sep).rotate(v.angle)
119112
if start is None:
120113
return empty()
121114

122-
def fn(a, b):
115+
def fn(a: Diagram, b: Diagram) -> Diagram:
123116
return a.beside(sep_dia, v).beside(b, v)
124117

125118
return fn(start, associative_reduce(fn, diagrams, empty()))
@@ -136,9 +129,16 @@ def concat(diagrams: Iterable[Diagram]) -> Diagram:
136129
Diagram: New diagram
137130
138131
"""
139-
from chalk.core import empty
132+
from chalk.core import BaseDiagram
140133

141-
return associative_reduce(atop, diagrams, empty())
134+
return BaseDiagram.concat(diagrams) # type: ignore
135+
136+
137+
def empty() -> Diagram:
138+
"Create an empty diagram"
139+
from chalk.core import BaseDiagram
140+
141+
return BaseDiagram.empty()
142142

143143

144144
# CompaseAligned.
@@ -147,15 +147,15 @@ def concat(diagrams: Iterable[Diagram]) -> Diagram:
147147

148148

149149
def hstrut(width: Optional[float]) -> Diagram:
150-
from chalk.core import Primitive, empty
150+
from chalk.core import Primitive
151151

152152
if width is None:
153153
return empty()
154154
return Primitive.from_shape(Spacer(width, 0))
155155

156156

157157
def vstrut(height: Optional[float]) -> Diagram:
158-
from chalk.core import Primitive, empty
158+
from chalk.core import Primitive
159159

160160
if height is None:
161161
return empty()

0 commit comments

Comments
 (0)