@explorable-viz/fluid 0.11.1 → 0.11.3
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.
- package/.spago/aff/v7.1.0/.editorconfig +13 -0
- package/.spago/aff/v7.1.0/.eslintrc.json +28 -0
- package/.spago/aff/v7.1.0/.gitignore +14 -0
- package/.spago/aff/v7.1.0/.tidyrc.json +10 -0
- package/.spago/argonaut-codecs/v9.1.0/.editorconfig +13 -0
- package/.spago/argonaut-codecs/v9.1.0/.gitignore +9 -0
- package/.spago/argonaut-codecs/v9.1.0/.tidyrc.json +10 -0
- package/.spago/arrays/v7.2.1/.eslintrc.json +26 -0
- package/.spago/arrays/v7.2.1/.gitignore +9 -0
- package/.spago/console/v6.1.0/.eslintrc.json +30 -0
- package/.spago/console/v6.1.0/.gitignore +9 -0
- package/.spago/debug/v6.0.2/.eslintrc.json +36 -0
- package/.spago/debug/v6.0.2/.gitignore +8 -0
- package/.spago/enums/v6.0.1/.gitignore +7 -0
- package/.spago/foreign-object/v4.1.0/.eslintrc.json +26 -0
- package/.spago/foreign-object/v4.1.0/.gitignore +8 -0
- package/.spago/free/v7.1.0/.gitignore +8 -0
- package/.spago/graphs/v8.1.0/.gitignore +7 -0
- package/.spago/js-uri/v3.1.0/.eslintrc.json +30 -0
- package/.spago/js-uri/v3.1.0/.gitignore +14 -0
- package/.spago/js-uri/v3.1.0/.tidyrc.json +10 -0
- package/.spago/node-buffer/v9.0.0/.eslintrc.json +26 -0
- package/.spago/node-buffer/v9.0.0/.gitignore +8 -0
- package/.spago/node-process/v11.2.0/.eslintrc.json +29 -0
- package/.spago/node-process/v11.2.0/.gitignore +8 -0
- package/.spago/node-streams/v9.0.0/.eslintrc.json +29 -0
- package/.spago/node-streams/v9.0.0/.gitignore +8 -0
- package/.spago/optparse/v6.0.0/.gitignore +8 -0
- package/.spago/optparse/v6.0.0/.npmrc +1 -0
- package/.spago/ordered-collections/v3.1.1/.gitignore +8 -0
- package/.spago/parallel/v7.0.0/.gitignore +7 -0
- package/.spago/parsing/v10.3.1/.editorconfig +13 -0
- package/.spago/parsing/v10.3.1/.gitignore +12 -0
- package/.spago/parsing/v10.3.1/.tidyoperators +231 -0
- package/.spago/parsing/v10.3.1/.tidyrc.json +10 -0
- package/.spago/prelude/v6.0.1/.eslintrc.json +26 -0
- package/.spago/prelude/v6.0.1/.gitignore +8 -0
- package/.spago/st/v6.2.0/.eslintrc.json +26 -0
- package/.spago/st/v6.2.0/.gitignore +8 -0
- package/.spago/strings/v6.0.1/.eslintrc.json +26 -0
- package/.spago/strings/v6.0.1/.gitignore +8 -0
- package/.spago/tailrec/v6.1.0/.gitignore +7 -0
- package/.spago/web-html/v4.1.0/.eslintrc.json +29 -0
- package/.spago/web-html/v4.1.0/.gitignore +8 -0
- package/.spago/web-xhr/v5.0.1/.eslintrc.json +29 -0
- package/.spago/web-xhr/v5.0.1/.gitignore +8 -0
- package/dist/fluid/fluid/lib/graphics.fld +130 -102
- package/dist/fluid/fluid/lib/matrix.fld +1 -1
- package/dist/fluid/fluid/lib/prelude.fld +50 -12
- package/dist/fluid/fluid/lib/stats.fld +6 -6
- package/dist/fluid/shared/fluid.mjs +21454 -26011
- package/dist/fluid/shared/load-figure.js +30116 -29574
- package/dist/fluid/shared/webtest-lib.js +3385 -3389
- package/package.json +1 -1
- package/website/article/.DS_Store +0 -0
- package/website/article/convolution/index.html +1 -1
- package/website/article/css/styles.css +4 -0
- package/website/article/css/view-styles.css +9 -2
- package/website/article/dataset/.DS_Store +0 -0
- package/website/article/energy-scatter/index.html +1 -1
- package/website/article/fluid/1805.02474v1-10.fld +21 -21
- package/website/article/fluid/bar-chart-line-chart.fld +7 -5
- package/website/article/fluid/convolution.fld +1 -1
- package/website/article/fluid/moving-average.fld +4 -4
- package/website/article/fluid/non-renewables.fld +7 -5
- package/website/article/index.html +19 -7
- package/website/article/methane/index.html +1 -1
- package/website/article/moving-average/index.html +1 -1
- package/website/article/non-renewables/index.html +1 -1
- package/website/article/renewables-linked/index.html +1 -1
- package/website/article/scigen-1805.02474v1-10/index.html +1 -1
- package/website/article/test.mjs +5 -5
- package/dist/fluid/fluid/lib/pi.fld +0 -1
- package/website/article/dataset/annual-temp-anomaly.json +0 -413
- package/website/article/dataset/ccra3-risks.json +0 -2015
|
@@ -1,18 +1,26 @@
|
|
|
1
|
+
# type Colour = Str
|
|
2
|
+
# type Colours = List Colour
|
|
3
|
+
# type Cat = Str
|
|
4
|
+
|
|
5
|
+
# Group has location (0, 0) because it doesn't interfere with positioning of its children.
|
|
6
|
+
# GraphicsElement -> Point
|
|
1
7
|
def coords(Group(gs)): Point(0, 0)
|
|
2
8
|
def coords(Rect(x, y, _, _, _)): Point(x, y)
|
|
3
9
|
def coords(String(x, y, _, _, _)): Point(x, y)
|
|
4
|
-
def coords(Viewport(x, y, _, _, _, _, _, _, _)): Point(x, y)
|
|
10
|
+
def coords(Viewport(x, y, _, _, _, _, _, _, _)): Point(x, y)
|
|
5
11
|
|
|
12
|
+
# GraphicsElement -> Float
|
|
6
13
|
def get_x(g):
|
|
7
|
-
def Point(x, _): coords(g)
|
|
8
|
-
|
|
9
|
-
x;
|
|
14
|
+
def Point(x, _): coords(g)
|
|
15
|
+
x
|
|
10
16
|
|
|
17
|
+
# GraphicsElement -> Float
|
|
11
18
|
def get_y(g):
|
|
12
|
-
def Point(_, y): coords(g)
|
|
13
|
-
|
|
14
|
-
x;
|
|
19
|
+
def Point(_, y): coords(g)
|
|
20
|
+
y
|
|
15
21
|
|
|
22
|
+
# Want some kind of typeclass mechanism plus record accessors/updaters.
|
|
23
|
+
# Float -> GraphicsElement -> GraphicsElement
|
|
16
24
|
def set_x(x, Group(gs)):
|
|
17
25
|
error("Group has immutable coordinates")
|
|
18
26
|
def set_x(x, Rect(_, y, w, h, fill)):
|
|
@@ -20,11 +28,16 @@ def set_x(x, Rect(_, y, w, h, fill)):
|
|
|
20
28
|
def set_x(x, String(_, y, str, anchor, baseline)):
|
|
21
29
|
String(x, y, str, anchor, baseline)
|
|
22
30
|
def set_x(x, Viewport(_, y, w, h, fill, margin, scale, translate, g)):
|
|
23
|
-
Viewport(x, y, w, h, fill, margin, scale, translate, g)
|
|
31
|
+
Viewport(x, y, w, h, fill, margin, scale, translate, g)
|
|
24
32
|
|
|
33
|
+
# (Point, Point) -> Point
|
|
25
34
|
def dimensions2((Point(x1, y1), Point(x2, y2))):
|
|
26
|
-
Point(max(x1, x2), max(y1, y2))
|
|
35
|
+
Point(max(x1, x2), max(y1, y2))
|
|
27
36
|
|
|
37
|
+
# For Group, dimensions are relative to implicit coords of (0, 0), since a Group's children are effectively
|
|
38
|
+
# positioned relative to parent of Group. For Polymarker, will probably have to ignore the markers themselves,
|
|
39
|
+
# since they are scale-invariant.
|
|
40
|
+
# GraphicsElement -> Point
|
|
28
41
|
def dimensions(Group(gs)):
|
|
29
42
|
foldl(curry(dimensions2), Point(0, 0), map(coords_op, gs))
|
|
30
43
|
def dimensions(Polyline(ps, _, _)):
|
|
@@ -32,25 +45,28 @@ def dimensions(Polyline(ps, _, _)):
|
|
|
32
45
|
def dimensions(Rect(_, _, w, h, _)): Point(w, h)
|
|
33
46
|
def dimensions(String(_, _, _, _, _)): Point(0, 0)
|
|
34
47
|
def dimensions(Viewport(_, _, w, h, _, _, _, _, _)): Point(w, h)
|
|
48
|
+
|
|
35
49
|
def coords_op(g):
|
|
36
50
|
def (Point(x, y), Point(w, h)):
|
|
37
|
-
prod(coords, dimensions, g)
|
|
38
|
-
|
|
39
|
-
Point(x + w, y + h);
|
|
51
|
+
prod(coords, dimensions, g)
|
|
52
|
+
Point(x + w, y + h)
|
|
40
53
|
|
|
54
|
+
# GraphicsElement -> Float
|
|
41
55
|
def width(g):
|
|
42
|
-
def Point(w, _): dimensions(g)
|
|
43
|
-
|
|
44
|
-
w;
|
|
56
|
+
def Point(w, _): dimensions(g)
|
|
57
|
+
w
|
|
45
58
|
|
|
59
|
+
# GraphicsElement -> Float
|
|
46
60
|
def height(g):
|
|
47
|
-
def Point(_, h): dimensions(g)
|
|
48
|
-
|
|
49
|
-
h;
|
|
61
|
+
def Point(_, h): dimensions(g)
|
|
62
|
+
h
|
|
50
63
|
|
|
64
|
+
# Float -> Float -> List GraphicsElement -> List GraphicsElement
|
|
51
65
|
def spaceRight(z, sep, gs):
|
|
52
|
-
zipWith(set_x, iterate(length(gs), (+)(sep), z), gs)
|
|
66
|
+
zipWith(set_x, iterate(length(gs), (+)(sep), z), gs)
|
|
53
67
|
|
|
68
|
+
# Bake colour decisions into the library for the time being. Provide two palettes, so we can have two
|
|
69
|
+
# different sets of categorical values (e.g. countries and energy types). Palettes from colorbrewer2.org
|
|
54
70
|
def colours1: [
|
|
55
71
|
"#66c2a5",
|
|
56
72
|
"#a6d854",
|
|
@@ -60,7 +76,7 @@ def colours1: [
|
|
|
60
76
|
"#b3b3b3",
|
|
61
77
|
"#8da0cb",
|
|
62
78
|
"#e78ac3"
|
|
63
|
-
]
|
|
79
|
+
]
|
|
64
80
|
|
|
65
81
|
def colours2: [
|
|
66
82
|
"#e41a1c",
|
|
@@ -71,176 +87,188 @@ def colours2: [
|
|
|
71
87
|
"#ffff33",
|
|
72
88
|
"#a65628",
|
|
73
89
|
"#f781bf"
|
|
74
|
-
]
|
|
90
|
+
]
|
|
75
91
|
|
|
92
|
+
# Compositionality principle: child coords/dimensions are always expressed directly using parent reference
|
|
93
|
+
# frame, to avoid depending on content of child, and so are not themselves scaled. Polyline can't be scaled
|
|
94
|
+
# directly because it inherits its frame of reference from its parent. For Viewport, margin will shrink the
|
|
95
|
+
# available area, possibly to zero, at which point nothing will be rendered.
|
|
96
|
+
# Float -> GraphicsElement -> GraphicsElement
|
|
76
97
|
def scaleToWidth(w, Rect(x, y, _, h, fill)):
|
|
77
98
|
Rect(x, y, w, h, fill)
|
|
78
99
|
def scaleToWidth(w, Viewport(x, y, w0, h, fill, margin, Scale(x_scale, y_scale), translate, g)):
|
|
79
|
-
def scale:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Viewport(x, y, w, h, fill, margin, scale, translate, g);
|
|
100
|
+
def scale: Scale((x_scale * w) / w0, y_scale)
|
|
101
|
+
Viewport(x, y, w, h, fill, margin, scale, translate, g)
|
|
83
102
|
|
|
103
|
+
# Float -> List GraphicsElement -> List GraphicsElement
|
|
84
104
|
def stackRight(sep, gs):
|
|
85
|
-
map(scaleToWidth(1 - sep), spaceRight(sep / 2, 1, gs))
|
|
105
|
+
map(scaleToWidth(1 - sep), spaceRight(sep / 2, 1, gs))
|
|
86
106
|
|
|
107
|
+
# Float -> List GraphicsElement -> GraphicsElement
|
|
87
108
|
def groupRight(sep, gs):
|
|
88
|
-
Viewport(0, 0, length(gs), maximum(map(height, gs)), "none", 0, Scale(1, 1), Translate(0, 0), Group(stackRight(sep, gs)))
|
|
109
|
+
Viewport(0, 0, length(gs), maximum(map(height, gs)), "none", 0, Scale(1, 1), Translate(0, 0), Group(stackRight(sep, gs)))
|
|
89
110
|
|
|
111
|
+
# Heuristic saying how often to place a tick on an axis of length n.
|
|
112
|
+
# Float -> Float
|
|
90
113
|
def tickEvery(n):
|
|
91
|
-
def m:
|
|
92
|
-
floor(logBase(10, n));
|
|
114
|
+
def m: floor(logBase(10, n))
|
|
93
115
|
|
|
94
116
|
if n <= 2 * 10 ** m: 2 * 10 ** (m - 1)
|
|
95
|
-
else: 10 ** m
|
|
117
|
+
else: 10 ** m
|
|
96
118
|
|
|
97
119
|
def axisStrokeWidth: 0.5
|
|
98
120
|
def axisColour: "black"
|
|
99
121
|
def backgroundColour: "white"
|
|
100
122
|
def defaultMargin: 24
|
|
101
123
|
def markerRadius: 3.5
|
|
102
|
-
def tickLength: 4
|
|
124
|
+
def tickLength: 4
|
|
103
125
|
|
|
126
|
+
# Helpers for axis functions.
|
|
127
|
+
# Orient -> Colour -> Float -> GraphicsElement
|
|
104
128
|
def tick(Horiz, colour, len):
|
|
105
129
|
Line(Point(0, 0), Point(0, 0 - len), colour, axisStrokeWidth)
|
|
106
130
|
def tick(Vert, colour, len):
|
|
107
|
-
Line(Point(0, 0), Point(0 - len, 0), colour, axisStrokeWidth)
|
|
131
|
+
Line(Point(0, 0), Point(0 - len, 0), colour, axisStrokeWidth)
|
|
108
132
|
|
|
133
|
+
# Orient -> Float -> Float -> Str -> GraphicsElement
|
|
109
134
|
def label(Horiz, x, distance, str):
|
|
110
135
|
String(x, (0 - distance) - 4, str, "middle", "hanging")
|
|
111
136
|
def label(Vert, x, distance, str):
|
|
112
|
-
String(0 - distance, x, str, "end", "central")
|
|
137
|
+
String(0 - distance, x, str, "end", "central")
|
|
113
138
|
|
|
139
|
+
# Orient -> Colour -> Float -> Str -> GraphicsElement
|
|
114
140
|
def labelledTick(orient, colour, len, str):
|
|
115
141
|
Group([
|
|
116
142
|
tick(orient, colour, len),
|
|
117
143
|
label(orient, 0, len, str)
|
|
118
|
-
])
|
|
144
|
+
])
|
|
119
145
|
|
|
146
|
+
# Orient -> Float -> Float -> Point
|
|
120
147
|
def mkPoint(Horiz, x, y): Point(y, x)
|
|
121
|
-
def mkPoint(Vert, x, y): Point(x, y)
|
|
148
|
+
def mkPoint(Vert, x, y): Point(x, y)
|
|
122
149
|
|
|
150
|
+
# x is position of this axis on the other axis. Returns axis and position of last tick.
|
|
151
|
+
# Orient -> Float -> Float -> Float -> GraphicsElement
|
|
123
152
|
def axis(orient, x, start, end):
|
|
124
|
-
def tickSp:
|
|
125
|
-
|
|
126
|
-
def
|
|
127
|
-
|
|
128
|
-
def
|
|
129
|
-
ceilingToNearest(end, tickSp)
|
|
130
|
-
def n:
|
|
131
|
-
floor((end - firstTick) / tickSp) + 1
|
|
132
|
-
def ys:
|
|
133
|
-
iterate(n, (+)(tickSp), firstTick)
|
|
153
|
+
def tickSp: tickEvery(end - start)
|
|
154
|
+
def firstTick: ceilingToNearest(start, tickSp)
|
|
155
|
+
def lastTick: ceilingToNearest(end, tickSp)
|
|
156
|
+
def n: floor((end - firstTick) / tickSp) + 1
|
|
157
|
+
def ys: iterate(n, (+)(tickSp), firstTick)
|
|
134
158
|
def ys:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
case False: ys
|
|
159
|
+
if firstTick > start: start :| ys
|
|
160
|
+
else: ys
|
|
138
161
|
def ys:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
case False: ys
|
|
143
|
-
def ps:
|
|
144
|
-
map(mkPoint(orient, x), ys)
|
|
162
|
+
if lastTick > end: concat2(ys, [lastTick])
|
|
163
|
+
else: ys
|
|
164
|
+
def ps: map(mkPoint(orient, x), ys)
|
|
145
165
|
def ax:
|
|
146
166
|
Group([
|
|
147
167
|
Line(head(ps), last(ps), axisColour, axisStrokeWidth),
|
|
148
168
|
Polymarkers(ps, flip(map, ys, compose(labelledTick(orient, axisColour, tickLength), numToStr)))
|
|
149
|
-
])
|
|
169
|
+
])
|
|
150
170
|
|
|
151
|
-
(ax, lastTick)
|
|
171
|
+
(ax, lastTick)
|
|
152
172
|
|
|
173
|
+
# x is position of this axis on the other axis.
|
|
174
|
+
# Orient -> Float -> List Cat -> GraphicsElement
|
|
153
175
|
def catAxis(orient, x, catValues):
|
|
154
|
-
def ys:
|
|
155
|
-
|
|
156
|
-
def ps:
|
|
157
|
-
map(mkPoint(orient, x), ys);
|
|
176
|
+
def ys: iterate(length(catValues) + 1, (+)(1), 0)
|
|
177
|
+
def ps: map(mkPoint(orient, x), ys)
|
|
158
178
|
|
|
159
179
|
Group([
|
|
160
180
|
Line(head(ps), last(ps), axisColour, axisStrokeWidth),
|
|
161
181
|
Polymarkers(tail(ps), map(const(tick(orient, axisColour, tickLength)), catValues)),
|
|
162
|
-
Polymarkers(flip(map, tail(ps),
|
|
163
|
-
])
|
|
182
|
+
Polymarkers(flip(map, tail(ps), lambda Point(x, y): Point(x - 0.5, y)), map(label(orient, -0.5, 0), catValues))
|
|
183
|
+
])
|
|
164
184
|
|
|
185
|
+
# Float -> Float -> Float -> Float -> List GraphicsElement -> GraphicsElement
|
|
165
186
|
def viewport(x_start, x_finish, y_finish, margin, gs):
|
|
166
|
-
Viewport(0, 0, x_finish - x_start, y_finish, backgroundColour, margin, Scale(1, 1), Translate(0 - x_start, 0), Group(gs))
|
|
187
|
+
Viewport(0, 0, x_finish - x_start, y_finish, backgroundColour, margin, Scale(1, 1), Translate(0 - x_start, 0), Group(gs))
|
|
167
188
|
|
|
189
|
+
# Plot a map of x values to lists of (categorical value, y value) pairs. Importantly, assume all data is uniform
|
|
190
|
+
# (categorical keys are the same for each x value and are ordered the same each time).
|
|
191
|
+
# Bool -> Colours -> Float -> List (Float, List (Cat, Float)) -> GraphicsElement
|
|
168
192
|
def lineChart(withAxes, colours, x_start, data):
|
|
169
193
|
def xs: map(fst, data)
|
|
170
|
-
def nCat:
|
|
171
|
-
length(snd(head(data)));
|
|
194
|
+
def nCat: length(snd(head(data)))
|
|
172
195
|
|
|
196
|
+
# (Int, Colour) -> GraphicsElement
|
|
173
197
|
def plot((n, colour)):
|
|
174
198
|
def ps:
|
|
175
|
-
map(
|
|
199
|
+
map(lambda (x, kvs): Point(x, snd(nth(n, kvs))), data)
|
|
176
200
|
|
|
177
201
|
Group([
|
|
178
202
|
Polyline(ps, colour, 1),
|
|
179
203
|
Polymarkers(ps, repeat(length(ps), Circle(0, 0, markerRadius, colour)))
|
|
180
|
-
])
|
|
204
|
+
])
|
|
181
205
|
|
|
206
|
+
# List GraphicsElement
|
|
182
207
|
def lines:
|
|
183
208
|
zipWith(curry(plot), iterate(nCat, (+)(1), 0), colours)
|
|
184
209
|
def x_finish: last(xs)
|
|
185
210
|
def y_finish:
|
|
186
|
-
maximum(flip(map, data,
|
|
187
|
-
|
|
188
|
-
match withAxes:
|
|
189
|
-
case True:
|
|
190
|
-
def (x_axis, x_finish):
|
|
191
|
-
axis(Horiz, 0, x_start, x_finish)
|
|
192
|
-
def (y_axis, y_finish'):
|
|
193
|
-
axis(Vert, x_start, 0, y_finish);
|
|
211
|
+
maximum(flip(map, data, lambda (_, kvs): maximum(map(snd, kvs))))
|
|
194
212
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
213
|
+
if withAxes:
|
|
214
|
+
def (x_axis, x_finish): axis(Horiz, 0, x_start, x_finish)
|
|
215
|
+
def (y_axis, y_finish_): axis(Vert, x_start, 0, y_finish)
|
|
216
|
+
viewport(x_start, x_finish, y_finish_, defaultMargin, x_axis :| y_axis :| lines)
|
|
217
|
+
else:
|
|
218
|
+
viewport(x_start, x_finish, y_finish, 0, lines)
|
|
198
219
|
|
|
220
|
+
# Plot a chart of categorical values on the x-axis and renderings of the corresponding a-value on the y-axis.
|
|
221
|
+
# (Colours -> List a -> GraphicsElement) -> Bool -> Colours -> Float -> List (Cat, a) -> GraphicsElement
|
|
199
222
|
def categoricalChart(plotValue, withAxes, colours, sep, data):
|
|
200
223
|
def gs:
|
|
201
224
|
stackRight(sep, plotValue(colours, map(snd, data)))
|
|
202
225
|
def w: length(gs)
|
|
203
|
-
def h:
|
|
204
|
-
maximum(map(height, gs));
|
|
205
|
-
|
|
206
|
-
match withAxes:
|
|
207
|
-
case True:
|
|
208
|
-
def x_axis:
|
|
209
|
-
catAxis(Horiz, 0, map(fst, data))
|
|
210
|
-
def (y_axis, h'): axis(Vert, 0, 0, h);
|
|
226
|
+
def h: maximum(map(height, gs))
|
|
211
227
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
228
|
+
if withAxes:
|
|
229
|
+
def x_axis: catAxis(Horiz, 0, map(fst, data))
|
|
230
|
+
def (y_axis, h_): axis(Vert, 0, 0, h)
|
|
231
|
+
viewport(0, w, h_, defaultMargin, concat2(gs, [x_axis, y_axis]))
|
|
232
|
+
else:
|
|
233
|
+
viewport(0, w, h, 0, gs)
|
|
215
234
|
|
|
235
|
+
# Colours -> List a -> GraphicsElement
|
|
216
236
|
def rects(colours, ns):
|
|
217
|
-
zipWith(
|
|
237
|
+
zipWith(lambda colour, n: Rect(0, 0, 1, n, colour), colours, ns)
|
|
218
238
|
|
|
239
|
+
# First component of data (categorical value) currently ignored; values just mapped positionally to colors.
|
|
240
|
+
# Can we use Group instead of Viewport here?
|
|
241
|
+
# Colours -> List (a, Num) -> GraphicsElement
|
|
219
242
|
def stackedBar(colours, ns):
|
|
220
243
|
def heights: map(snd, ns)
|
|
221
|
-
def subtotals:
|
|
222
|
-
|
|
223
|
-
def dims:
|
|
224
|
-
zip(0 :| subtotals, heights)
|
|
244
|
+
def subtotals: scanl1((+), 0, heights)
|
|
245
|
+
def dims: zip(0 :| subtotals, heights)
|
|
225
246
|
def rects:
|
|
226
|
-
map(
|
|
247
|
+
map(lambda ((y, height), colour): Rect(0, y, 1, height, colour), zip(dims, colours))
|
|
227
248
|
|
|
228
|
-
Viewport(0, 0, 1, last(subtotals), "none", 0, Scale(1, 1), Translate(0, 0), Group(rects))
|
|
249
|
+
Viewport(0, 0, 1, last(subtotals), "none", 0, Scale(1, 1), Translate(0, 0), Group(rects))
|
|
229
250
|
|
|
251
|
+
# Bool -> Colours -> Float -> List (a, Float) -> GraphicsElement
|
|
230
252
|
def barChart:
|
|
231
|
-
categoricalChart(rects)
|
|
253
|
+
categoricalChart(rects)
|
|
232
254
|
|
|
255
|
+
# For each categorical value of type a, plot a bar chart for the corresponding b-indexed data.
|
|
256
|
+
# Bool -> Colours -> Float -> List (a, List (b, Float)) -> GraphicsElement
|
|
233
257
|
def groupedBarChart:
|
|
234
|
-
categoricalChart(compose(map, flip(barChart(False), 0)))
|
|
258
|
+
categoricalChart(compose(map, flip(barChart(False), 0)))
|
|
235
259
|
|
|
260
|
+
# See stackedBar for strong (unjustified) assumption about uniformity of data.
|
|
261
|
+
# Bool -> Colours -> Num -> List (a, List (b, Num)) -> GraphicsElement
|
|
236
262
|
def stackedBarChart:
|
|
237
|
-
categoricalChart(compose(map, stackedBar))
|
|
263
|
+
categoricalChart(compose(map, stackedBar))
|
|
238
264
|
|
|
265
|
+
# Bit of a hack, but how text fits into our model is a bit unclear at the moment.
|
|
266
|
+
# Str -> GraphicsElement -> GraphicsElement
|
|
239
267
|
def caption(str, Viewport(x, y, w, h, fill, margin, scale, translate, g)):
|
|
240
|
-
def
|
|
268
|
+
def g_:
|
|
241
269
|
Group([
|
|
242
270
|
String(x + w / 2, -2, str, "middle", "hanging"),
|
|
243
271
|
Viewport(0, 0, w, h, fill, margin, scale, translate, g)
|
|
244
|
-
])
|
|
272
|
+
])
|
|
245
273
|
|
|
246
|
-
Viewport(x, y, w, h, backgroundColour, defaultMargin / 2 + 4, Scale(1, 1), Translate(0, 0),
|
|
274
|
+
Viewport(x, y, w, h, backgroundColour, defaultMargin / 2 + 4, Scale(1, 1), Translate(0, 0), g_)
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# "Num" throughout means (Int + Float).
|
|
2
2
|
|
|
3
|
+
# To resolve in new semantics: expected dependencies don't arise for and/or unless they make a fresh value.
|
|
3
4
|
# Bool -> Bool
|
|
4
5
|
def and(False, y): False
|
|
5
|
-
def and(True,
|
|
6
|
+
def and(True, True): True
|
|
7
|
+
def and(True, False): False
|
|
6
8
|
|
|
7
9
|
# Bool -> Bool
|
|
8
10
|
def or(True, y): True
|
|
9
|
-
def or(False,
|
|
11
|
+
def or(False, True): True
|
|
12
|
+
def or(False, False): False
|
|
10
13
|
|
|
11
14
|
# Bool -> Bool
|
|
12
15
|
def not(True): False
|
|
@@ -19,6 +22,10 @@ def compare(x, y):
|
|
|
19
22
|
if x < y: LT
|
|
20
23
|
else: EQ
|
|
21
24
|
|
|
25
|
+
# (b -> b -> c) -> (a -> b) -> a -> a -> c
|
|
26
|
+
def on(binOp, prop, x, y):
|
|
27
|
+
binOp(prop(x), prop(y))
|
|
28
|
+
|
|
22
29
|
# Num -> Num
|
|
23
30
|
def negate: (-)(0)
|
|
24
31
|
|
|
@@ -83,20 +90,23 @@ def elem(x, y :| xs):
|
|
|
83
90
|
x == y |or| elem(x, xs)
|
|
84
91
|
|
|
85
92
|
# (a -> Bool) -> List a -> Option a
|
|
86
|
-
def find(p, []):
|
|
93
|
+
def find(p, []): None
|
|
87
94
|
def find(p, x :| xs):
|
|
88
95
|
if p(x): Some(x)
|
|
89
96
|
else: find(p, xs)
|
|
90
97
|
|
|
91
98
|
# String -> String -> List Dict -> Option Dict
|
|
92
|
-
def findWithKey(
|
|
93
|
-
find(
|
|
99
|
+
def findWithKey(k, v, rs):
|
|
100
|
+
find(lambda y: y[k] == v, rs)
|
|
94
101
|
|
|
95
102
|
# Option a -> a
|
|
96
|
-
def fromSome(None):
|
|
97
|
-
error("Expected Some!")
|
|
103
|
+
def fromSome(None): error("Expected Some!")
|
|
98
104
|
def fromSome(Some(x)): x
|
|
99
105
|
|
|
106
|
+
# Option a -> a -> a
|
|
107
|
+
def fromOption(None, y): y
|
|
108
|
+
def fromOption(Some(x), _): x
|
|
109
|
+
|
|
100
110
|
# (a -> Bool) -> List a -> List a
|
|
101
111
|
def filter(p, []): []
|
|
102
112
|
def filter(p, x :| xs):
|
|
@@ -113,6 +123,30 @@ def filterMap(p, x :| xs):
|
|
|
113
123
|
case Some(y):
|
|
114
124
|
y :| filterMap(f, xs)
|
|
115
125
|
|
|
126
|
+
# Equivalent to but more efficient than length ∘ filter(p)
|
|
127
|
+
def count_if(p):
|
|
128
|
+
def f(n, x):
|
|
129
|
+
if p(x): n + 1
|
|
130
|
+
else: n
|
|
131
|
+
foldl(f, 0)
|
|
132
|
+
|
|
133
|
+
# Split list into longest initial segment whose elements satisfy a predicate, and the rest.
|
|
134
|
+
# (a -> Bool) -> List a -> { init :: List a, rest :: List a }
|
|
135
|
+
def span(p, Nil): { init: Nil, rest: Nil }
|
|
136
|
+
def span(p, x :| xs_):
|
|
137
|
+
if p(x):
|
|
138
|
+
def { init: ys, rest: zs }: span(p, xs_)
|
|
139
|
+
{ init: x :| ys, rest: zs }
|
|
140
|
+
else:
|
|
141
|
+
{ init: Nil, rest: x :| xs_ }
|
|
142
|
+
|
|
143
|
+
# Each returned list is non-empty.
|
|
144
|
+
# (a -> a -> Bool) -> List a -> List (List a)
|
|
145
|
+
def groupBy(eq, Nil): Nil
|
|
146
|
+
def groupBy(eq, x :| xs):
|
|
147
|
+
def { init: ys, rest: zs }: span(eq(x), xs)
|
|
148
|
+
(x :| ys) :| groupBy(eq, zs)
|
|
149
|
+
|
|
116
150
|
# (a -> b -> a) -> a -> List b -> a
|
|
117
151
|
def foldl(op, z, []): z
|
|
118
152
|
def foldl(op, z, x :| xs):
|
|
@@ -135,9 +169,7 @@ def foldr1(op, x :| y :| xs):
|
|
|
135
169
|
def scanl1(op, z, xs):
|
|
136
170
|
def go(x, continue, acc):
|
|
137
171
|
def next: op(acc, x)
|
|
138
|
-
|
|
139
172
|
next :| continue(next)
|
|
140
|
-
|
|
141
173
|
foldr(go, const([]), xs, z)
|
|
142
174
|
|
|
143
175
|
# (a -> b -> a) -> a -> List b -> List a
|
|
@@ -177,8 +209,13 @@ def iterate(n, f, z):
|
|
|
177
209
|
else:
|
|
178
210
|
z :| map(f, iterate(n - 1, f, z))
|
|
179
211
|
|
|
180
|
-
# List
|
|
181
|
-
def sum:
|
|
212
|
+
# List Num -> Num
|
|
213
|
+
def sum: foldl((+), 0)
|
|
214
|
+
|
|
215
|
+
# List Num -> Num
|
|
216
|
+
def mean(xs):
|
|
217
|
+
def (s, n): foldl(lambda (s, n), x: (s + x, n + 1), (0, 0), xs)
|
|
218
|
+
s / n
|
|
182
219
|
|
|
183
220
|
# List a -> a
|
|
184
221
|
def last([x]): x
|
|
@@ -286,7 +323,8 @@ def abs(x, y):
|
|
|
286
323
|
def nub(xs):
|
|
287
324
|
def nub_([], _): []
|
|
288
325
|
def nub_(x :| xs, ys):
|
|
289
|
-
if x |elem| ys:
|
|
326
|
+
if x |elem| ys:
|
|
327
|
+
nub_(xs, ys)
|
|
290
328
|
else:
|
|
291
329
|
x :| nub_(xs, x :| ys)
|
|
292
330
|
|
|
@@ -19,7 +19,7 @@ def mergesort(xs):
|
|
|
19
19
|
|
|
20
20
|
def findQuantile(q, p, xs):
|
|
21
21
|
def rank:
|
|
22
|
-
(p / q) * (length(xs) - 1)
|
|
22
|
+
(p / q) * (length(xs) - 1)
|
|
23
23
|
|
|
24
24
|
if rank == floor(rank):
|
|
25
25
|
nth(rank, xs)
|
|
@@ -36,7 +36,7 @@ def accumBins(data, Nil): []
|
|
|
36
36
|
def accumBins(data, [l]): []
|
|
37
37
|
def accumBins(data, l :| r :| es):
|
|
38
38
|
def (ge, le):
|
|
39
|
-
splitOn(
|
|
39
|
+
splitOn(lambda x: x <= r, data)
|
|
40
40
|
(le, r - l) :| accumBins(ge, r :| es)
|
|
41
41
|
|
|
42
42
|
def cut(xs, nbins):
|
|
@@ -46,7 +46,7 @@ def cut(xs, nbins):
|
|
|
46
46
|
def edges:
|
|
47
47
|
[low + x * binwidth for x in enumFromTo(0, nbins)]
|
|
48
48
|
|
|
49
|
-
accumBins(xs, edges)
|
|
49
|
+
accumBins(xs, edges)
|
|
50
50
|
|
|
51
51
|
def qcut(xs, qs):
|
|
52
52
|
def (low, high):
|
|
@@ -57,13 +57,13 @@ def qcut(xs, qs):
|
|
|
57
57
|
accumBins(xs, edges)
|
|
58
58
|
|
|
59
59
|
def likelihoodLE(xs, target):
|
|
60
|
-
length(filter(
|
|
60
|
+
length(filter(lambda x: x <= target, xs)) / length(xs)
|
|
61
61
|
|
|
62
62
|
def likelihoodGE(xs, target):
|
|
63
|
-
length(filter(
|
|
63
|
+
length(filter(lambda x: x >= target, xs)) / length(xs)
|
|
64
64
|
|
|
65
65
|
def likelihoodMap(table, prob):
|
|
66
|
-
fromSome(find(
|
|
66
|
+
fromSome(find(lambda x: x.prob <= prob, table)).msg
|
|
67
67
|
|
|
68
68
|
def mkPercent(num):
|
|
69
69
|
numToStr(num * 100) ++ "%"
|