Skip to content

Commit

Permalink
num-dot-chart: Takes just a list of x-values, possibly repeating, uno…
Browse files Browse the repository at this point in the history
…rdered. No frequencies brownplt#469

Also, no distinction for non-binned charts. Every chart responds to resizing
  • Loading branch information
ds26gte committed Nov 13, 2024
1 parent d54291f commit ab4a52d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 95 deletions.
102 changes: 11 additions & 91 deletions src/web/arr/trove/chart.arr
Original file line number Diff line number Diff line change
Expand Up @@ -1919,102 +1919,22 @@ fun bar-chart-from-list(labels :: P.LoS, values :: P.LoN) -> DataSeries block:
data-series.make-axis(max-positive-height, max-negative-height)
end

fun num-dot-chart-no-bin(x-values :: P.LoN, y-values :: P.LoN,
min-x-value :: Number, max-x-value :: Number):
num-dot-chart-args = map2(lam(x-value, y-value): [list: x-value, y-value] end,
x-values, y-values)
.append(range(min-x-value, max-x-value)
.filter(lam(x-value): not(member(x-values, x-value)) end)
.map(lam(x-value): [list: x-value, 0] end))
.sort-by({(x1y1, x2y2): x1y1.get(0) < x2y2.get(0)},
{(x1y1, x2y2): x1y1.get(0) == x2y2.get(0)})
dot-chart-from-list(map(lam(x1y1): num-to-string(x1y1.get(0)) end,
num-dot-chart-args),
map(lam(x1y1): x1y1.get(1) end, num-dot-chart-args))
end

fun num-dot-chart-bin(labels :: P.LoN, values :: P.LoN) block:
actual-num-of-xs = fold(lam(num1, num2): num1 + num2 end, 0, values)
num-dot-chart-args-ra = raw-array-build(lam(_): 0 end, actual-num-of-xs)
var num-dot-chart-i = 0
for each2(x-value from labels, y-value from values):
for each(y-value-i from range(0, y-value)) block:
raw-array-set(num-dot-chart-args-ra, num-dot-chart-i, x-value)
num-dot-chart-i := num-dot-chart-i + 1
end
end
scatter-plot-xs = raw-array-to-list(num-dot-chart-args-ra)
scatter-plot-ys = map(lam(_): 0 end, scatter-plot-xs)
default-scatter-plot-series.{
ps: map4({(x, y, z, img): [raw-array: x, y, z, img]},
scatter-plot-xs, scatter-plot-ys,
scatter-plot-xs.map({(_): ''}), scatter-plot-xs.map({(_): false})),
dot-chart: true
} ^ scatter-plot-series
end

fun old-num-dot-chart-bin(labels :: P.LoN, values :: P.LoN,
min-x-value :: Number, max-x-value :: Number) block:
labels-length = labels.length()
median-index = labels-length / 2
sorted-labels = labels.sort()
sorted-labels-split = sorted-labels.split-at(num-floor(median-index))
sorted-labels-1st-half = sorted-labels.split-at(num-floor(median-index)).prefix
sorted-labels-2nd-half = sorted-labels.split-at(num-ceiling(median-index)).suffix
sorted-labels-iqr = ST.median(sorted-labels-2nd-half) -
ST.median(sorted-labels-1st-half)
# bin width based on Freedman-Diaconis rule
dot-chart-bin-width-1 = ((2 * sorted-labels-iqr) /
num-expt(labels-length, 1/3))
# if bin width > 1, make it an even int
dot-chart-bin-width = if dot-chart-bin-width-1 > 1:
num-round-even(dot-chart-bin-width-1) else: dot-chart-bin-width-1 end
left-most-x-1 = min-x-value - (dot-chart-bin-width / 2)
# if all x's are positive, don't make first interval start negative
left-most-x-2 = if all(num-is-positive, labels) and num-is-negative(left-most-x-1):
min-x-value else: left-most-x-1 end
# if bin width > 0.5, keep x's integral
left-most-x = if dot-chart-bin-width > 0.5: num-floor(left-most-x-2) else:
left-most-x-2 end
num-bins = num-ceiling((max-x-value - left-most-x) / dot-chart-bin-width)
num-dot-chart-args = for map(range-iter from range(0, num-bins)):
[raw-array: "[" +
num-to-string(left-most-x + (range-iter * dot-chart-bin-width)) +
"," + num-to-string(left-most-x + ((range-iter + 1) * dot-chart-bin-width)) + ")",
0]
end
for each2(x-value from labels, y-value from values):
x-index = num-min(num-floor((x-value - left-most-x) / dot-chart-bin-width),
num-bins - 1)
this-ra = num-dot-chart-args.get(x-index)
raw-array-set(this-ra, 1, raw-array-get(this-ra, 1) + y-value)
end
dot-chart-from-list(map(lam(x1y1): raw-array-get(x1y1, 0) end, num-dot-chart-args),
map(lam(x1y1): raw-array-get(x1y1, 1) end, num-dot-chart-args))
end

fun num-dot-chart-from-list(labels :: P.LoN, values :: P.LoN) -> DataSeries block:
fun num-dot-chart-from-list(x-values :: P.LoN) -> DataSeries block:
doc: ```
Consume labels, a list of numbers, and values, a list of numbers
Consume a (possibly repeating, unordered) list of numbers
and construct a dot chart
```
labels.each(check-num)
labels-length = labels.length()
when labels-length == 0:
x-values.each(check-num)
when x-values.length() == 0:
raise("num-dot-chart: can't have empty data")
end
when labels-length <> values.length():
raise("num-dot-chart: labels and values should have the same length")
end
any-x-value = labels.get(0)
min-x-value = fold(num-min, any-x-value, labels)
max-x-value = fold(num-max, any-x-value, labels)
# create a binned chart if x range is large or if some x's are noninteger
if (not(all(num-is-integer, labels)) or ((max-x-value - min-x-value) > 15)):
num-dot-chart-bin(labels, values)
else:
num-dot-chart-no-bin(labels, values, min-x-value, max-x-value)
end
scatter-plot-ys = x-values.map(lam(_): 0 end)
default-scatter-plot-series.{
ps: map4({(x, y, z, img): [raw-array: x, y, z, img]},
x-values, scatter-plot-ys,
x-values.map({(_): ''}), x-values.map({(_): false})),
dot-chart: true
} ^ scatter-plot-series
end

fun dot-chart-from-list(labels :: P.LoS, values :: P.LoN) -> DataSeries block:
Expand Down
21 changes: 17 additions & 4 deletions test-util/pyret-programs/charts/num-dot-chart-test.arr
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,23 @@ fun render-image(series):
render-chart(series)
end

r-x-values = [list: 1, 2, 3, 4, 5, 6, 8, 9, 10, 24, 30]
r-y-values = [list: 5, 3, 6, 4, 3, 3, 3, 2, 1, 1, 1]

r-zoo-series = from-list.num-dot-chart(r-x-values, r-y-values)
# r-x-values = [list: 1, 2, 3, 4, 5, 6, 8, 9, 10, 24, 30]
# r-y-values = [list: 5, 3, 6, 4, 3, 3, 3, 2, 1, 1, 1]

r-x-values = [list: 1,1,1,1,1,
2,2,2,
3,3,3,3,3,3,
4,4,4,4,
5,5,5,
6,6,6,
8,8,8,
9,9,
10,
24,
30]

# r-zoo-series = from-list.num-dot-chart(r-x-values, r-y-values)
r-zoo-series = from-list.num-dot-chart(r-x-values)

r-zoo = render-image(r-zoo-series)

Expand Down

0 comments on commit ab4a52d

Please sign in to comment.